mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-14 18:01:06 +00:00
test(combo-box): add unit tests
This commit is contained in:
parent
d25a85c825
commit
0e1177f398
4 changed files with 271 additions and 77 deletions
|
@ -1,77 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { ComboBox } from "carbon-components-svelte";
|
||||
import type { ComboBoxItem } from "carbon-components-svelte/ComboBox/ComboBox.svelte";
|
||||
|
||||
const items: ComboBoxItem[] = [
|
||||
{ id: 0, text: "Slack" },
|
||||
{ id: "1", text: "Email" },
|
||||
{ id: "2", text: "Fax", disabled: true },
|
||||
];
|
||||
|
||||
let ref: ComboBox;
|
||||
|
||||
$: ref?.clear({ focus: false });
|
||||
$: ref?.clear();
|
||||
</script>
|
||||
|
||||
<ComboBox
|
||||
bind:this={ref}
|
||||
direction="top"
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
{items}
|
||||
on:select={(e) => {
|
||||
console.log(e.detail.selectedId);
|
||||
}}
|
||||
on:clear={(e) => {
|
||||
console.log(e.detail);
|
||||
}}
|
||||
translateWithId={(id) => {
|
||||
console.log(id); // "open" | "close"
|
||||
return id;
|
||||
}}
|
||||
translateWithIdSelection={(id) => {
|
||||
console.log(id); // "clearSelection"
|
||||
return id;
|
||||
}}
|
||||
let:item
|
||||
let:index
|
||||
>
|
||||
{item.id}
|
||||
{index}
|
||||
</ComboBox>
|
||||
|
||||
<ComboBox
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
selectedId="1"
|
||||
{items}
|
||||
/>
|
||||
|
||||
<ComboBox
|
||||
light
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
{items}
|
||||
/>
|
||||
|
||||
<ComboBox
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
size="xl"
|
||||
{items}
|
||||
/>
|
||||
|
||||
<ComboBox
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
size="sm"
|
||||
{items}
|
||||
/>
|
||||
|
||||
<ComboBox
|
||||
disabled
|
||||
titleText="Contact"
|
||||
placeholder="Select contact method"
|
||||
{items}
|
||||
/>
|
49
tests/ComboBox/ComboBox.test.svelte
Normal file
49
tests/ComboBox/ComboBox.test.svelte
Normal file
|
@ -0,0 +1,49 @@
|
|||
<script lang="ts">
|
||||
import { ComboBox } from "carbon-components-svelte";
|
||||
import type { ComboBoxItem } from "carbon-components-svelte/ComboBox/ComboBox.svelte";
|
||||
|
||||
export let items: ComboBoxItem[] = [
|
||||
{ id: "0", text: "Slack" },
|
||||
{ id: "1", text: "Email" },
|
||||
{ id: "2", text: "Fax" },
|
||||
];
|
||||
export let selectedId: string | undefined = undefined;
|
||||
export let value = "";
|
||||
export let disabled = false;
|
||||
export let invalid = false;
|
||||
export let warn = false;
|
||||
export let light = false;
|
||||
export let open = false;
|
||||
export let titleText = "Contact";
|
||||
export let placeholder = "Select contact method";
|
||||
export let invalidText = "";
|
||||
export let warnText = "";
|
||||
export let helperText = "";
|
||||
export let size: "sm" | "xl" | undefined = undefined;
|
||||
export let shouldFilterItem = (item: ComboBoxItem, value: string) =>
|
||||
item.text.toLowerCase().includes(value.toLowerCase());
|
||||
</script>
|
||||
|
||||
<ComboBox
|
||||
{disabled}
|
||||
{helperText}
|
||||
{invalid}
|
||||
{invalidText}
|
||||
{items}
|
||||
{light}
|
||||
{open}
|
||||
{placeholder}
|
||||
{selectedId}
|
||||
{size}
|
||||
{titleText}
|
||||
{value}
|
||||
{warn}
|
||||
{warnText}
|
||||
{shouldFilterItem}
|
||||
on:select={(e) => {
|
||||
console.log("select", e.detail);
|
||||
}}
|
||||
on:clear={(e) => {
|
||||
console.log("clear", e.type);
|
||||
}}
|
||||
/>
|
186
tests/ComboBox/ComboBox.test.ts
Normal file
186
tests/ComboBox/ComboBox.test.ts
Normal file
|
@ -0,0 +1,186 @@
|
|||
import { render, screen } from "@testing-library/svelte";
|
||||
import { user } from "../setup-tests";
|
||||
import ComboBox from "./ComboBox.test.svelte";
|
||||
import ComboBoxCustom from "./ComboBoxCustom.test.svelte";
|
||||
|
||||
describe("ComboBox", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("should render with default props", () => {
|
||||
render(ComboBox);
|
||||
|
||||
expect(screen.getByText("Contact")).toBeInTheDocument();
|
||||
const input = screen.getByRole("textbox");
|
||||
expect(input).toHaveAttribute("placeholder", "Select contact method");
|
||||
});
|
||||
|
||||
it("should open menu on click", async () => {
|
||||
render(ComboBox);
|
||||
|
||||
const input = screen.getByRole("textbox");
|
||||
await user.click(input);
|
||||
|
||||
const dropdown = screen.getAllByRole("listbox")[1];
|
||||
expect(dropdown).toBeVisible();
|
||||
});
|
||||
|
||||
it("should handle item selection", async () => {
|
||||
const consoleLog = vi.spyOn(console, "log");
|
||||
render(ComboBox);
|
||||
|
||||
await user.click(screen.getByRole("textbox"));
|
||||
await user.click(screen.getByText("Email"));
|
||||
|
||||
expect(consoleLog).toHaveBeenCalledWith("select", {
|
||||
selectedId: "1",
|
||||
selectedItem: { id: "1", text: "Email" },
|
||||
});
|
||||
expect(screen.getByRole("textbox")).toHaveValue("Email");
|
||||
});
|
||||
|
||||
it("should handle keyboard navigation", async () => {
|
||||
render(ComboBox);
|
||||
|
||||
const input = screen.getByRole("textbox");
|
||||
await user.click(input);
|
||||
await user.keyboard("{ArrowDown}");
|
||||
await user.keyboard("{Enter}");
|
||||
|
||||
expect(input).toHaveValue("Slack");
|
||||
});
|
||||
|
||||
it("should handle clear selection", async () => {
|
||||
const consoleLog = vi.spyOn(console, "log");
|
||||
render(ComboBox, {
|
||||
props: {
|
||||
selectedId: "1",
|
||||
value: "Email",
|
||||
},
|
||||
});
|
||||
|
||||
const clearButton = screen.getByRole("button", { name: /clear/i });
|
||||
await user.click(clearButton);
|
||||
|
||||
expect(consoleLog).toHaveBeenCalledWith("clear", expect.any(String));
|
||||
expect(screen.getByRole("textbox")).toHaveValue("");
|
||||
});
|
||||
|
||||
it("should handle disabled state", () => {
|
||||
render(ComboBox, { props: { disabled: true } });
|
||||
|
||||
expect(screen.getByRole("textbox")).toBeDisabled();
|
||||
expect(screen.getByText("Contact")).toHaveClass("bx--label--disabled");
|
||||
});
|
||||
|
||||
it("should handle invalid state", () => {
|
||||
render(ComboBox, {
|
||||
props: {
|
||||
invalid: true,
|
||||
invalidText: "Invalid selection",
|
||||
},
|
||||
});
|
||||
|
||||
expect(screen.getByRole("listbox")).toHaveAttribute("data-invalid", "true");
|
||||
expect(screen.getByText("Invalid selection")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should handle warning state", () => {
|
||||
render(ComboBox, {
|
||||
props: {
|
||||
warn: true,
|
||||
warnText: "Warning message",
|
||||
},
|
||||
});
|
||||
|
||||
expect(screen.getByText("Warning message")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should handle helper text", () => {
|
||||
render(ComboBox, { props: { helperText: "Helper message" } });
|
||||
|
||||
expect(screen.getByText("Helper message")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("should handle light variant", () => {
|
||||
render(ComboBox, { props: { light: true } });
|
||||
|
||||
expect(screen.getByRole("textbox")).toHaveClass("bx--text-input--light");
|
||||
});
|
||||
|
||||
test.each([
|
||||
["sm", "bx--list-box--sm"],
|
||||
["xl", "bx--list-box--xl"],
|
||||
] as const)("should handle size variants", (size, className) => {
|
||||
render(ComboBox, { props: { size } });
|
||||
expect(screen.getByRole("listbox")).toHaveClass(className);
|
||||
});
|
||||
|
||||
it("should handle filtering items", async () => {
|
||||
render(ComboBox);
|
||||
|
||||
const input = screen.getByRole("textbox");
|
||||
await user.click(input);
|
||||
await user.type(input, "em");
|
||||
|
||||
const options = screen.getAllByRole("option");
|
||||
expect(options).toHaveLength(1);
|
||||
expect(options[0]).toHaveTextContent("Email");
|
||||
});
|
||||
|
||||
it("should handle disabled items", async () => {
|
||||
render(ComboBoxCustom);
|
||||
|
||||
await user.click(screen.getByRole("textbox"));
|
||||
const disabledOption = screen.getByText(/Fax/).closest('[role="option"]');
|
||||
assert(disabledOption);
|
||||
expect(disabledOption).toHaveAttribute("disabled", "true");
|
||||
|
||||
await user.click(disabledOption);
|
||||
expect(screen.getByRole("textbox")).toHaveValue("");
|
||||
|
||||
// Dropdown remains open
|
||||
const dropdown = screen.getAllByRole("listbox")[1];
|
||||
expect(dropdown).toBeVisible();
|
||||
});
|
||||
|
||||
it("should handle custom item display", async () => {
|
||||
render(ComboBoxCustom);
|
||||
|
||||
await user.click(screen.getByRole("textbox"));
|
||||
const options = screen.getAllByRole("option");
|
||||
|
||||
expect(options[0]).toHaveTextContent("Item Slack");
|
||||
expect(options[1]).toHaveTextContent("Item Email");
|
||||
expect(options[2]).toHaveTextContent("Item Fax");
|
||||
});
|
||||
|
||||
it("should handle top direction", async () => {
|
||||
render(ComboBoxCustom, { props: { direction: "top" } });
|
||||
|
||||
await user.click(screen.getAllByRole("button")[0]);
|
||||
expect(screen.getByRole("listbox")).toHaveClass("bx--list-box--up");
|
||||
});
|
||||
|
||||
it("should programmatically clear selection", async () => {
|
||||
render(ComboBoxCustom, { props: { selectedId: "1" } });
|
||||
|
||||
expect(screen.getByRole("textbox")).toHaveValue("Email");
|
||||
await user.click(screen.getByText("Clear"));
|
||||
expect(screen.getByRole("textbox")).toHaveValue("");
|
||||
});
|
||||
|
||||
it("should close menu on Escape key", async () => {
|
||||
render(ComboBox);
|
||||
|
||||
const input = screen.getByRole("textbox");
|
||||
await user.click(input);
|
||||
|
||||
const dropdown = screen.getAllByRole("listbox")[1];
|
||||
expect(dropdown).toBeVisible();
|
||||
|
||||
await user.keyboard("{Escape}");
|
||||
expect(dropdown).not.toBeVisible();
|
||||
});
|
||||
});
|
36
tests/ComboBox/ComboBoxCustom.test.svelte
Normal file
36
tests/ComboBox/ComboBoxCustom.test.svelte
Normal file
|
@ -0,0 +1,36 @@
|
|||
<script lang="ts">
|
||||
import { ComboBox } from "carbon-components-svelte";
|
||||
import type { ComboBoxItem } from "carbon-components-svelte/ComboBox/ComboBox.svelte";
|
||||
|
||||
let comboBoxRef: ComboBox;
|
||||
|
||||
export let items: ComboBoxItem[] = [
|
||||
{ id: "0", text: "Slack" },
|
||||
{ id: "1", text: "Email" },
|
||||
{ id: "2", text: "Fax", disabled: true },
|
||||
];
|
||||
export let selectedId: string | undefined = undefined;
|
||||
export let direction: "top" | "bottom" = "bottom";
|
||||
export let shouldFilterItem = (item: ComboBoxItem, value: string) =>
|
||||
item.text.toLowerCase().includes(value.toLowerCase());
|
||||
export let itemToString = (item: ComboBoxItem) => item.text;
|
||||
</script>
|
||||
|
||||
<ComboBox
|
||||
bind:this={comboBoxRef}
|
||||
{items}
|
||||
{selectedId}
|
||||
{direction}
|
||||
{shouldFilterItem}
|
||||
{itemToString}
|
||||
titleText="Contact with icons"
|
||||
placeholder="Select contact method"
|
||||
on:select={(e) => {
|
||||
console.log("select", e.detail);
|
||||
}}
|
||||
let:item
|
||||
>
|
||||
<span>Item {item.text}</span>
|
||||
</ComboBox>
|
||||
|
||||
<button type="button" on:click={() => comboBoxRef.clear()}>Clear</button>
|
Loading…
Add table
Add a link
Reference in a new issue