-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: dropdown aria 속성 추가, test 코드 추가
- Loading branch information
Showing
3 changed files
with
213 additions
and
1 deletion.
There are no files selected for viewing
207 changes: 207 additions & 0 deletions
207
packages/wow-ui/src/components/DropDown/DropDown.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
"use client"; | ||
|
||
import { render, screen, waitFor } from "@testing-library/react"; | ||
import { userEvent } from "@testing-library/user-event"; | ||
import type { ReactNode } from "react"; | ||
import { useState } from "react"; | ||
|
||
import DropDown from "@/components/DropDown"; | ||
import DropDownOption from "@/components/DropDown/DropDownOption"; | ||
|
||
const dropdownId = "dropdown-id"; | ||
|
||
const options = [ | ||
{ value: "option1", text: "Option 1" }, | ||
{ value: "option2", text: "Option 2" }, | ||
{ value: "option3", text: "Option 3" }, | ||
]; | ||
|
||
const renderDropDown = (props = {}) => | ||
render( | ||
<DropDown {...props} id={dropdownId}> | ||
{options.map((option) => ( | ||
<DropDownOption | ||
key={option.value} | ||
text={option.text} | ||
value={option.value} | ||
/> | ||
))} | ||
</DropDown> | ||
); | ||
|
||
describe("DropDown component", () => { | ||
it("should render the placeholder", () => { | ||
renderDropDown({ placeholder: "Please select" }); | ||
expect(screen.getByText("Please select")).toBeInTheDocument(); | ||
}); | ||
|
||
it("should allow selection of an option", async () => { | ||
const dropdownId = "dropdown-id"; | ||
renderDropDown({ id: dropdownId, placeholder: "Please select" }); | ||
|
||
await userEvent.click(screen.getByText("Please select")); | ||
await userEvent.click(screen.getByText("Option 1")); | ||
|
||
await waitFor(() => { | ||
const option1 = document.querySelector(`#${dropdownId}-option-option1`); | ||
expect(option1).toHaveAttribute("aria-selected", "true"); | ||
}); | ||
}); | ||
|
||
it("should render with default value", () => { | ||
renderDropDown({ | ||
defaultValue: "option2", | ||
placeholder: "Please select", | ||
}); | ||
|
||
const dropdownButton = screen.getByRole("button", { | ||
name: "Option 2 down-arrow icon", | ||
}); | ||
expect(dropdownButton).toBeInTheDocument(); | ||
expect(dropdownButton).toHaveAttribute("id", `${dropdownId}-trigger`); | ||
expect(dropdownButton).toHaveTextContent("Option 2"); | ||
}); | ||
|
||
it("should render the trigger button", async () => { | ||
renderDropDown({ trigger: <button>Open Dropdown</button> }); | ||
|
||
userEvent.click(screen.getByText("Open Dropdown")); | ||
|
||
await waitFor(() => { | ||
expect(screen.getByText("Option 1")).toBeInTheDocument(); | ||
}); | ||
}); | ||
|
||
it("closes dropdown when clicking outside", async () => { | ||
renderDropDown({ placeholder: "Select an option" }); | ||
await userEvent.click(screen.getByText("Select an option")); | ||
await userEvent.click(document.body); | ||
|
||
await waitFor(() => { | ||
const dropdown = screen.queryByRole("listbox"); | ||
expect(dropdown).toBeNull(); | ||
}); | ||
}); | ||
}); | ||
|
||
describe("external control and events", () => { | ||
it("should fire external onChange event and update controlled state", async () => { | ||
const ControlledDropDown = () => { | ||
const [selectedValue, setSelectedValue] = useState(""); | ||
|
||
const handleChange = (value: { | ||
selectedValue: string; | ||
selectedText: ReactNode; | ||
}) => { | ||
setSelectedValue(value.selectedValue); | ||
}; | ||
|
||
return ( | ||
<DropDown | ||
id={dropdownId} | ||
placeholder="Please select" | ||
value={selectedValue} | ||
onChange={handleChange} | ||
> | ||
{options.map((option) => ( | ||
<DropDownOption | ||
key={option.value} | ||
text={option.text} | ||
value={option.value} | ||
/> | ||
))} | ||
</DropDown> | ||
); | ||
}; | ||
|
||
render(<ControlledDropDown />); | ||
|
||
await userEvent.click(screen.getByText("Please select")); | ||
await userEvent.click(screen.getByText("Option 2")); | ||
|
||
await waitFor(() => { | ||
const option2 = document.querySelector(`#${dropdownId}-option-option2`); | ||
expect(option2).toHaveAttribute("aria-selected", "true"); | ||
}); | ||
}); | ||
|
||
it("should navigate options using keyboard and apply focus correctly", async () => { | ||
const ControlledDropDown = () => { | ||
const [selectedValue, setSelectedValue] = useState(""); | ||
|
||
const handleChange = (value: { | ||
selectedValue: string; | ||
selectedText: ReactNode; | ||
}) => { | ||
setSelectedValue(value.selectedValue); | ||
}; | ||
|
||
return ( | ||
<DropDown | ||
id={dropdownId} | ||
placeholder="Please select" | ||
value={selectedValue} | ||
onChange={handleChange} | ||
> | ||
{options.map((option) => ( | ||
<DropDownOption | ||
key={option.value} | ||
text={option.text} | ||
value={option.value} | ||
/> | ||
))} | ||
</DropDown> | ||
); | ||
}; | ||
|
||
render(<ControlledDropDown />); | ||
await userEvent.click(screen.getByText("Please select")); | ||
|
||
await userEvent.keyboard("{ArrowDown}"); | ||
await waitFor(() => { | ||
const dropdown = screen.getByRole("listbox"); | ||
expect(dropdown).toHaveAttribute( | ||
"aria-activedescendant", | ||
`${dropdownId}-option-option1` | ||
); | ||
}); | ||
|
||
await userEvent.keyboard("{ArrowDown}"); | ||
await waitFor(() => { | ||
const dropdown = screen.getByRole("listbox"); | ||
expect(dropdown).toHaveAttribute( | ||
"aria-activedescendant", | ||
`${dropdownId}-option-option2` | ||
); | ||
}); | ||
|
||
await userEvent.keyboard("{ArrowDown}"); | ||
await waitFor(() => { | ||
const dropdown = screen.getByRole("listbox"); | ||
expect(dropdown).toHaveAttribute( | ||
"aria-activedescendant", | ||
`${dropdownId}-option-option3` | ||
); | ||
}); | ||
|
||
await userEvent.keyboard("{ArrowUp}"); | ||
await waitFor(() => { | ||
const dropdown = screen.getByRole("listbox"); | ||
expect(dropdown).toHaveAttribute( | ||
"aria-activedescendant", | ||
`${dropdownId}-option-option2` | ||
); | ||
}); | ||
|
||
await userEvent.keyboard("{Enter}"); | ||
await waitFor(() => { | ||
const option2 = document.querySelector(`#${dropdownId}-option-option2`); | ||
expect(option2).toHaveAttribute("aria-selected", "true"); | ||
|
||
const option1 = document.querySelector(`#${dropdownId}-option-option1`); | ||
const option3 = document.querySelector(`#${dropdownId}-option-option3`); | ||
expect(option1).toHaveAttribute("aria-selected", "false"); | ||
expect(option3).toHaveAttribute("aria-selected", "false"); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters