Skip to content

Commit f0ce498

Browse files
authored
Merge pull request #724 from DaleStudy/645-aria-invalid-and-required
์ปดํฌ๋„ŒํŠธ ์ ‘๊ทผ์„ฑ ๊ฐœ์„ (aria-invalid, aria-required)
2 parents 660f3b4 + 264c985 commit f0ce498

File tree

9 files changed

+182
-84
lines changed

9 files changed

+182
-84
lines changed

โ€Žsrc/components/Checkbox/Checkbox.test.tsxโ€Ž

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,19 @@ describe("๋ Œ๋”๋ง", () => {
6464
expect(checkbox).toBeChecked();
6565
});
6666

67-
test("invalid๊ฐ€ true์ด๋ฉด aria-invalid๊ฐ€ ์„ค์ •๋œ๋‹ค.", () => {
67+
test("invalid prop์ด ์—†์„ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
68+
render(<Checkbox label="ํ…Œ์ŠคํŠธ" />);
69+
const checkbox = screen.getByRole("checkbox");
70+
expect(checkbox).toHaveAttribute("aria-invalid", "false");
71+
});
72+
73+
test("invalid๊ฐ€ true์ผ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
6874
render(<Checkbox label="ํ…Œ์ŠคํŠธ" invalid />);
6975
const checkbox = screen.getByRole("checkbox");
7076
expect(checkbox).toHaveAttribute("aria-invalid", "true");
7177
});
7278

73-
test("invalid๊ฐ€ false์ด๋ฉด aria-invalid๊ฐ€ false๋กœ ์„ค์ •๋œ๋‹ค.", () => {
79+
test("invalid๊ฐ€ false์ผ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
7480
render(<Checkbox label="ํ…Œ์ŠคํŠธ" invalid={false} />);
7581
const checkbox = screen.getByRole("checkbox");
7682
expect(checkbox).toHaveAttribute("aria-invalid", "false");
@@ -142,16 +148,22 @@ describe("๋ Œ๋”๋ง", () => {
142148
).not.toBeInTheDocument();
143149
});
144150

145-
test("required๊ฐ€ true์ด๋ฉด aria-required๊ฐ€ true๋กœ ์„ค์ •๋œ๋‹ค.", () => {
151+
test("required prop์ด ์—†์„ ๋•Œ aria-required ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
152+
render(<Checkbox label="์ผ๋ฐ˜ ์ฒดํฌ๋ฐ•์Šค" />);
153+
const checkbox = screen.getByRole("checkbox");
154+
expect(checkbox).toHaveAttribute("aria-required", "false");
155+
});
156+
157+
test("required๊ฐ€ true์ผ ๋•Œ aria-required ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
146158
render(<Checkbox label="ํ•„์ˆ˜ ์ฒดํฌ๋ฐ•์Šค" required />);
147159
const checkbox = screen.getByRole("checkbox");
148160
expect(checkbox).toHaveAttribute("aria-required", "true");
149161
});
150162

151-
test("required๊ฐ€ false์ด๋ฉด aria-required๊ฐ€ ์„ค์ •๋˜์ง€ ์•Š๋Š”๋‹ค.", () => {
163+
test("required๊ฐ€ false์ผ ๋•Œ aria-required ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
152164
render(<Checkbox label="์ผ๋ฐ˜ ์ฒดํฌ๋ฐ•์Šค" required={false} />);
153165
const checkbox = screen.getByRole("checkbox");
154-
expect(checkbox).not.toHaveAttribute("aria-required");
166+
expect(checkbox).toHaveAttribute("aria-required", "false");
155167
});
156168
});
157169

โ€Žsrc/components/Checkbox/Checkbox.tsxโ€Ž

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export const Checkbox = ({
4545
checked,
4646
defaultChecked,
4747
disabled,
48-
invalid,
48+
invalid = false,
4949
tone = "brand",
5050
required = false,
5151
onChange,
@@ -111,10 +111,7 @@ export const Checkbox = ({
111111
)}
112112
</ArkCheckbox.Label>
113113
)}
114-
<ArkCheckbox.HiddenInput
115-
data-test-tone={tone}
116-
aria-required={required ? true : undefined}
117-
/>
114+
<ArkCheckbox.HiddenInput data-test-tone={tone} aria-required={required} />
118115
</ArkCheckbox.Root>
119116
);
120117
};

โ€Žsrc/components/PasswordInput/PasswordInput.test.tsxโ€Ž

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,42 @@ test("์ ‘๊ทผ์„ฑ ์†์„ฑ์„ ์ œ๊ณตํ•œ๋‹ค (aria-label, aria-pressed)", async () =>
8282
expect(toggle).toHaveAttribute("aria-pressed", "true");
8383
});
8484

85+
test("invalid prop์ด ์—†์„ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
86+
render(<PasswordInput />);
87+
const input = screen.getByLabelText(/ํŒจ์Šค์›Œ๋“œ/, { selector: "input" });
88+
expect(input).toHaveAttribute("aria-invalid", "false");
89+
});
90+
91+
test("invalid๊ฐ€ true์ผ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
92+
render(<PasswordInput invalid />);
93+
const input = screen.getByLabelText(/ํŒจ์Šค์›Œ๋“œ/, { selector: "input" });
94+
expect(input).toHaveAttribute("aria-invalid", "true");
95+
});
96+
97+
test("invalid๊ฐ€ false์ผ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
98+
render(<PasswordInput invalid={false} />);
99+
const input = screen.getByLabelText(/ํŒจ์Šค์›Œ๋“œ/, { selector: "input" });
100+
expect(input).toHaveAttribute("aria-invalid", "false");
101+
});
102+
103+
test("required prop์ด ์—†์„ ๋•Œ aria-required ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
104+
render(<PasswordInput />);
105+
const input = screen.getByLabelText(/ํŒจ์Šค์›Œ๋“œ/, { selector: "input" });
106+
expect(input).toHaveAttribute("aria-required", "false");
107+
});
108+
109+
test("required๊ฐ€ true์ผ ๋•Œ aria-required ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
110+
render(<PasswordInput required />);
111+
const input = screen.getByLabelText(/ํŒจ์Šค์›Œ๋“œ/, { selector: "input" });
112+
expect(input).toHaveAttribute("aria-required", "true");
113+
});
114+
115+
test("required๊ฐ€ false์ผ ๋•Œ aria-required ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
116+
render(<PasswordInput required={false} />);
117+
const input = screen.getByLabelText(/ํŒจ์Šค์›Œ๋“œ/, { selector: "input" });
118+
expect(input).toHaveAttribute("aria-required", "false");
119+
});
120+
85121
test("ํ‚ค๋ณด๋“œ(Space/Enter)๋กœ ๊ฐ€์‹œ์„ฑ์„ ํ† ๊ธ€ํ•  ์ˆ˜ ์žˆ๋‹ค", async () => {
86122
const user = userEvent.setup();
87123
render(<PasswordInput />);

โ€Žsrc/components/PasswordInput/PasswordInput.tsxโ€Ž

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export interface PasswordInputProps extends Omit<
2323
*/
2424
export function PasswordInput({
2525
invalid = false,
26+
required = false,
2627
disabled = false,
2728
placeholder = "ํŒจ์Šค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.",
2829
ref,
@@ -49,7 +50,8 @@ export function PasswordInput({
4950
disabled={disabled}
5051
className={inputStyles()}
5152
aria-label="ํŒจ์Šค์›Œ๋“œ"
52-
aria-invalid={invalid ? true : undefined}
53+
aria-invalid={invalid}
54+
aria-required={required}
5355
{...rest}
5456
/>
5557
<button

โ€Žsrc/components/RadioGroup/RadioGroup.stories.tsxโ€Ž

Lines changed: 46 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -41,35 +41,43 @@ export const WithDefaultValue: Story = {
4141
};
4242

4343
export const Orientation: Story = {
44-
render: () => {
44+
render: (args) => {
4545
return (
4646
<div
4747
className={css({ display: "flex", flexDirection: "column", gap: "32" })}
4848
>
4949
<RadioGroup
50+
{...args}
5051
name="vertical-orientation"
5152
label="์„ธ๋กœ ๋ฐฉํ–ฅ (Vertical)"
5253
orientation="vertical"
5354
defaultValue="apple"
54-
>
55-
<Radio value="apple">์‚ฌ๊ณผ</Radio>
56-
<Radio value="banana">๋ฐ”๋‚˜๋‚˜</Radio>
57-
<Radio value="orange">์˜ค๋ Œ์ง€</Radio>
58-
</RadioGroup>
55+
/>
5956

6057
<RadioGroup
58+
{...args}
6159
name="horizontal-orientation"
6260
label="๊ฐ€๋กœ ๋ฐฉํ–ฅ (Horizontal)"
6361
orientation="horizontal"
6462
defaultValue="banana"
65-
>
66-
<Radio value="apple">์‚ฌ๊ณผ</Radio>
67-
<Radio value="banana">๋ฐ”๋‚˜๋‚˜</Radio>
68-
<Radio value="orange">์˜ค๋ Œ์ง€</Radio>
69-
</RadioGroup>
63+
/>
7064
</div>
7165
);
7266
},
67+
argTypes: {
68+
name: {
69+
control: false,
70+
},
71+
label: {
72+
control: false,
73+
},
74+
orientation: {
75+
control: false,
76+
},
77+
defaultValue: {
78+
control: false,
79+
},
80+
},
7381
};
7482

7583
export const GroupDisabled: Story = {
@@ -115,79 +123,69 @@ export const ItemDisabled: Story = {
115123
};
116124

117125
export const Tones: Story = {
118-
render: () => {
126+
render: (args) => {
119127
return (
120128
<div
121129
className={css({ display: "flex", flexDirection: "column", gap: "32" })}
122130
>
123131
<RadioGroup
132+
{...args}
124133
name="neutral-tone"
125134
label="์ค‘๋ฆฝ ์ƒ‰์กฐ (Neutral)"
126-
defaultValue="apple"
127135
tone="neutral"
128-
>
129-
<Radio value="apple">์‚ฌ๊ณผ</Radio>
130-
<Radio value="banana">๋ฐ”๋‚˜๋‚˜</Radio>
131-
<Radio value="orange">์˜ค๋ Œ์ง€</Radio>
132-
</RadioGroup>
136+
/>
133137

134138
<RadioGroup
139+
{...args}
135140
name="brand-tone"
136141
label="๋ธŒ๋žœ๋“œ ์ƒ‰์กฐ (Brand)"
137-
defaultValue="apple"
138142
tone="brand"
139-
>
140-
<Radio value="apple">์‚ฌ๊ณผ</Radio>
141-
<Radio value="banana">๋ฐ”๋‚˜๋‚˜</Radio>
142-
<Radio value="orange">์˜ค๋ Œ์ง€</Radio>
143-
</RadioGroup>
143+
/>
144144

145145
<RadioGroup
146+
{...args}
146147
name="danger-tone"
147148
label="์œ„ํ—˜ ์ƒ‰์กฐ (Danger)"
148-
defaultValue="apple"
149149
tone="danger"
150-
>
151-
<Radio value="apple">์‚ฌ๊ณผ</Radio>
152-
<Radio value="banana">๋ฐ”๋‚˜๋‚˜</Radio>
153-
<Radio value="orange">์˜ค๋ Œ์ง€</Radio>
154-
</RadioGroup>
150+
/>
155151

156152
<RadioGroup
153+
{...args}
157154
name="warning-tone"
158155
label="๊ฒฝ๊ณ  ์ƒ‰์กฐ (Warning)"
159-
defaultValue="apple"
160156
tone="warning"
161-
>
162-
<Radio value="apple">์‚ฌ๊ณผ</Radio>
163-
<Radio value="banana">๋ฐ”๋‚˜๋‚˜</Radio>
164-
<Radio value="orange">์˜ค๋ Œ์ง€</Radio>
165-
</RadioGroup>
157+
/>
166158

167159
<RadioGroup
160+
{...args}
168161
name="success-tone"
169162
label="์„ฑ๊ณต ์ƒ‰์กฐ (Success)"
170-
defaultValue="apple"
171163
tone="success"
172-
>
173-
<Radio value="apple">์‚ฌ๊ณผ</Radio>
174-
<Radio value="banana">๋ฐ”๋‚˜๋‚˜</Radio>
175-
<Radio value="orange">์˜ค๋ Œ์ง€</Radio>
176-
</RadioGroup>
164+
/>
177165

178166
<RadioGroup
167+
{...args}
179168
name="info-tone"
180169
label="์ •๋ณด ์ƒ‰์กฐ (Info)"
181-
defaultValue="apple"
182170
tone="info"
183-
>
184-
<Radio value="apple">์‚ฌ๊ณผ</Radio>
185-
<Radio value="banana">๋ฐ”๋‚˜๋‚˜</Radio>
186-
<Radio value="orange">์˜ค๋ Œ์ง€</Radio>
187-
</RadioGroup>
171+
/>
188172
</div>
189173
);
190174
},
175+
argTypes: {
176+
name: {
177+
control: false,
178+
},
179+
label: {
180+
control: false,
181+
},
182+
tone: {
183+
control: false,
184+
},
185+
},
186+
args: {
187+
defaultValue: "apple",
188+
},
191189
};
192190

193191
export const Controlled = () => {

โ€Žsrc/components/Select/Select.test.tsxโ€Ž

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,19 @@ describe("์ƒํƒœ ๊ด€๋ฆฌ", () => {
434434
});
435435

436436
describe("์ ‘๊ทผ์„ฑ ๋ฐ ๊ธฐํƒ€", () => {
437-
test("invalid๊ฐ€ true์ผ ๋•Œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค", () => {
437+
test("invalid prop์ด ์—†์„ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
438+
render(
439+
<Select placeholder="๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”">
440+
<option value="react">React</option>
441+
</Select>,
442+
);
443+
expect(screen.getByRole("combobox")).toHaveAttribute(
444+
"aria-invalid",
445+
"false",
446+
);
447+
});
448+
449+
test("invalid๊ฐ€ true์ผ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
438450
render(
439451
<Select invalid placeholder="๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”">
440452
<option value="react">React</option>
@@ -446,13 +458,28 @@ describe("์ ‘๊ทผ์„ฑ ๋ฐ ๊ธฐํƒ€", () => {
446458
);
447459
});
448460

449-
test("invalid๊ฐ€ false์ผ ๋•Œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค", () => {
461+
test("invalid๊ฐ€ false์ผ ๋•Œ aria-invalid ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
450462
render(
451463
<Select invalid={false} placeholder="๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”">
452464
<option value="react">React</option>
453465
</Select>,
454466
);
455-
expect(screen.getByRole("combobox")).not.toHaveAttribute("aria-invalid");
467+
expect(screen.getByRole("combobox")).toHaveAttribute(
468+
"aria-invalid",
469+
"false",
470+
);
471+
});
472+
473+
test("required prop์ด ์—†์„ ๋•Œ aria-required ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
474+
render(
475+
<Select placeholder="๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ•˜์„ธ์š”">
476+
<option value="react">React</option>
477+
</Select>,
478+
);
479+
expect(screen.getByRole("combobox")).toHaveAttribute(
480+
"aria-required",
481+
"false",
482+
);
456483
});
457484

458485
test("required๊ฐ€ true์ผ ๋•Œ aria-required ์†์„ฑ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋œ๋‹ค", () => {
@@ -473,7 +500,10 @@ describe("์ ‘๊ทผ์„ฑ ๋ฐ ๊ธฐํƒ€", () => {
473500
<option value="react">React</option>
474501
</Select>,
475502
);
476-
expect(screen.getByRole("combobox")).not.toHaveAttribute("aria-required");
503+
expect(screen.getByRole("combobox")).toHaveAttribute(
504+
"aria-required",
505+
"false",
506+
);
477507
});
478508

479509
test("disabled ์˜ต์…˜์ด ์žˆ์„ ๋•Œ ํ•ด๋‹น ์˜ต์…˜์€ disabled ์†์„ฑ์„ ๊ฐ€์ง„๋‹ค", () => {

โ€Žsrc/components/Select/Select.tsxโ€Ž

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ export function Select({
5252
value,
5353
defaultValue,
5454
disabled,
55-
required,
56-
invalid,
55+
required = false,
56+
invalid = false,
5757
clearButtonName,
5858
placeholder,
5959
children,
@@ -165,8 +165,8 @@ export function Select({
165165
onChange={handleChange}
166166
disabled={disabled}
167167
required={required}
168-
aria-invalid={invalid ? true : undefined}
169-
aria-required={required ? true : undefined}
168+
aria-invalid={invalid}
169+
aria-required={required}
170170
className={selectStyles({ invalid, showClearButton })}
171171
{...rest}
172172
>

0 commit comments

Comments
ย (0)