mirror of
https://github.com/carbon-design-system/carbon-components-svelte.git
synced 2025-09-14 18:01:06 +00:00
test(number-input): add unit tests
This commit is contained in:
parent
eb413a1fba
commit
6dccd5cbe2
4 changed files with 303 additions and 51 deletions
|
@ -1,51 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { NumberInput, NumberInputSkeleton } from "carbon-components-svelte";
|
|
||||||
import type { NumberInputProps } from "carbon-components-svelte/NumberInput/NumberInput.svelte";
|
|
||||||
|
|
||||||
let value: NumberInputProps["value"] = null;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
{value}
|
|
||||||
|
|
||||||
<NumberInput
|
|
||||||
disabled
|
|
||||||
light
|
|
||||||
min={4}
|
|
||||||
max={20}
|
|
||||||
value={4}
|
|
||||||
label="Clusters"
|
|
||||||
helperText="Clusters provisioned in your region"
|
|
||||||
invalidText="Number must be between 4 and 20."
|
|
||||||
on:input={(e) => {
|
|
||||||
console.log({ input: e.detail }); // null | number
|
|
||||||
}}
|
|
||||||
on:change={(e) => {
|
|
||||||
console.log({ change: e.detail }); // null | number
|
|
||||||
}}
|
|
||||||
on:keydown
|
|
||||||
on:keyup
|
|
||||||
on:paste
|
|
||||||
/>
|
|
||||||
|
|
||||||
<NumberInput
|
|
||||||
disabled
|
|
||||||
light
|
|
||||||
min={1}
|
|
||||||
max={10}
|
|
||||||
value={4}
|
|
||||||
step={0.1}
|
|
||||||
label="Clusters"
|
|
||||||
helperText="Clusters provisioned in your region"
|
|
||||||
invalidText="Number must be between 1 and 10."
|
|
||||||
on:input={(e) => {
|
|
||||||
console.log({ input: e.detail }); // null | number
|
|
||||||
}}
|
|
||||||
on:change={(e) => {
|
|
||||||
console.log(e.detail); // null | number
|
|
||||||
}}
|
|
||||||
on:keydown
|
|
||||||
on:keyup
|
|
||||||
on:paste
|
|
||||||
/>
|
|
||||||
|
|
||||||
<NumberInputSkeleton hideLabel />
|
|
59
tests/NumberInput/NumberInput.test.svelte
Normal file
59
tests/NumberInput/NumberInput.test.svelte
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { NumberInput } from "carbon-components-svelte";
|
||||||
|
import type { ComponentProps } from "svelte";
|
||||||
|
|
||||||
|
export let value: ComponentProps<NumberInput>["value"] = 0;
|
||||||
|
export let step: ComponentProps<NumberInput>["step"] = 1;
|
||||||
|
export let min: ComponentProps<NumberInput>["min"] = undefined;
|
||||||
|
export let max: ComponentProps<NumberInput>["max"] = undefined;
|
||||||
|
export let size: ComponentProps<NumberInput>["size"] = undefined;
|
||||||
|
export let light = false;
|
||||||
|
export let readonly = false;
|
||||||
|
export let allowEmpty = false;
|
||||||
|
export let disabled = false;
|
||||||
|
export let hideSteppers = false;
|
||||||
|
export let iconDescription = "";
|
||||||
|
export let invalid = false;
|
||||||
|
export let invalidText = "";
|
||||||
|
export let warn = false;
|
||||||
|
export let warnText = "";
|
||||||
|
export let helperText = "";
|
||||||
|
export let label = "Clusters";
|
||||||
|
export let hideLabel = false;
|
||||||
|
export let id = "ccs-test";
|
||||||
|
export let name: ComponentProps<NumberInput>["name"] = undefined;
|
||||||
|
export let ref: ComponentProps<NumberInput>["ref"] = null;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<NumberInput
|
||||||
|
bind:value
|
||||||
|
{step}
|
||||||
|
{min}
|
||||||
|
{max}
|
||||||
|
{size}
|
||||||
|
{light}
|
||||||
|
{readonly}
|
||||||
|
{allowEmpty}
|
||||||
|
{disabled}
|
||||||
|
{hideSteppers}
|
||||||
|
{iconDescription}
|
||||||
|
{invalid}
|
||||||
|
{invalidText}
|
||||||
|
{warn}
|
||||||
|
{warnText}
|
||||||
|
{helperText}
|
||||||
|
{label}
|
||||||
|
{hideLabel}
|
||||||
|
{id}
|
||||||
|
{name}
|
||||||
|
{ref}
|
||||||
|
on:change
|
||||||
|
on:input
|
||||||
|
on:keydown
|
||||||
|
on:keyup
|
||||||
|
on:focus
|
||||||
|
on:blur
|
||||||
|
on:paste
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div data-testid="value">{value}</div>
|
237
tests/NumberInput/NumberInput.test.ts
Normal file
237
tests/NumberInput/NumberInput.test.ts
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
import { render, screen } from "@testing-library/svelte";
|
||||||
|
import { user } from "../setup-tests";
|
||||||
|
import NumberInput from "./NumberInput.test.svelte";
|
||||||
|
import NumberInputCustom from "./NumberInputCustom.test.svelte";
|
||||||
|
|
||||||
|
describe("NumberInput", () => {
|
||||||
|
it("should render with default props", () => {
|
||||||
|
render(NumberInput);
|
||||||
|
|
||||||
|
expect(screen.getByLabelText("Clusters")).toBeInTheDocument();
|
||||||
|
expect(screen.getByRole("spinbutton")).toHaveValue(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle step value", () => {
|
||||||
|
render(NumberInput, { props: { step: 0.1 } });
|
||||||
|
|
||||||
|
expect(screen.getByRole("spinbutton")).toHaveAttribute("step", "0.1");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle min and max values", () => {
|
||||||
|
render(NumberInput, { props: { min: 4, max: 20 } });
|
||||||
|
|
||||||
|
const input = screen.getByRole("spinbutton");
|
||||||
|
expect(input).toHaveAttribute("min", "4");
|
||||||
|
expect(input).toHaveAttribute("max", "20");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle different sizes", () => {
|
||||||
|
(["sm", "xl"] as const).forEach((size) => {
|
||||||
|
const { container } = render(NumberInput, {
|
||||||
|
props: { size },
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = container.querySelector("input");
|
||||||
|
expect(input?.closest(".bx--number")).toHaveClass(`bx--number--${size}`);
|
||||||
|
container.remove();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle light variant", () => {
|
||||||
|
render(NumberInput, { props: { light: true } });
|
||||||
|
|
||||||
|
expect(screen.getByRole("spinbutton").closest(".bx--number")).toHaveClass(
|
||||||
|
"bx--number--light",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle disabled state", () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: { disabled: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = screen.getByRole("spinbutton");
|
||||||
|
expect(input).toBeDisabled();
|
||||||
|
expect(screen.getByText("Clusters")).toHaveClass("bx--label--disabled");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle helper text", () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: { helperText: "Helper text" },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText("Helper text")).toHaveClass(
|
||||||
|
"bx--form__helper-text",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle invalid state", () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: { invalid: true, invalidText: "Invalid input" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = screen.getByRole("spinbutton");
|
||||||
|
expect(input).toHaveAttribute("aria-invalid", "true");
|
||||||
|
expect(screen.getByText("Invalid input")).toBeInTheDocument();
|
||||||
|
|
||||||
|
expect(input.closest(".bx--number")).toHaveAttribute(
|
||||||
|
"data-invalid",
|
||||||
|
"true",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle warning state", () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: { warn: true, warnText: "Warning message" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = screen.getByRole("spinbutton");
|
||||||
|
expect(input.closest(".bx--number__input-wrapper")).toHaveClass(
|
||||||
|
"bx--number__input-wrapper--warning",
|
||||||
|
);
|
||||||
|
expect(screen.getByText("Warning message")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle hidden label", () => {
|
||||||
|
render(NumberInput, { props: { hideLabel: true } });
|
||||||
|
|
||||||
|
expect(screen.getByText("Clusters")).toHaveClass("bx--visually-hidden");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle custom id", () => {
|
||||||
|
render(NumberInput, { props: { id: "custom-id" } });
|
||||||
|
|
||||||
|
const input = screen.getByRole("spinbutton");
|
||||||
|
expect(input).toHaveAttribute("id", "custom-id");
|
||||||
|
expect(screen.getByText("Clusters")).toHaveAttribute("for", "custom-id");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle custom name", () => {
|
||||||
|
render(NumberInput, { props: { name: "custom-name" } });
|
||||||
|
|
||||||
|
expect(screen.getByRole("spinbutton")).toHaveAttribute(
|
||||||
|
"name",
|
||||||
|
"custom-name",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle readonly state", () => {
|
||||||
|
render(NumberInput, { props: { readonly: true } });
|
||||||
|
|
||||||
|
expect(screen.getByRole("spinbutton")).toHaveAttribute("readonly");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle hidden steppers", () => {
|
||||||
|
render(NumberInput, { props: { hideSteppers: true } });
|
||||||
|
|
||||||
|
expect(
|
||||||
|
screen.queryByRole("button", { name: "Increment number" }),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
screen.queryByRole("button", { name: "Decrement number" }),
|
||||||
|
).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO(bug): The icon descriptions are not being applied.
|
||||||
|
it.skip("should handle custom icon descriptions", () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: { iconDescription: "Custom description" },
|
||||||
|
});
|
||||||
|
|
||||||
|
screen.getAllByRole("button").forEach((button) => {
|
||||||
|
expect(button).toHaveAttribute("title", "Custom description");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle custom slots", () => {
|
||||||
|
render(NumberInputCustom);
|
||||||
|
|
||||||
|
expect(screen.getByText("Custom Label Text")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle value binding", async () => {
|
||||||
|
render(NumberInput);
|
||||||
|
|
||||||
|
const input = screen.getByRole("spinbutton");
|
||||||
|
await user.type(input, "5");
|
||||||
|
expect(screen.getByTestId("value").textContent).toBe("5");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle increment/decrement buttons", async () => {
|
||||||
|
render(NumberInput);
|
||||||
|
|
||||||
|
const incrementButton = screen.getByRole("button", {
|
||||||
|
name: "Increment number",
|
||||||
|
});
|
||||||
|
const decrementButton = screen.getByRole("button", {
|
||||||
|
name: "Decrement number",
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.click(incrementButton);
|
||||||
|
expect(screen.getByTestId("value").textContent).toBe("1");
|
||||||
|
|
||||||
|
await user.click(decrementButton);
|
||||||
|
expect(screen.getByTestId("value").textContent).toBe("0");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle empty value when allowEmpty is true", async () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: { allowEmpty: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
const input = screen.getByRole("spinbutton");
|
||||||
|
await user.clear(input);
|
||||||
|
expect(input).toHaveValue(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle min/max validation", async () => {
|
||||||
|
render(NumberInput, { props: { min: 4, max: 20 } });
|
||||||
|
|
||||||
|
const input = screen.getByRole("spinbutton");
|
||||||
|
await user.type(input, "25");
|
||||||
|
expect(screen.getByTestId("value").textContent).toBe("25");
|
||||||
|
expect(screen.getByRole("spinbutton")).toHaveAttribute(
|
||||||
|
"aria-invalid",
|
||||||
|
"true",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not show helper text when invalid", () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: {
|
||||||
|
invalid: true,
|
||||||
|
invalidText: "Invalid input",
|
||||||
|
helperText: "Helper text",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.queryByText("Helper text")).not.toBeInTheDocument();
|
||||||
|
expect(screen.getByText("Invalid input")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not show helper text when warning", () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: {
|
||||||
|
warn: true,
|
||||||
|
warnText: "Warning message",
|
||||||
|
helperText: "Helper text",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.queryByText("Helper text")).not.toBeInTheDocument();
|
||||||
|
expect(screen.getByText("Warning message")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle disabled helper text", () => {
|
||||||
|
render(NumberInput, {
|
||||||
|
props: {
|
||||||
|
disabled: true,
|
||||||
|
helperText: "Helper text",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText("Helper text")).toHaveClass(
|
||||||
|
"bx--form__helper-text--disabled",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
7
tests/NumberInput/NumberInputCustom.test.svelte
Normal file
7
tests/NumberInput/NumberInputCustom.test.svelte
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { NumberInput } from "carbon-components-svelte";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<NumberInput label="Custom label" value={0}>
|
||||||
|
<span slot="label">Custom Label Text</span>
|
||||||
|
</NumberInput>
|
Loading…
Add table
Add a link
Reference in a new issue