From 9de194bfc011a8fbc7362b4f8ebd912a18dd3f12 Mon Sep 17 00:00:00 2001 From: adilallo <39313955+adilallo@users.noreply.github.com> Date: Tue, 14 Oct 2025 17:27:09 -0600 Subject: [PATCH] Switch component with storybook and testing --- .storybook/fonts.css | 7 + .storybook/preview.js | 3 +- app/components/Switch.js | 163 +++++++++ app/forms/page.js | 322 ++++-------------- stories/Switch.stories.js | 128 +++++++ tests/accessibility/Switch.a11y.test.jsx | 98 ++++++ tests/integration/Switch.integration.test.jsx | 265 ++++++++++++++ tests/unit/Switch.test.jsx | 184 ++++++++++ 8 files changed, 908 insertions(+), 262 deletions(-) create mode 100644 .storybook/fonts.css create mode 100644 app/components/Switch.js create mode 100644 stories/Switch.stories.js create mode 100644 tests/accessibility/Switch.a11y.test.jsx create mode 100644 tests/integration/Switch.integration.test.jsx create mode 100644 tests/unit/Switch.test.jsx diff --git a/.storybook/fonts.css b/.storybook/fonts.css new file mode 100644 index 0000000..7f3782b --- /dev/null +++ b/.storybook/fonts.css @@ -0,0 +1,7 @@ +@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"); + +:root { + --font-inter: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", + Roboto, "Helvetica Neue", Arial, "Noto Sans", "Apple Color Emoji", + "Segoe UI Emoji"; +} diff --git a/.storybook/preview.js b/.storybook/preview.js index 0b1f78a..aadfe40 100644 --- a/.storybook/preview.js +++ b/.storybook/preview.js @@ -1,4 +1,5 @@ import "../app/globals.css"; +import "./fonts.css"; /** @type { import('@storybook/react').Preview } */ const preview = { @@ -12,7 +13,7 @@ const preview = { }, decorators: [ (Story) => ( -
+
), diff --git a/app/components/Switch.js b/app/components/Switch.js new file mode 100644 index 0000000..e12fae0 --- /dev/null +++ b/app/components/Switch.js @@ -0,0 +1,163 @@ +import React, { memo, useCallback, useId, forwardRef } from "react"; + +const Switch = memo( + forwardRef((props, ref) => { + const { + checked = false, + onChange, + onFocus, + onBlur, + state = "default", + label, + className = "", + ...rest + } = props; + + const switchId = useId(); + + const handleClick = useCallback( + (e) => { + if (onChange) { + onChange(e); + } + }, + [onChange] + ); + + const handleKeyDown = useCallback( + (e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + if (onChange) { + onChange(e); + } + } + }, + [onChange] + ); + + const handleFocus = useCallback( + (e) => { + if (onFocus) { + onFocus(e); + } + }, + [onFocus] + ); + + const handleBlur = useCallback( + (e) => { + if (onBlur) { + onBlur(e); + } + }, + [onBlur] + ); + + // Switch track styles based on checked state + const getTrackStyles = useCallback(() => { + return checked + ? "bg-[var(--color-surface-inverse-tertiary)]" + : "bg-[var(--color-surface-default-tertiary)]"; + }, [checked]); + + // Switch thumb styles based on checked state + const getThumbStyles = useCallback(() => { + return "bg-[var(--color-gray-000)]"; + }, []); + + // Focus styles + const getFocusStyles = useCallback(() => { + if (state === "focus") { + return "shadow-[0_0_5px_3px_#3281F8] rounded-full"; + } + return ""; + }, [state]); + + const trackStyles = getTrackStyles(); + const thumbStyles = getThumbStyles(); + const focusStyles = getFocusStyles(); + + const switchClasses = ` + relative + inline-flex + items-center + cursor-pointer + transition-all + duration-200 + focus:outline-none + focus-visible:shadow-[0_0_5px_3px_#3281F8] + focus-visible:rounded-full + ${focusStyles} + ${className} + ` + .trim() + .replace(/\s+/g, " "); + + const trackClasses = ` + ${trackStyles} + w-[40px] + h-[24px] + rounded-full + transition-all + duration-200 + flex + items-center + ${checked ? "justify-end" : "justify-start"} + p-[2px] + ` + .trim() + .replace(/\s+/g, " "); + + const thumbClasses = ` + ${thumbStyles} + w-[var(--measures-sizing-020)] + h-[var(--measures-sizing-020)] + rounded-[var(--measures-radius-xlarge)] + transition-all + duration-200 + shadow-sm + ` + .trim() + .replace(/\s+/g, " "); + + const labelClasses = ` + ml-[var(--measures-spacing-008)] + font-inter + font-normal + text-[14px] + leading-[20px] + text-[var(--color-content-default-primary)] + ` + .trim() + .replace(/\s+/g, " "); + + return ( +
+ + {label && {label}} +
+ ); + }) +); + +Switch.displayName = "Switch"; + +export default Switch; diff --git a/app/forms/page.js b/app/forms/page.js index 7b154a5..766e565 100644 --- a/app/forms/page.js +++ b/app/forms/page.js @@ -1,286 +1,86 @@ "use client"; import React, { useState } from "react"; -import ToggleGroup from "../components/ToggleGroup"; +import Switch from "../components/Switch"; export default function FormsPlayground() { - const [selectedToggle, setSelectedToggle] = useState("active"); - const [selectedFilter, setSelectedFilter] = useState("all"); - const [toggleStates, setToggleStates] = useState({ - default: false, - hover: false, - selected: true, - focus: false, + const [switchStates, setSwitchStates] = useState({ + switch1: false, + switch2: true, + switch3: false, + switch4: true, }); - const handleToggleChange = (key) => (e) => { - setToggleStates((prev) => ({ + const handleSwitchChange = (switchName) => { + setSwitchStates((prev) => ({ ...prev, - [key]: !prev[key], + [switchName]: !prev[switchName], })); }; - const handleToggleGroupChange = (position) => (e) => { - setSelectedToggle(position); - }; - - const handleFilterChange = (filter) => (e) => { - setSelectedFilter(filter); - }; - return (

Forms Playground

-

Toggle Group Examples

+

Switch Examples

+
+

Switch States

+
+ handleSwitchChange("switch1")} + label="Switch label" + /> + handleSwitchChange("switch2")} + label="Switch label" + /> + handleSwitchChange("switch3")} + state="focus" + label="Switch label" + /> + handleSwitchChange("switch4")} + state="focus" + label="Switch label" + /> +
+
+

- Interactive Toggle Group + Interactive Example

-
- - Active Deals - - - Inactive Deals - - - Pending Deals - -
-
- -
-

States

-
- - Default - - - Hover - - - Focus - - - Selected - -
-
- -
-

Positions

-
- - Left - - - Middle - - - Middle - - - Right - -
-
- -
-

Without Text

-
- - Icon - - - Icon - - - Icon - -
-
-
-
- - {/* Content Visibility Examples */} -
-

Content Visibility Examples

- - {/* Deal Management Example */} -
-

Deal Management

-
- - Active Deals - - - Inactive Deals - - - Pending Deals - -
- - {/* Content that changes based on toggle selection */} -
- {selectedToggle === "active" && ( -
-

- Active Deals -

-
    -
  • - Summer Sale - 50% Off - $299 -
  • -
  • - Black Friday Special - $199 -
  • -
-
- )} - - {selectedToggle === "inactive" && ( -
-

- Inactive Deals -

-
    -
  • - Holiday Sale - Expired - $399 -
  • -
  • - Spring Clearance - Ended - $149 -
  • -
-
- )} - - {selectedToggle === "pending" && ( -
-

- Pending Deals -

-
    -
  • - Cyber Monday - Coming Soon - $99 -
  • -
  • - New Year Sale - Pending - $79 -
  • -
-
- )} -
-
- - {/* Filter Example */} -
-

Content Filter

-
- - All - - - Featured - - - Recent - -
- -
-
-

Featured Article

-

- This is a featured article that shows when "All" or "Featured" - is selected. -

-
-
-

Recent Post

-

- This is a recent post that shows when "All" or "Recent" is - selected. -

-
-
-

General Content

-

- This content only shows when "All" is selected. -

+
+ handleSwitchChange("switch1")} + label="Enable notifications" + /> + handleSwitchChange("switch2")} + label="Auto-save documents" + /> + handleSwitchChange("switch3")} + label="Dark mode" + /> + handleSwitchChange("switch4")} + label="Email updates" + />
diff --git a/stories/Switch.stories.js b/stories/Switch.stories.js new file mode 100644 index 0000000..8dd184c --- /dev/null +++ b/stories/Switch.stories.js @@ -0,0 +1,128 @@ +import React from "react"; +import Switch from "../app/components/Switch"; + +export default { + title: "Forms/Switch", + component: Switch, + parameters: { + layout: "centered", + }, + argTypes: { + checked: { + control: "boolean", + description: "Whether the switch is checked (on) or not (off)", + }, + state: { + control: "select", + options: ["default", "focus"], + description: "Visual state of the switch", + }, + label: { + control: "text", + description: "Label text displayed next to the switch", + }, + onChange: { + action: "changed", + description: "Callback fired when the switch is toggled", + }, + onFocus: { + action: "focused", + description: "Callback fired when the switch receives focus", + }, + onBlur: { + action: "blurred", + description: "Callback fired when the switch loses focus", + }, + }, +}; + +const Template = (args) => ; + +export const Default = Template.bind({}); +Default.args = { + checked: false, + label: "Switch label", +}; + +export const Checked = Template.bind({}); +Checked.args = { + checked: true, + label: "Switch label", +}; + +export const Focus = Template.bind({}); +Focus.args = { + checked: false, + state: "focus", + label: "Switch label", +}; + +export const FocusChecked = Template.bind({}); +FocusChecked.args = { + checked: true, + state: "focus", + label: "Switch label", +}; + +export const States = () => ( +
+
+

Switch States

+
+ + + + +
+
+
+); + +export const Interactive = () => { + const [checked, setChecked] = React.useState(false); + const [state, setState] = React.useState("default"); + + return ( +
+
+

Interactive Switch

+ setChecked(!checked)} + label="Enable notifications" + /> +
+
+

Controls

+
+
+ + +
+
+
+
+ ); +}; + +export const WithText = () => ( +
+
+

Switch with Different Labels

+
+ + + + +
+
+
+); diff --git a/tests/accessibility/Switch.a11y.test.jsx b/tests/accessibility/Switch.a11y.test.jsx new file mode 100644 index 0000000..ad73576 --- /dev/null +++ b/tests/accessibility/Switch.a11y.test.jsx @@ -0,0 +1,98 @@ +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, vi } from "vitest"; +import { axe, toHaveNoViolations } from "jest-axe"; +import Switch from "../../app/components/Switch"; + +expect.extend(toHaveNoViolations); + +describe("Switch Accessibility", () => { + it("has proper ARIA attributes", () => { + render(); + const switchButton = screen.getByRole("switch"); + + expect(switchButton).toHaveAttribute("role", "switch"); + expect(switchButton).toHaveAttribute("aria-checked", "false"); + expect(switchButton).toHaveAttribute("aria-label", "Test Switch"); + }); + + it("has proper ARIA attributes when checked", () => { + render(); + const switchButton = screen.getByRole("switch"); + + expect(switchButton).toHaveAttribute("aria-checked", "true"); + }); + + it("has proper ARIA attributes when focused", () => { + render(); + const switchButton = screen.getByRole("switch"); + + expect(switchButton).toHaveAttribute("aria-checked", "false"); + expect(switchButton).toHaveClass("shadow-[0_0_5px_3px_#3281F8]"); + expect(switchButton).toHaveClass("rounded-full"); + expect(switchButton).toHaveAttribute("aria-label", "Test Switch"); + }); + + it("handles keyboard navigation", () => { + const handleChange = vi.fn(); + render(); + const switchButton = screen.getByRole("switch"); + + // Test Enter key + fireEvent.keyDown(switchButton, { key: "Enter" }); + expect(handleChange).toHaveBeenCalledTimes(1); + + // Test Space key + fireEvent.keyDown(switchButton, { key: " " }); + expect(handleChange).toHaveBeenCalledTimes(2); + }); + + it("handles focus state accessibility", () => { + const handleFocus = vi.fn(); + render(); + const switchButton = screen.getByRole("switch"); + + fireEvent.focus(switchButton); + expect(handleFocus).toHaveBeenCalledTimes(1); + }); + + it("handles checked state accessibility", () => { + const { rerender } = render(); + let switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveAttribute("aria-checked", "false"); + + rerender(); + switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveAttribute("aria-checked", "true"); + }); + + it("has no accessibility violations", async () => { + const { container } = render(); + const results = await axe(container); + expect(results).toHaveNoViolations(); + }); + + it("has no accessibility violations when checked", async () => { + const { container } = render(); + const results = await axe(container); + expect(results).toHaveNoViolations(); + }); + + it("has no accessibility violations when focused", async () => { + const { container } = render(); + const results = await axe(container); + expect(results).toHaveNoViolations(); + }); + + it("has no accessibility violations with text", async () => { + const { container } = render(); + const results = await axe(container); + expect(results).toHaveNoViolations(); + }); + + it("has no accessibility violations without text", async () => { + const { container } = render(); + const results = await axe(container); + expect(results).toHaveNoViolations(); + }); +}); diff --git a/tests/integration/Switch.integration.test.jsx b/tests/integration/Switch.integration.test.jsx new file mode 100644 index 0000000..d538e6b --- /dev/null +++ b/tests/integration/Switch.integration.test.jsx @@ -0,0 +1,265 @@ +import React from "react"; +import { render, screen, fireEvent, waitFor } from "@testing-library/react"; +import { describe, it, expect, vi } from "vitest"; +import userEvent from "@testing-library/user-event"; +import Switch from "../../app/components/Switch"; + +// Test form component +const TestForm = ({ onSubmit }) => { + const [switch1, setSwitch1] = React.useState(false); + const [switch2, setSwitch2] = React.useState(true); + + const handleSubmit = (e) => { + e.preventDefault(); + onSubmit({ switch1, switch2 }); + }; + + return ( +
+ setSwitch1(!switch1)} + label="First Switch" + /> + setSwitch2(!switch2)} + label="Second Switch" + /> + + + ); +}; + +// Dynamic switch component +const DynamicSwitch = ({ initialState = false }) => { + const [checked, setChecked] = React.useState(initialState); + + // Update state when initialState prop changes + React.useEffect(() => { + setChecked(initialState); + }, [initialState]); + + return ( +
+ setChecked(!checked)} + label="Dynamic Switch" + /> +
+ ); +}; + +describe("Switch Integration", () => { + it("handles form submission", async () => { + const user = userEvent.setup(); + const handleSubmit = vi.fn(); + + render(); + + const submitButton = screen.getByRole("button", { name: "Submit" }); + await user.click(submitButton); + + expect(handleSubmit).toHaveBeenCalledWith({ + switch1: false, + switch2: true, + }); + }); + + it("handles keyboard navigation between switches", async () => { + const user = userEvent.setup(); + render( +
+ + + +
+ ); + + const switches = screen.getAllByRole("switch"); + expect(switches).toHaveLength(3); + + // Focus first switch + await user.tab(); + expect(switches[0]).toHaveFocus(); + + // Tab to second switch + await user.tab(); + expect(switches[1]).toHaveFocus(); + + // Tab to third switch + await user.tab(); + expect(switches[2]).toHaveFocus(); + }); + + it("handles dynamic prop changes", () => { + const { rerender } = render(); + + let switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveAttribute("aria-checked", "false"); + + // Change initial state - the DynamicSwitch component should handle this internally + rerender(); + switchButton = screen.getByRole("switch"); + // The DynamicSwitch component manages its own state, so it should be checked + expect(switchButton).toHaveAttribute("aria-checked", "true"); + }); + + it("handles multiple switches in form", async () => { + const user = userEvent.setup(); + const handleSubmit = vi.fn(); + + const TestForm = () => { + const [switch1, setSwitch1] = React.useState(false); + const [switch2, setSwitch2] = React.useState(false); + const [switch3, setSwitch3] = React.useState(false); + + return ( +
{ + e.preventDefault(); + handleSubmit(); + }} + > + setSwitch1(!switch1)} + /> + setSwitch2(!switch2)} + /> + setSwitch3(!switch3)} + /> + + + ); + }; + + render(); + + const switches = screen.getAllByRole("switch"); + expect(switches).toHaveLength(3); + + // Toggle first switch + await user.click(switches[0]); + expect(switches[0]).toHaveAttribute("aria-checked", "true"); + + // Toggle second switch + await user.click(switches[1]); + expect(switches[1]).toHaveAttribute("aria-checked", "true"); + + // Submit form + const submitButton = screen.getByRole("button", { name: "Submit" }); + await user.click(submitButton); + expect(handleSubmit).toHaveBeenCalled(); + }); + + it("handles state changes", async () => { + const user = userEvent.setup(); + const TestComponent = () => { + const [checked, setChecked] = React.useState(false); + + return ( +
+ setChecked(!checked)} + label="Test Switch" + /> +
+ ); + }; + + render(); + + const switchButton = screen.getByRole("switch"); + + // Initially unchecked + expect(switchButton).toHaveAttribute("aria-checked", "false"); + + // Toggle checked state + await user.click(switchButton); + expect(switchButton).toHaveAttribute("aria-checked", "true"); + }); + + it("handles content changes", () => { + const { rerender } = render(); + expect(screen.getByText("Original Label")).toBeInTheDocument(); + + rerender(); + expect(screen.getByText("Updated Label")).toBeInTheDocument(); + expect(screen.queryByText("Original Label")).not.toBeInTheDocument(); + }); + + it("handles performance with many switches", () => { + const switches = Array.from({ length: 100 }, (_, i) => ( + + )); + + const startTime = performance.now(); + render(
{switches}
); + const endTime = performance.now(); + + // Should render within reasonable time (less than 1 second) + expect(endTime - startTime).toBeLessThan(1000); + + const renderedSwitches = screen.getAllByRole("switch"); + expect(renderedSwitches).toHaveLength(100); + }); + + it("handles rapid state changes", async () => { + const user = userEvent.setup(); + const TestComponent = () => { + const [checked, setChecked] = React.useState(false); + + return ( + setChecked(!checked)} + label="Rapid Toggle Switch" + /> + ); + }; + + render(); + + const switchButton = screen.getByRole("switch"); + + // Rapidly toggle the switch + for (let i = 0; i < 10; i++) { + await user.click(switchButton); + await waitFor(() => { + expect(switchButton).toHaveAttribute( + "aria-checked", + i % 2 === 0 ? "true" : "false" + ); + }); + } + }); + + it("handles mixed content types", () => { + render( +
+ + + + +
+ ); + + const switches = screen.getAllByRole("switch"); + expect(switches).toHaveLength(4); + + // Check that labels are rendered correctly + expect(screen.getByText("Text Switch")).toBeInTheDocument(); + expect(screen.getByText("Another Text Switch")).toBeInTheDocument(); + expect(screen.getByText("Final Switch")).toBeInTheDocument(); + }); +}); diff --git a/tests/unit/Switch.test.jsx b/tests/unit/Switch.test.jsx new file mode 100644 index 0000000..3fbd348 --- /dev/null +++ b/tests/unit/Switch.test.jsx @@ -0,0 +1,184 @@ +import React from "react"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { describe, it, expect, vi } from "vitest"; +import Switch from "../../app/components/Switch"; + +describe("Switch Component", () => { + it("renders with default props", () => { + render(); + const switchButton = screen.getByRole("switch"); + expect(switchButton).toBeInTheDocument(); + expect(switchButton).toHaveAttribute("aria-checked", "false"); + }); + + it("renders with custom props", () => { + const handleChange = vi.fn(); + render( + + ); + + const switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveAttribute("aria-checked", "true"); + expect(screen.getByText("Test Switch")).toBeInTheDocument(); + }); + + it("handles checked prop correctly", () => { + const { rerender } = render(); + let switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveAttribute("aria-checked", "false"); + + rerender(); + switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveAttribute("aria-checked", "true"); + }); + + it("handles state prop correctly", () => { + const { rerender } = render(); + let switchButton = screen.getByRole("switch"); + expect(switchButton).not.toHaveClass("shadow-[0_0_5px_1px_#3281F8]"); + + rerender(); + switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveClass("shadow-[0_0_5px_3px_#3281F8]"); + }); + + it("calls onChange when clicked", () => { + const handleChange = vi.fn(); + render(); + + const switchButton = screen.getByRole("switch"); + fireEvent.click(switchButton); + expect(handleChange).toHaveBeenCalledTimes(1); + }); + + it("calls onFocus when focused", () => { + const handleFocus = vi.fn(); + render(); + + const switchButton = screen.getByRole("switch"); + fireEvent.focus(switchButton); + expect(handleFocus).toHaveBeenCalledTimes(1); + }); + + it("calls onBlur when blurred", () => { + const handleBlur = vi.fn(); + render(); + + const switchButton = screen.getByRole("switch"); + fireEvent.blur(switchButton); + expect(handleBlur).toHaveBeenCalledTimes(1); + }); + + it("handles keyboard events correctly", () => { + const handleChange = vi.fn(); + render(); + + const switchButton = screen.getByRole("switch"); + + // Test Enter key + fireEvent.keyDown(switchButton, { key: "Enter" }); + expect(handleChange).toHaveBeenCalledTimes(1); + + // Test Space key + fireEvent.keyDown(switchButton, { key: " " }); + expect(handleChange).toHaveBeenCalledTimes(2); + + // Test other key (should not trigger) + fireEvent.keyDown(switchButton, { key: "Tab" }); + expect(handleChange).toHaveBeenCalledTimes(2); + }); + + it("applies correct classes for different states", () => { + const { rerender } = render(); + let switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveClass("cursor-pointer"); + + rerender(); + switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveClass("cursor-pointer"); + }); + + it("applies correct track styles based on checked state", () => { + const { rerender } = render(); + let switchButton = screen.getByRole("switch"); + let track = switchButton.querySelector("div"); + expect(track).toHaveClass("bg-[var(--color-surface-default-tertiary)]"); + + rerender(); + switchButton = screen.getByRole("switch"); + track = switchButton.querySelector("div"); + expect(track).toHaveClass("bg-[var(--color-surface-inverse-tertiary)]"); + + switchButton = screen.getByRole("switch"); + track = switchButton.querySelector("div"); + expect(track).toHaveClass("bg-[var(--color-surface-inverse-tertiary)]"); + }); + + it("applies correct focus styles", () => { + const { rerender } = render(); + let switchButton = screen.getByRole("switch"); + expect(switchButton).not.toHaveClass("shadow-[0_0_5px_1px_#3281F8]"); + + rerender(); + switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveClass("shadow-[0_0_5px_3px_#3281F8]"); + }); + + it("applies correct base classes", () => { + render(); + const switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveClass( + "relative", + "inline-flex", + "items-center", + "cursor-pointer", + "transition-all", + "duration-200", + "focus:outline-none", + "focus-visible:shadow-[0_0_5px_3px_#3281F8]" + ); + }); + + it("forwards ref correctly", () => { + const ref = React.createRef(); + render(); + expect(ref.current).toBeInstanceOf(HTMLButtonElement); + }); + + it("applies custom className", () => { + render(); + const switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveClass("custom-class"); + }); + + it("renders label when provided", () => { + render(); + expect(screen.getByText("Test Label")).toBeInTheDocument(); + }); + + it("does not render label when not provided", () => { + render(); + expect(screen.queryByText("Switch label")).not.toBeInTheDocument(); + // Should have aria-label for accessibility + const switchButton = screen.getByRole("switch"); + expect(switchButton).toHaveAttribute("aria-label", "Toggle switch"); + }); + + it("applies correct label styles", () => { + render(); + const label = screen.getByText("Test Label"); + expect(label).toHaveClass( + "ml-[var(--measures-spacing-008)]", + "font-inter", + "font-normal", + "text-[14px]", + "leading-[20px]", + "text-[var(--color-content-default-primary)]" + ); + }); +});