WK 4e41f50fa2
v2.7.10 (#5381)
* fix(date-picker): error state (#5317)

* fix(date-range-picker): fixed the error state in preset

* Update giant-sloths-shop.md

* Removed if statement

* chore(date-picker): prettier

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix(theme): clear button in mobile (#5252)

* fix(toast): fixed close button hover position

* fix(input): fixed the clear button rendering on smaller devices

* Delete .changeset/soft-spoons-march.md

* Update input.ts

* Undo unrelated toast changes

* fix(toast): icons (#5246)

* feat(shared-icons): add loading icon

* fix(toast): icons

* chore(toast): revise types for icons

* chore(changeset): add changeset

* refactor: migrate eslint to v9 (#5267)

* refactor: migrate eslint to v9

* chore: lint

* chore: update eslint command

* chore: fix lint warnings

* chore: separate lint and lint:fix

* chore: exclude contentlayer generated code

* fix(scripts): add missing await

* fix(autocomplete): persist last selected item position (#5286)

* refactor(select): remove unnecessary code

* fix(autocomplete): persist last selected item position

* chore(changeset): add changeset

* chore(deps): bump framer-motion version (#5287)

* chore(deps): bump framer-motion version

* fix: typing issues

* chore(changeset): add changeset

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* chore(docs): supplement onAction & selectionBehavior (#5289)

* fix(autocomplete): ensure focused item matches selected item after filter, selection (#5290)

* fix(autocomplete): ensure focused item matches selected item after filter, selection

* chore: apply type and default value

* chore: add perpose coment in updated code

* test: add focuskey management testcode

* docs: add changeset

* docs: update changeset

* chore: remove comment

* fix: broken components in stories (#5291)

* chore(switch): remove xl size

* chore(docs): remove xl size

* chore(system-rsc): remove xl size

* chore(circular-progress): remove xl size

* chore: undo

* chore(deps): bump RA versions (#5310)

* chore(deps): ra version bump

* chore(changeset): add changeset

* fix(scripts): incorrect docs path

---------

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* chore(docs): update meta data (#5311)

* docs(layout.tsx): added text-foreground (#5316)

* feat(tabs): add click handling for tab items in tests and implementation (#3917)

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix issues in tabs examples (#2405)

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* chore(docs): add missing onValueChange in CheckboxGroup (#5332)

* ci(changesets): version packages (#5323)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

* chore(deps): bump RA versions (#5361)

* chore(deps): bump RA versions

* chore(deps): bump RA versions

* chore(deps): bump RA versions

* chore: changeset

* refactor(listbox): already extends in AriaListBoxProps

* chore(docs): remove herohack announcement (#5363)

* chore: remove herohack announcement

* Update carbon-ad.tsx

* chore(docs): fixed lint errors

* chore(docs): requested changes

* Update carbon-ad.tsx

* Update carbon-ad.tsx

* fix(theme): consistent faded styling for isInvalid in InputOtp and DateInput (#5349)

* fix(input-otp): remove bg and border styles from faded variant when isInvalid

* fix(date-input): remove bg styles from faded variant when isInvalid

* chore(changeset): add changeset

* chore: bump theme peerDependencies

* chore: bump theme peerDependencies

* fix: wrong version

* chore: extra line

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix(theme): helperWrapper padding (#5350)

* fix(number-input): decreased helperWrapper padding to maintain consistency

* Update beige-laws-heal.md

* chore(theme): change to p-1

* chore(deps): bump peerDependencies for theme pkg

* fix(number-input): incorrect versions

* chore(changeset): include number input

---------

Co-authored-by: WK Wong <wingkwong.code@gmail.com>

* fix(autocomplete): onClear (#5365)

* fix(autocomplete): add onClear

* feat(autocomplete): add test case for onClear

* chore(changeset): add changeset

* fix(number-input): only allow number type (#5368)

* refactor(number-input): avoid non number type passing to number input

* chore(changeset): add changeset

* refactor: optimization (#5362)

* chore(deps): bump RA versions

* chore(deps): bump RA versions

* chore(deps): bump RA versions

* chore: changeset

* chore(deps): remove unnecessary dependencies

* fix(calendar): typing issue

* refactor(system): remove unused SupportedCalendars

* refactor(system): move I18nProviderProps to type

* refactor: use `spectrumCalendarProps<DateValue>["createCalendar"]`

* feat: add consistent-type-imports

* fix: eslint

* chore: add changeset

* refactor: remove unused deps

* ci(changesets): version packages (#5364)

Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>

---------

Co-authored-by: Vishv Salvi <82429084+Vishvsalvi@users.noreply.github.com>
Co-authored-by: Junior Garcia <jrgarciadev@gmail.com>
Co-authored-by: KumJungMin <37934668+KumJungMin@users.noreply.github.com>
Co-authored-by: liaoyinglong <vigossliao@gmail.com>
Co-authored-by: zhengjitf <zhengjitf@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Anuj Kuralkar <76731106+anuj-kuralkar@users.noreply.github.com>
2025-06-16 11:28:11 -03:00

266 lines
7.4 KiB
TypeScript

import type {UserEvent} from "@testing-library/user-event";
import type {CheckboxProps} from "../src";
import * as React from "react";
import {render, renderHook, act} from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import {useForm} from "react-hook-form";
import {Checkbox} from "../src";
describe("Checkbox", () => {
let user: UserEvent;
beforeEach(() => {
user = userEvent.setup();
});
it("should render correctly", () => {
const wrapper = render(<Checkbox>Label</Checkbox>);
expect(() => wrapper.unmount()).not.toThrow();
});
it("ref should be forwarded", () => {
const ref = React.createRef<HTMLInputElement>();
render(<Checkbox ref={ref}>Option</Checkbox>);
expect(ref.current).not.toBeNull();
});
it("should work correctly with initial value", () => {
let {container} = render(<Checkbox isSelected>Option</Checkbox>);
expect(container.querySelector("input")?.checked).toBe(true);
container = render(<Checkbox isSelected={false}>Option</Checkbox>).container;
expect(container.querySelector("input")?.checked).toBe(false);
});
it("should change value after click", async () => {
const wrapper = render(<Checkbox data-testid="checkbox-test">Option</Checkbox>);
const checkbox = wrapper.container.querySelector("input")!;
expect(checkbox.checked).toBe(false);
await user.click(wrapper.getByTestId("checkbox-test"));
expect(checkbox.checked).toBe(true);
});
it("should ignore events when disabled", async () => {
const {container} = render(<Checkbox isDisabled>Option</Checkbox>);
await user.click(container.querySelector("label")!);
expect(container.querySelector("input")?.checked).toBe(false);
});
it("should work correctly with indeterminate value", () => {
const {container} = render(<Checkbox isIndeterminate>Option</Checkbox>);
expect(container.querySelector("input")?.indeterminate).toBe(true);
});
it('should work correctly with "onChange" prop', async () => {
const onChange = jest.fn();
const wrapper = render(
<Checkbox data-testid="checkbox-test" onChange={onChange}>
Option
</Checkbox>,
);
await user.click(wrapper.getByTestId("checkbox-test"));
expect(onChange).toHaveBeenCalled();
});
it('should work correctly with "onFocus" prop', () => {
const onFocus = jest.fn();
const wrapper = render(
<Checkbox data-testid="checkbox-test" onFocus={onFocus}>
Option
</Checkbox>,
);
const input = wrapper.container.querySelector("input")!;
act(() => {
input.focus();
});
expect(onFocus).toHaveBeenCalled();
});
it("should have required attribute when isRequired with native validationBehavior", () => {
const {container} = render(
<Checkbox isRequired validationBehavior="native">
Option
</Checkbox>,
);
expect(container.querySelector("input")).toHaveAttribute("required");
expect(container.querySelector("input")).not.toHaveAttribute("aria-required");
});
it("should have aria-required attribute when isRequired with aria validationBehavior", () => {
const {container} = render(
<Checkbox isRequired validationBehavior="aria">
Option
</Checkbox>,
);
expect(container.querySelector("input")).not.toHaveAttribute("required");
expect(container.querySelector("input")).toHaveAttribute("aria-required", "true");
});
it("should work correctly with controlled value", async () => {
const onChange = jest.fn();
const Component = (props: CheckboxProps) => {
const [value, setValue] = React.useState(false);
return (
<Checkbox
{...props}
isSelected={value}
onValueChange={(checked) => {
act(() => {
setValue(checked);
onChange(checked);
});
}}
/>
);
};
const wrapper = render(
<Component data-testid="checkbox-test" onChange={onChange}>
Option
</Component>,
);
await user.click(wrapper.getByTestId("checkbox-test"));
expect(onChange).toHaveBeenCalled();
});
describe("validation", () => {
describe("validationBehavior=native", () => {
it("supports isRequired", async () => {
const {getByRole, getByTestId} = render(
<form data-testid="form">
<Checkbox isRequired validationBehavior="native">
Terms and conditions
</Checkbox>
</form>,
);
const checkbox = getByRole("checkbox") as HTMLInputElement;
expect(checkbox).toHaveAttribute("required");
expect(checkbox).not.toHaveAttribute("aria-required");
expect(checkbox.validity.valid).toBe(false);
act(() => {
(getByTestId("form") as HTMLFormElement).checkValidity();
});
await user.click(checkbox);
expect(checkbox.validity.valid).toBe(true);
});
});
describe("validationBehavior=aria", () => {
it("supports validate function", async () => {
const {getByRole} = render(
<Checkbox
validate={(v) => (!v ? "You must accept the terms." : null)}
validationBehavior="aria"
value="terms"
>
Terms and conditions
</Checkbox>,
);
const checkbox = getByRole("checkbox") as HTMLInputElement;
expect(checkbox.validity.valid).toBe(true);
await user.click(checkbox);
expect(checkbox.validity.valid).toBe(true);
});
});
});
});
describe("Checkbox with React Hook Form", () => {
let checkbox1: HTMLInputElement;
let checkbox2: HTMLInputElement;
let checkbox3: HTMLInputElement;
let submitButton: HTMLButtonElement;
let onSubmit: () => void;
beforeEach(() => {
const {result} = renderHook(() =>
useForm({
defaultValues: {
withDefaultValue: true,
withoutDefaultValue: false,
requiredField: false,
},
}),
);
const {
handleSubmit,
register,
formState: {errors},
} = result.current;
onSubmit = jest.fn();
render(
<form className="flex flex-col gap-4" onSubmit={handleSubmit(onSubmit)}>
<Checkbox {...register("withDefaultValue")} />
<Checkbox {...register("withoutDefaultValue")} />
<Checkbox {...register("requiredField", {required: true})} />
{errors.requiredField && <span className="text-danger">This field is required</span>}
<button type="submit">Submit</button>
</form>,
);
checkbox1 = document.querySelector("input[name=withDefaultValue]")!;
checkbox2 = document.querySelector("input[name=withoutDefaultValue]")!;
checkbox3 = document.querySelector("input[name=requiredField]")!;
submitButton = document.querySelector("button")!;
});
it("should work with defaultValues", () => {
expect(checkbox1.checked).toBe(true);
expect(checkbox2.checked).toBe(false);
expect(checkbox3.checked).toBe(false);
});
it("should not submit form when required field is empty", async () => {
const user = userEvent.setup();
await user.click(submitButton);
expect(onSubmit).toHaveBeenCalledTimes(0);
});
it("should submit form when required field is not empty", async () => {
const user = userEvent.setup();
await user.click(checkbox3);
expect(checkbox3.checked).toBe(true);
await user.click(submitButton);
expect(onSubmit).toHaveBeenCalledTimes(1);
});
});