Checkbox component with testing and storybook

This commit is contained in:
adilallo
2025-10-08 17:49:13 -06:00
parent 2835fac38b
commit 0b9e918fd0
12 changed files with 6187 additions and 4527 deletions
@@ -0,0 +1,160 @@
import React from "react";
import { render, screen } from "@testing-library/react";
import { expect, test, describe } from "vitest";
import { axe, toHaveNoViolations } from "jest-axe";
import Checkbox from "../../../app/components/Checkbox";
expect.extend(toHaveNoViolations);
describe("Checkbox Accessibility", () => {
test("should not have accessibility violations when unchecked", async () => {
const { container } = render(<Checkbox label="Test checkbox" />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
test("should not have accessibility violations when checked", async () => {
const { container } = render(
<Checkbox label="Test checkbox" checked={true} />
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
test("should not have accessibility violations when disabled", async () => {
const { container } = render(
<Checkbox label="Test checkbox" disabled={true} />
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
test("should not have accessibility violations in inverse mode", async () => {
const { container } = render(
<Checkbox label="Test checkbox" mode="inverse" />
);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
test("should have proper ARIA attributes", () => {
render(<Checkbox label="Test checkbox" checked={true} />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("role", "checkbox");
expect(checkbox).toHaveAttribute("aria-checked", "true");
expect(checkbox).toHaveAttribute("tabIndex", "0");
});
test("should have proper ARIA attributes when disabled", () => {
render(<Checkbox label="Test checkbox" disabled={true} />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("role", "checkbox");
expect(checkbox).toHaveAttribute("aria-checked", "false");
expect(checkbox).toHaveAttribute("aria-disabled", "true");
expect(checkbox).toHaveAttribute("tabIndex", "-1");
});
test("should have proper ARIA attributes when checked", () => {
render(<Checkbox label="Test checkbox" checked={true} />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("role", "checkbox");
expect(checkbox).toHaveAttribute("aria-checked", "true");
expect(checkbox).toHaveAttribute("tabIndex", "0");
});
test("should have proper ARIA attributes when unchecked", () => {
render(<Checkbox label="Test checkbox" checked={false} />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("role", "checkbox");
expect(checkbox).toHaveAttribute("aria-checked", "false");
expect(checkbox).toHaveAttribute("tabIndex", "0");
});
test("should have proper ARIA attributes with custom aria-label", () => {
render(<Checkbox ariaLabel="Custom accessibility label" />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute(
"aria-label",
"Custom accessibility label"
);
});
test("should have proper focus management", () => {
const { rerender } = render(<Checkbox label="Test checkbox" />);
const checkbox = screen.getByRole("checkbox");
// Should be focusable when not disabled
expect(checkbox).toHaveAttribute("tabIndex", "0");
// Should not be focusable when disabled
rerender(
<Checkbox label="Test checkbox disabled" disabled={true} />
);
const disabledCheckbox = screen.getByRole("checkbox");
expect(disabledCheckbox).toHaveAttribute("tabIndex", "-1");
});
test("should have proper keyboard navigation", () => {
render(<Checkbox label="Test checkbox" />);
const checkbox = screen.getByRole("checkbox");
// Should be focusable
expect(checkbox).toHaveAttribute("tabIndex", "0");
// Should support keyboard interaction
expect(checkbox).toHaveAttribute("role", "checkbox");
});
test("should have proper semantic structure", () => {
render(<Checkbox label="Test checkbox" />);
// Should have a label element
const label = screen.getByText("Test checkbox").closest("label");
expect(label).toBeInTheDocument();
// Should have a checkbox role
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toBeInTheDocument();
// Should be associated with the label
expect(label).toContainElement(checkbox);
});
test("should have proper color contrast", async () => {
const { container } = render(<Checkbox label="Test checkbox" />);
const results = await axe(container);
// Check for color contrast violations
const contrastViolations = results.violations.filter(
(violation) => violation.id === "color-contrast"
);
expect(contrastViolations).toHaveLength(0);
});
test("should have proper focus indicators", async () => {
const { container } = render(<Checkbox label="Test checkbox" />);
const results = await axe(container);
// Check for focus indicator violations
const focusViolations = results.violations.filter(
(violation) => violation.id === "focus-order-semantics"
);
expect(focusViolations).toHaveLength(0);
});
test("should have proper form integration", () => {
render(<Checkbox name="test-checkbox" value="test-value" checked={true} />);
// Should have hidden input for form submission
const hiddenInput = screen.getByDisplayValue("test-value");
expect(hiddenInput).toBeInTheDocument();
expect(hiddenInput).toHaveAttribute("type", "checkbox");
expect(hiddenInput).toHaveAttribute("name", "test-checkbox");
expect(hiddenInput).toBeChecked();
});
});
@@ -0,0 +1,249 @@
import React, { useState } from "react";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import { expect, test, describe, vi } from "vitest";
import userEvent from "@testing-library/user-event";
import Checkbox from "../../app/components/Checkbox";
// Test component that uses Checkbox in a form
function TestForm() {
const [formData, setFormData] = useState({
agree: false,
newsletter: false,
notifications: true,
});
const handleCheckboxChange =
(field) =>
({ checked }) => {
setFormData((prev) => ({ ...prev, [field]: checked }));
};
const handleSubmit = (e) => {
e.preventDefault();
// Form submission logic would go here
};
return (
<form onSubmit={handleSubmit} data-testid="test-form">
<Checkbox
label="I agree to the terms"
checked={formData.agree}
onChange={handleCheckboxChange("agree")}
name="agree"
data-testid="agree-checkbox"
/>
<Checkbox
label="Subscribe to newsletter"
checked={formData.newsletter}
onChange={handleCheckboxChange("newsletter")}
name="newsletter"
data-testid="newsletter-checkbox"
/>
<Checkbox
label="Enable notifications"
checked={formData.notifications}
onChange={handleCheckboxChange("notifications")}
name="notifications"
data-testid="notifications-checkbox"
/>
<button type="submit" data-testid="submit-button">
Submit
</button>
</form>
);
}
describe("Checkbox Integration Tests", () => {
test("handles multiple checkboxes in a form", async () => {
const user = userEvent.setup();
render(<TestForm />);
const agreeCheckbox = screen.getByTestId("agree-checkbox");
const newsletterCheckbox = screen.getByTestId("newsletter-checkbox");
const notificationsCheckbox = screen.getByTestId("notifications-checkbox");
// Initial state
expect(agreeCheckbox).toHaveAttribute("aria-checked", "false");
expect(newsletterCheckbox).toHaveAttribute("aria-checked", "false");
expect(notificationsCheckbox).toHaveAttribute("aria-checked", "true");
// Toggle checkboxes
await user.click(agreeCheckbox);
await user.click(newsletterCheckbox);
await user.click(notificationsCheckbox);
// Check final state
expect(agreeCheckbox).toHaveAttribute("aria-checked", "true");
expect(newsletterCheckbox).toHaveAttribute("aria-checked", "true");
expect(notificationsCheckbox).toHaveAttribute("aria-checked", "false");
});
test("handles keyboard navigation between checkboxes", async () => {
const user = userEvent.setup();
render(<TestForm />);
const agreeCheckbox = screen.getByTestId("agree-checkbox");
const newsletterCheckbox = screen.getByTestId("newsletter-checkbox");
const notificationsCheckbox = screen.getByTestId("notifications-checkbox");
// Focus first checkbox
await user.tab();
expect(agreeCheckbox).toHaveFocus();
// Navigate to next checkbox
await user.tab();
expect(newsletterCheckbox).toHaveFocus();
// Navigate to next checkbox
await user.tab();
expect(notificationsCheckbox).toHaveFocus();
});
test("handles keyboard activation", async () => {
const user = userEvent.setup();
render(<TestForm />);
const agreeCheckbox = screen.getByTestId("agree-checkbox");
// Focus and activate with Space
await user.tab();
expect(agreeCheckbox).toHaveFocus();
expect(agreeCheckbox).toHaveAttribute("aria-checked", "false");
await user.keyboard(" ");
expect(agreeCheckbox).toHaveAttribute("aria-checked", "true");
// Activate with Enter
await user.keyboard("Enter");
expect(agreeCheckbox).toHaveAttribute("aria-checked", "true");
});
test("handles mode switching", async () => {
function ModeSwitchForm() {
const [mode, setMode] = useState("standard");
const [checked, setChecked] = useState(false);
return (
<div>
<Checkbox
label="Switch to inverse mode"
checked={mode === "inverse"}
onChange={({ checked }) =>
setMode(checked ? "inverse" : "standard")
}
data-testid="mode-switch"
/>
<Checkbox
label="Test checkbox"
checked={checked}
onChange={({ checked }) => setChecked(checked)}
mode={mode}
data-testid="test-checkbox"
/>
</div>
);
}
const user = userEvent.setup();
render(<ModeSwitchForm />);
const modeSwitch = screen.getByTestId("mode-switch");
const testCheckbox = screen.getByTestId("test-checkbox");
// Initially standard mode
expect(testCheckbox).toBeInTheDocument();
// Switch to inverse mode
await user.click(modeSwitch);
expect(testCheckbox).toBeInTheDocument();
// Should still be functional
await user.click(testCheckbox);
expect(testCheckbox).toHaveAttribute("aria-checked", "true");
});
test("handles form submission with checkbox values", async () => {
const handleSubmit = vi.fn();
function FormWithSubmission() {
const [formData, setFormData] = useState({
agree: false,
newsletter: false,
});
const handleCheckboxChange =
(field) =>
({ checked }) => {
setFormData((prev) => ({ ...prev, [field]: checked }));
};
const onSubmit = (e) => {
e.preventDefault();
handleSubmit(formData);
};
return (
<form onSubmit={onSubmit} data-testid="form">
<Checkbox
label="I agree"
checked={formData.agree}
onChange={handleCheckboxChange("agree")}
name="agree"
value="yes"
data-testid="agree-checkbox"
/>
<Checkbox
label="Newsletter"
checked={formData.newsletter}
onChange={handleCheckboxChange("newsletter")}
name="newsletter"
value="yes"
data-testid="newsletter-checkbox"
/>
<button type="submit" data-testid="submit-button">
Submit
</button>
</form>
);
}
const user = userEvent.setup();
render(<FormWithSubmission />);
const agreeCheckbox = screen.getByTestId("agree-checkbox");
const newsletterCheckbox = screen.getByTestId("newsletter-checkbox");
const submitButton = screen.getByTestId("submit-button");
// Check some checkboxes
await user.click(agreeCheckbox);
await user.click(newsletterCheckbox);
// Submit form
await user.click(submitButton);
// Verify form data was captured
expect(handleSubmit).toHaveBeenCalledWith({
agree: true,
newsletter: true,
});
});
test("handles accessibility in form context", async () => {
render(<TestForm />);
const form = screen.getByTestId("test-form");
const checkboxes = screen.getAllByRole("checkbox");
// All checkboxes should be accessible
expect(checkboxes).toHaveLength(3);
checkboxes.forEach((checkbox) => {
expect(checkbox).toHaveAttribute("role", "checkbox");
expect(checkbox).toHaveAttribute("aria-checked");
expect(checkbox).toHaveAttribute("tabIndex");
});
// Form should be accessible
expect(form).toBeInTheDocument();
});
});
@@ -0,0 +1,136 @@
import { within, userEvent } from "@storybook/test";
import { expect } from "@storybook/test";
// Interaction test for Default story
export const DefaultInteraction = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const checkbox = canvas.getByRole("checkbox");
// Test initial state
expect(checkbox).toHaveAttribute("aria-checked", "false");
// Test click interaction
await userEvent.click(checkbox);
expect(checkbox).toHaveAttribute("aria-checked", "true");
// Test toggle back
await userEvent.click(checkbox);
expect(checkbox).toHaveAttribute("aria-checked", "false");
},
};
// Interaction test for Checked story
export const CheckedInteraction = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const checkbox = canvas.getByRole("checkbox");
// Test initial checked state
expect(checkbox).toHaveAttribute("aria-checked", "true");
// Test unchecking
await userEvent.click(checkbox);
expect(checkbox).toHaveAttribute("aria-checked", "false");
},
};
// Interaction test for Standard story
export const StandardInteraction = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const checkboxes = canvas.getAllByRole("checkbox");
// Test both checkboxes
expect(checkboxes).toHaveLength(2);
// Test first checkbox (unchecked)
expect(checkboxes[0]).toHaveAttribute("aria-checked", "false");
await userEvent.click(checkboxes[0]);
expect(checkboxes[0]).toHaveAttribute("aria-checked", "true");
// Test second checkbox (checked)
expect(checkboxes[1]).toHaveAttribute("aria-checked", "true");
await userEvent.click(checkboxes[1]);
expect(checkboxes[1]).toHaveAttribute("aria-checked", "false");
},
};
// Interaction test for Inverse story
export const InverseInteraction = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const checkboxes = canvas.getAllByRole("checkbox");
// Test both checkboxes in inverse mode
expect(checkboxes).toHaveLength(2);
// Test first checkbox (unchecked)
expect(checkboxes[0]).toHaveAttribute("aria-checked", "false");
await userEvent.click(checkboxes[0]);
expect(checkboxes[0]).toHaveAttribute("aria-checked", "true");
// Test second checkbox (checked)
expect(checkboxes[1]).toHaveAttribute("aria-checked", "true");
await userEvent.click(checkboxes[1]);
expect(checkboxes[1]).toHaveAttribute("aria-checked", "false");
},
};
// Keyboard interaction test
export const KeyboardInteraction = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const checkbox = canvas.getByRole("checkbox");
// Focus the checkbox
await userEvent.tab();
expect(checkbox).toHaveFocus();
// Test Space key
await userEvent.keyboard(" ");
expect(checkbox).toHaveAttribute("aria-checked", "true");
// Test Enter key
await userEvent.keyboard("Enter");
expect(checkbox).toHaveAttribute("aria-checked", "false");
},
};
// Accessibility interaction test
export const AccessibilityInteraction = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const checkbox = canvas.getByRole("checkbox");
// Test ARIA attributes
expect(checkbox).toHaveAttribute("role", "checkbox");
expect(checkbox).toHaveAttribute("aria-checked");
expect(checkbox).toHaveAttribute("tabIndex");
// Test keyboard navigation
await userEvent.tab();
expect(checkbox).toHaveFocus();
// Test activation
await userEvent.keyboard(" ");
expect(checkbox).toHaveAttribute("aria-checked", "true");
},
};
// Form integration test
export const FormIntegration = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const checkbox = canvas.getByRole("checkbox");
// Test form integration
const hiddenInput = canvas.getByRole("checkbox", { hidden: true });
expect(hiddenInput).toBeInTheDocument();
// Test checkbox interaction
await userEvent.click(checkbox);
expect(checkbox).toHaveAttribute("aria-checked", "true");
expect(hiddenInput).toBeChecked();
},
};
+234
View File
@@ -0,0 +1,234 @@
import { test, expect } from "@playwright/test";
test.describe("Checkbox Storybook Tests", () => {
test.beforeEach(async ({ page }) => {
await page.goto("http://localhost:6006");
});
test("should load Checkbox stories", async ({ page }) => {
// Navigate to Checkbox stories
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
// Check that the stories are loaded
await expect(page.locator('[data-testid="Default"]')).toBeVisible();
await expect(page.locator('[data-testid="Checked"]')).toBeVisible();
await expect(page.locator('[data-testid="Standard"]')).toBeVisible();
await expect(page.locator('[data-testid="Inverse"]')).toBeVisible();
});
test("Default story should render correctly", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
// Check that the checkbox is rendered
const checkbox = page.locator('[role="checkbox"]').first();
await expect(checkbox).toBeVisible();
await expect(checkbox).toHaveAttribute("aria-checked", "false");
});
test("Checked story should render correctly", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Checked"]');
// Check that the checkbox is checked
const checkbox = page.locator('[role="checkbox"]').first();
await expect(checkbox).toBeVisible();
await expect(checkbox).toHaveAttribute("aria-checked", "true");
});
test("Standard story should show standard mode checkboxes", async ({
page,
}) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Standard"]');
// Check that multiple checkboxes are rendered
const checkboxes = page.locator('[role="checkbox"]');
await expect(checkboxes).toHaveCount(2); // Unchecked and checked
// Check that they have proper styling (standard mode)
const firstCheckbox = checkboxes.first();
await expect(firstCheckbox).toBeVisible();
});
test("Inverse story should show inverse mode checkboxes", async ({
page,
}) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Inverse"]');
// Check that multiple checkboxes are rendered
const checkboxes = page.locator('[role="checkbox"]');
await expect(checkboxes).toHaveCount(2); // Unchecked and checked
// Check that they have proper styling (inverse mode)
const firstCheckbox = checkboxes.first();
await expect(firstCheckbox).toBeVisible();
});
test("should have proper controls in Controls panel", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
// Check that controls are available
await expect(page.locator('[data-testid="control-checked"]')).toBeVisible();
await expect(page.locator('[data-testid="control-mode"]')).toBeVisible();
await expect(page.locator('[data-testid="control-state"]')).toBeVisible();
await expect(
page.locator('[data-testid="control-disabled"]')
).toBeVisible();
await expect(page.locator('[data-testid="control-label"]')).toBeVisible();
});
test("should update when controls are changed", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
// Toggle checked control
await page.click('[data-testid="control-checked"]');
// Check that the checkbox is now checked
const checkbox = page.locator('[role="checkbox"]').first();
await expect(checkbox).toHaveAttribute("aria-checked", "true");
// Toggle back
await page.click('[data-testid="control-checked"]');
await expect(checkbox).toHaveAttribute("aria-checked", "false");
});
test("should change mode when mode control is changed", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
// Change mode to inverse
await page.selectOption('[data-testid="control-mode"]', "inverse");
// Check that the checkbox styling has changed (inverse mode)
const checkbox = page.locator('[role="checkbox"]').first();
await expect(checkbox).toBeVisible();
// Change back to standard
await page.selectOption('[data-testid="control-mode"]', "standard");
await expect(checkbox).toBeVisible();
});
test("should show disabled state when disabled control is toggled", async ({
page,
}) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
// Toggle disabled control
await page.click('[data-testid="control-disabled"]');
// Check that the checkbox is now disabled
const checkbox = page.locator('[role="checkbox"]').first();
await expect(checkbox).toHaveAttribute("aria-disabled", "true");
await expect(checkbox).toHaveAttribute("tabIndex", "-1");
// Toggle back
await page.click('[data-testid="control-disabled"]');
await expect(checkbox).toHaveAttribute("aria-disabled", "false");
await expect(checkbox).toHaveAttribute("tabIndex", "0");
});
test("should update label when label control is changed", async ({
page,
}) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
// Change label
await page.fill('[data-testid="control-label"]', "Custom Label");
// Check that the label has updated
await expect(page.locator("text=Custom Label")).toBeVisible();
});
test("should have proper accessibility in Storybook", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
// Check accessibility attributes
const checkbox = page.locator('[role="checkbox"]').first();
await expect(checkbox).toHaveAttribute("role", "checkbox");
await expect(checkbox).toHaveAttribute("aria-checked");
await expect(checkbox).toHaveAttribute("tabIndex");
});
test("should support keyboard navigation in Storybook", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
const checkbox = page.locator('[role="checkbox"]').first();
// Focus the checkbox
await checkbox.focus();
await expect(checkbox).toBeFocused();
// Test keyboard activation
await checkbox.press(" ");
await expect(checkbox).toHaveAttribute("aria-checked", "true");
await checkbox.press(" ");
await expect(checkbox).toHaveAttribute("aria-checked", "false");
});
test("should show proper documentation", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
// Check that documentation is available
await expect(page.locator('[data-testid="docs-tab"]')).toBeVisible();
// Click on docs tab
await page.click('[data-testid="docs-tab"]');
// Check that documentation content is shown
await expect(page.locator("text=Checkbox")).toBeVisible();
await expect(page.locator("text=Props")).toBeVisible();
});
test("should have proper story navigation", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
// Test navigation between stories
const stories = ["Default", "Checked", "Standard", "Inverse"];
for (const story of stories) {
await page.click(`[data-testid="${story}"]`);
await expect(page.locator('[role="checkbox"]').first()).toBeVisible();
}
});
test("should maintain state between story switches", async ({ page }) => {
await page.click('[data-testid="Forms"]');
await page.click('[data-testid="Checkbox"]');
await page.click('[data-testid="Default"]');
// Interact with checkbox
const checkbox = page.locator('[role="checkbox"]').first();
await checkbox.click();
await expect(checkbox).toHaveAttribute("aria-checked", "true");
// Switch to another story and back
await page.click('[data-testid="Checked"]');
await page.click('[data-testid="Default"]');
// Check that the state is maintained
await expect(checkbox).toHaveAttribute("aria-checked", "true");
});
});
+166
View File
@@ -0,0 +1,166 @@
import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import { expect, test, describe, vi } from "vitest";
import Checkbox from "../../app/components/Checkbox";
describe("Checkbox Component", () => {
test("renders with default props", () => {
render(<Checkbox />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toBeInTheDocument();
expect(checkbox).toHaveAttribute("aria-checked", "false");
});
test("renders with label", () => {
render(<Checkbox label="Test checkbox" />);
expect(screen.getByText("Test checkbox")).toBeInTheDocument();
});
test("renders as checked when checked prop is true", () => {
render(<Checkbox checked={true} />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("aria-checked", "true");
});
test("renders as unchecked when checked prop is false", () => {
render(<Checkbox checked={false} />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("aria-checked", "false");
});
test("calls onChange when clicked", () => {
const handleChange = vi.fn();
render(<Checkbox onChange={handleChange} />);
const checkbox = screen.getByRole("checkbox");
fireEvent.click(checkbox);
expect(handleChange).toHaveBeenCalledWith({
checked: true,
value: undefined,
event: expect.any(Object),
});
});
test("calls onChange when toggled from checked to unchecked", () => {
const handleChange = vi.fn();
render(<Checkbox checked={true} onChange={handleChange} />);
const checkbox = screen.getByRole("checkbox");
fireEvent.click(checkbox);
expect(handleChange).toHaveBeenCalledWith({
checked: false,
value: undefined,
event: expect.any(Object),
});
});
test("handles keyboard navigation", () => {
const handleChange = vi.fn();
render(<Checkbox onChange={handleChange} />);
const checkbox = screen.getByRole("checkbox");
// Test Space key
fireEvent.keyDown(checkbox, { key: " " });
expect(handleChange).toHaveBeenCalledWith({
checked: true,
value: undefined,
event: expect.any(Object),
});
// Test Enter key
fireEvent.keyDown(checkbox, { key: "Enter" });
expect(handleChange).toHaveBeenCalledTimes(2);
});
test("does not call onChange when disabled", () => {
const handleChange = vi.fn();
render(<Checkbox disabled={true} onChange={handleChange} />);
const checkbox = screen.getByRole("checkbox");
fireEvent.click(checkbox);
expect(handleChange).not.toHaveBeenCalled();
});
test("applies disabled attributes when disabled", () => {
render(<Checkbox disabled={true} />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("aria-disabled", "true");
expect(checkbox).toHaveAttribute("tabIndex", "-1");
});
test("applies correct tabIndex when not disabled", () => {
render(<Checkbox />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("tabIndex", "0");
});
test("renders with standard mode by default", () => {
render(<Checkbox />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toBeInTheDocument();
});
test("renders with inverse mode", () => {
render(<Checkbox mode="inverse" />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toBeInTheDocument();
});
test("applies custom className", () => {
render(<Checkbox className="custom-class" />);
const label = screen.getByRole("checkbox").closest("label");
expect(label).toHaveClass("custom-class");
});
test("passes through additional props", () => {
render(<Checkbox id="test-checkbox" name="test" value="test-value" />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("id", "test-checkbox");
});
test("renders hidden native input for form compatibility", () => {
render(<Checkbox name="test" value="test-value" checked={true} />);
const hiddenInput = screen.getByDisplayValue("test-value");
expect(hiddenInput).toBeInTheDocument();
expect(hiddenInput).toHaveAttribute("type", "checkbox");
expect(hiddenInput).toHaveAttribute("name", "test");
expect(hiddenInput).toBeChecked();
});
test("applies aria-label when provided", () => {
render(<Checkbox ariaLabel="Custom label" />);
const checkbox = screen.getByRole("checkbox");
expect(checkbox).toHaveAttribute("aria-label", "Custom label");
});
test("prevents default on mouse down", () => {
render(<Checkbox />);
const label = screen.getByRole("checkbox").closest("label");
const mouseDownEvent = new MouseEvent("mousedown", { bubbles: true });
const preventDefaultSpy = vi.spyOn(mouseDownEvent, "preventDefault");
fireEvent(label, mouseDownEvent);
expect(preventDefaultSpy).toHaveBeenCalled();
});
test("renders checkmark SVG when checked", () => {
render(<Checkbox checked={true} />);
const svg = screen.getByRole("checkbox").querySelector("svg");
expect(svg).toBeInTheDocument();
expect(svg).toHaveAttribute("aria-hidden", "true");
expect(svg).toHaveAttribute("focusable", "false");
});
test("does not render checkmark SVG when unchecked", () => {
render(<Checkbox checked={false} />);
const svg = screen.getByRole("checkbox").querySelector("svg");
expect(svg).toBeInTheDocument();
// SVG should be present but checkmark should be transparent
const path = svg.querySelector("polyline");
expect(path).toHaveAttribute("stroke", "transparent");
});
});
+83
View File
@@ -0,0 +1,83 @@
import { test, expect } from "@playwright/test";
test.describe("Checkbox Visual Regression Tests", () => {
test("Standard mode - unchecked", async ({ page }) => {
await page.goto("/forms");
await expect(
page.locator('[data-testid="standard-unchecked"]')
).toBeVisible();
await expect(page).toHaveScreenshot("checkbox-standard-unchecked.png");
});
test("Standard mode - checked", async ({ page }) => {
await page.goto("/forms");
await expect(
page.locator('[data-testid="standard-checked"]')
).toBeVisible();
await expect(page).toHaveScreenshot("checkbox-standard-checked.png");
});
test("Inverse mode - unchecked", async ({ page }) => {
await page.goto("/forms");
await expect(
page.locator('[data-testid="inverse-unchecked"]')
).toBeVisible();
await expect(page).toHaveScreenshot("checkbox-inverse-unchecked.png");
});
test("Inverse mode - checked", async ({ page }) => {
await page.goto("/forms");
await expect(page.locator('[data-testid="inverse-checked"]')).toBeVisible();
await expect(page).toHaveScreenshot("checkbox-inverse-checked.png");
});
test("Standard mode - hover state", async ({ page }) => {
await page.goto("/forms");
const checkbox = page.locator('[data-testid="standard-unchecked"]');
await checkbox.hover();
await expect(page).toHaveScreenshot("checkbox-standard-hover.png");
});
test("Standard mode - focus state", async ({ page }) => {
await page.goto("/forms");
const checkbox = page.locator('[data-testid="standard-unchecked"]');
await checkbox.focus();
await expect(page).toHaveScreenshot("checkbox-standard-focus.png");
});
test("Inverse mode - hover state", async ({ page }) => {
await page.goto("/forms");
const checkbox = page.locator('[data-testid="inverse-unchecked"]');
await checkbox.hover();
await expect(page).toHaveScreenshot("checkbox-inverse-hover.png");
});
test("Inverse mode - focus state", async ({ page }) => {
await page.goto("/forms");
const checkbox = page.locator('[data-testid="inverse-unchecked"]');
await checkbox.focus();
await expect(page).toHaveScreenshot("checkbox-inverse-focus.png");
});
test("Disabled state - standard", async ({ page }) => {
await page.goto("/forms");
await expect(
page.locator('[data-testid="standard-disabled"]')
).toBeVisible();
await expect(page).toHaveScreenshot("checkbox-standard-disabled.png");
});
test("Disabled state - inverse", async ({ page }) => {
await page.goto("/forms");
await expect(
page.locator('[data-testid="inverse-disabled"]')
).toBeVisible();
await expect(page).toHaveScreenshot("checkbox-inverse-disabled.png");
});
test("All variations grid", async ({ page }) => {
await page.goto("/forms");
await expect(page.locator('[data-testid="checkbox-grid"]')).toBeVisible();
await expect(page).toHaveScreenshot("checkbox-all-variations.png");
});
});