mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-15 10:21:05 +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