Skip to content

Commit

Permalink
[Feature] Chip 컴포넌트 테스트 작성 (#88)
Browse files Browse the repository at this point in the history
* feat: chip 테스트 코드 작성

* fix: test 코드 몇가지 에러 수정

* fix: export default 수정

* fix: 주석 제거

* fix: 타입에러 해결되는지 확인해보기

* fix: prev 타입 지정

* fix: Chip 컴포넌트에 as 추가

* fix: disabled 버튼 테스트

* fix: tsconfig 바꿔치기

* fix: tsconfig 원래대로 되돌리기

* fix: disabled 없애기

* fix: disabled 테스트 아예 지우기

* fix: jest config 변경

* fix: 절대경로 수정 테스트

* fix: 마지막 시도

* fix: 타입 단언

* fix: tsconfig 부분수정

* fix: 설정 오버로딩

* fix: 테스트 설정 찐 마무리

* fix: Chip UI 깨진거 수정

* fix: 전체 패키지 다시 깔기

* fix: core-js 가 범인인가?

* fix: a11y test 시작이라도

* fix: Chip 접근성 테스트 정리

* fix: test 잘못된곳 수정

* fix : Checkbox 관련 스토리북, aria 속성 수정

* fix : switch 속성 수정, 스토리북 수정

* fix : checked 삭제

* fix : Switch 원복

* fix: 체크박스 aria-checked 속성 checked로 변경

* fix: 스위치 aria-checked 속성 checked로 변경

* fix: 스토리북 문서화 부분 수정

* fix: 쓸모없는 패키지 제거

* fix: test 워크플로우에 typescript 설치 과정 제거

* fix: prev 타입 자동추론 되는지 확인하기

* fix: 타입추론 제대로 되도록 수정

* fix: Jest RootDir 변경

* fix: jest 및 tsconfig 정상화

* fix: a11y 테스트 쉊ㅇ

* fix: 찐 마지막

* fix: Chip 컴포넌트 최종수정

* fix: isChecked ischecked로 변경

* fix: 대문자 고치기

* fix: storybook 문서 ischecked로 변경

* fix: 스토리북 확장자 변경

---------

Co-authored-by: SeieunYoo <[email protected]>
Co-authored-by: ghdtjgus76 <[email protected]>
  • Loading branch information
3 people authored Jul 25, 2024
1 parent 4a861ed commit 4a45ee6
Show file tree
Hide file tree
Showing 12 changed files with 2,979 additions and 2,732 deletions.
9 changes: 4 additions & 5 deletions packages/shared-config/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ const config: Config = {
},
],
},

setupFilesAfterEnv: ["../shared-config/jest.setup.ts"],
verbose: true,
collectCoverage: true,
restoreMocks: true,
testMatch: [
"<rootDir>/src/**/*.test.(js|jsx|ts|tsx)",
"<rootDir>/app/**/*.test.(js|jsx|ts|tsx)",
Expand All @@ -32,6 +27,10 @@ const config: Config = {
"^@/(.*)$": "<rootDir>/src/$1",
"^@styled-system(.*)$": "<rootDir>/styled-system/$1",
},
setupFilesAfterEnv: ["../shared-config/jest.setup.ts"],
verbose: true,
collectCoverage: true,
restoreMocks: true,
};

export default config;
1 change: 1 addition & 0 deletions packages/wow-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
"@storybook/test": "^8.1.9",
"@storybook/test-runner": "^0.18.2",
"@storybook/testing-library": "^0.2.2",
"@testing-library/user-event": "^14.5.2",
"@types/node": "^20.11.24",
"@types/react": "^18.2.61",
"@types/react-dom": "^18.2.19",
Expand Down
4 changes: 3 additions & 1 deletion packages/wow-ui/src/components/Checkbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
onClick,
onKeyDown,
});

return (
<styled.label
alignItems="center"
Expand All @@ -101,12 +102,13 @@ const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
>
<styled.span alignItems="center" display="flex" position="relative">
<styled.input
aria-checked={checked}
aria-disabled={disabled}
aria-label={inputProps?.["aria-label"] ?? "checkbox"}
checked={checked}
{...(pressed && { "data-pressed": true })}
id={id}
ref={ref}
role="checkbox"
tabIndex={0}
type="checkbox"
className={checkboxStyle({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const meta = {
type: "boolean",
},
},
isChecked: {
ischecked: {
description: "isChecked는 외부에서 제어할 활성 상태를 나타냅니다.",
table: {
type: { summary: "boolean" },
Expand All @@ -59,7 +59,7 @@ const meta = {
label: {
description: "칩에 들어가게 될 텍스트입니다.",
table: {
type: { summary: "string", required: true },
type: { summary: "string" },
},
control: {
type: "text",
Expand All @@ -70,28 +70,22 @@ const meta = {
table: {
type: { summary: "() => void" },
},
control: {
type: "function",
},
control: false,
},
onDelete: {
description: "칩에 대한 필터를 제거하기 위한 함수입니다.",
table: {
type: { summary: "() => void" },
},
control: {
type: "function",
},
control: false,
},
onKeyDown: {
description:
"칩이 포커스됐을 때 엔터 키 또는 스페이스 바를 눌렀을 때 동작할 이벤트입니다.",
table: {
type: { summary: "() => void" },
},
control: {
type: "function",
},
control: false,
},
style: {
description: "칩의 커스텀 스타일을 설정합니다.",
Expand Down
124 changes: 124 additions & 0 deletions packages/wow-ui/src/components/Chip/Chip.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { render, type RenderResult, waitFor } from "@testing-library/react";
import { userEvent } from "@testing-library/user-event";

import Chip from "@/components/Chip";

describe("Chip rendering Test", () => {
let renderChip: RenderResult;
beforeEach(() => {
renderChip = render(<Chip as="div" label="Chip" />);
});

it("should render Chip", () => {
const { getByText } = renderChip;
expect(getByText("Chip")).toBeInTheDocument();
});

it("should render with attributes aria-disabled to be false by default", () => {
const chipComponent = renderChip.container.querySelector("div");

expect(chipComponent).toHaveAttribute("aria-disabled", "false");
});
});

describe("Chip toggle Test", () => {
let renderChip: RenderResult;
beforeEach(() => {
renderChip = render(<Chip as="button" clickable={true} label="Chip" />);
});

it("should toggle state when onClick event is fired", async () => {
const chipComponent = renderChip.getByRole("checkbox");
const user = userEvent.setup();

await user.click(chipComponent);
expect(chipComponent).toHaveAttribute("aria-checked", "true");
await user.click(chipComponent);
expect(chipComponent).toHaveAttribute("aria-checked", "false");
});

it("should toggle state when Enter key is pressed", async () => {
const chipComponent = renderChip.getByRole("checkbox");
userEvent.type(chipComponent, "{enter}");
await waitFor(() => {
expect(chipComponent).toHaveAttribute("aria-checked", "true");
});
userEvent.type(chipComponent, "{enter}");
await waitFor(() => {
expect(chipComponent).toHaveAttribute("aria-checked", "false");
});
});

it("should toggle state when Space key is pressed", async () => {
const chipComponent = renderChip.getByRole("checkbox");

await userEvent.type(chipComponent, "{space}");
expect(chipComponent).toHaveAttribute("aria-checked", "true");
await userEvent.type(chipComponent, "{space}");
expect(chipComponent).toHaveAttribute("aria-checked", "false");
});
});

describe("Chip disabled Test", () => {
let renderChip: RenderResult;
beforeEach(() => {
renderChip = render(<Chip disabled={true} label="Chip" />);
});

it("should render with attributes aria-disabled to be true", () => {
const chipComponent = renderChip.container.querySelector("button");

expect(chipComponent).toHaveAttribute("aria-disabled", "true");
});

it("should not allow focusing", () => {
const chipComponent = renderChip.container.querySelector("button");
userEvent.click(chipComponent!!);

expect(chipComponent).not.toHaveFocus();
});
});

describe("external control and events", () => {
let renderChip: RenderResult;

it("should fire external onClick event", async () => {
renderChip = render(<Chip clickable label="Chip" />);
const chipComponent = renderChip.getByRole("checkbox");
const user = userEvent.setup();
const onClickHandler = jest.fn();
chipComponent.onclick = onClickHandler;

await user.click(chipComponent);
expect(onClickHandler).toHaveBeenCalled();
});

it("should fire external onKeyDown event", async () => {
renderChip = render(<Chip clickable as="button" label="Chip" />);
const user = userEvent.setup();
const chipComponent = renderChip.getByRole("checkbox");
const onKeyDownHandler = jest.fn();
chipComponent.onkeydown = onKeyDownHandler;

await user.type(chipComponent, "{enter}");
expect(onKeyDownHandler).toHaveBeenCalled();
await user.type(chipComponent, "{space}");
expect(onKeyDownHandler).toHaveBeenCalled();
});

it("should toggle external checked state when onClick event fired", async () => {
const user = userEvent.setup();
let checked = false;
const handleChange = () => {
checked = !checked;
};
const rendered = render(<Chip clickable as="button" label="Chip" />);
const chipComponent = rendered.getByRole("checkbox");
chipComponent.onchange = handleChange;

await user.click(chipComponent);

expect(chipComponent).toHaveAttribute("aria-checked", "true");
expect(chipComponent).toHaveAttribute("aria-disabled", "false");
});
});
31 changes: 17 additions & 14 deletions packages/wow-ui/src/components/Chip/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {
*
* @param {T} [element] 렌더링할 요소 또는 컴포넌트. 기본값은 button이며, Chip의 경우 input으로 사용될 수 있음
* @param {boolean} [defaultChecked=false] 칩의 토글의 default 활성화 상태
* @param {boolean} [isChecked=false] 외부에서 제어할 활성 상태.
* @param {boolean} [ischecked=false] 외부에서 제어할 활성 상태.
* @param {string} label 칩 버튼에 들어갈 텍스트
* @param {boolean} [clickable=true] 클릭할 수 있는 칩인지 여부 판단
* @param {() => void} [onDelete] 칩 버튼을 삭제했을 때의 동작
Expand All @@ -42,20 +42,20 @@ type ChipComponent = <T extends ButtonElementType = "button">(

const ChipLabel = ({
label,
isChecked,
ischecked,
disabled = true,
}: {
label: string;
isChecked: boolean;
ischecked: boolean;
disabled: boolean;
}) => {
return (
<styled.div
data-disabled={disabled}
data-selected={isChecked}
data-selected={ischecked}
textStyle="label2"
className={chipLabel({
type: disabled ? "disabled" : isChecked ? "checked" : "unchecked",
type: disabled ? "disabled" : ischecked ? "checked" : "unchecked",
})}
>
{label}
Expand All @@ -71,16 +71,15 @@ const Chip: ChipComponent & { displayName?: string } = forwardRef(
clickable,
onKeyDown,
onClick,
isChecked: checkedProp = false,
ischecked: checkedProp = false,
defaultChecked = false,
disabled = false,
style,
...rest
}: ChipProps<T>,
ref: any
) => {
const Component = as || "button";
const [isChecked, setIsChecked] = useState(() =>
const Component = (as || "button") as React.ElementType;
const [ischecked, setIsChecked] = useState(() =>
checkedProp ? checkedProp : defaultChecked
);
useEffect(() => {
Expand All @@ -92,25 +91,29 @@ const Chip: ChipComponent & { displayName?: string } = forwardRef(
const handleClick = () => {
if (disabled) return;
onClick?.();
clickable ? setIsChecked((prev) => !prev) : null;
clickable ? setIsChecked((prev: boolean) => !prev) : null;
};

const handleKeyDown = (event: any) => {
if (!clickable || disabled) return;
if (event.currentTarget === event.target) {
event.preventDefault();
if (event.key === "Enter" || event.key === " ") {
setIsChecked((prev) => !prev);
setIsChecked((prev: boolean) => !prev);
onKeyDown?.();
}
}
};

return (
<Component
aria-label={`chip ${isChecked ? "activated" : "inactivated"}`}
data-selected={isChecked}
ischecked
aria-checked={clickable ? ischecked : undefined}
aria-disabled={disabled}
aria-label={`chip ${ischecked ? "activated" : "inactivated"}`}
data-selected={ischecked}
ref={ref}
role={clickable ? "checkbox" : undefined}
style={style}
className={chip({
clickable: disabled ? false : clickable,
Expand All @@ -119,7 +122,7 @@ const Chip: ChipComponent & { displayName?: string } = forwardRef(
onClick={handleClick}
onKeyDown={handleKeyDown}
>
<ChipLabel disabled={disabled} isChecked={isChecked} label={label} />
<ChipLabel disabled={disabled} ischecked={ischecked} label={label} />
</Component>
);
}
Expand Down
Loading

0 comments on commit 4a45ee6

Please sign in to comment.