From 4d421226abdf161d2bd1295dd4061abdd995c2f5 Mon Sep 17 00:00:00 2001 From: KingPr0f Date: Sat, 14 Mar 2026 15:54:58 +1000 Subject: [PATCH 1/3] YH-1788: add tests for Switch component --- src/shared/ui/Switch/Switch.test.tsx | 84 ++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/shared/ui/Switch/Switch.test.tsx diff --git a/src/shared/ui/Switch/Switch.test.tsx b/src/shared/ui/Switch/Switch.test.tsx new file mode 100644 index 000000000..3dd40e472 --- /dev/null +++ b/src/shared/ui/Switch/Switch.test.tsx @@ -0,0 +1,84 @@ +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { renderComponent } from '@/shared/libs'; + +import { Switch } from './Switch'; +import { SwitchProps } from './types'; + +const defaultProps: SwitchProps = { + checked: false, + onChange: jest.fn(), +}; + +const renderSwitch = (props?: Partial) => { + renderComponent(); +}; + +describe('Switch', () => { + it('renders switch input', () => { + renderSwitch(); + + expect(screen.getByRole('switch')).toBeInTheDocument(); + }); + + it('renders as checked when checked prop is true', () => { + renderSwitch({ checked: true }); + + const input = screen.getByRole('switch'); + + expect(input).toBeChecked(); + expect(input).toHaveAttribute('aria-checked', 'true'); + }); + + it('renders as unchecked when checked prop is false', () => { + renderSwitch({ checked: false }); + + const input = screen.getByRole('switch'); + + expect(input).not.toBeChecked(); + expect(input).toHaveAttribute('aria-checked', 'false'); + }); + + it('calls onChange when clicked', async () => { + const onChange = jest.fn(); + renderSwitch({ onChange }); + + await userEvent.click(screen.getByRole('switch')); + + expect(onChange).toHaveBeenCalledTimes(1); + }); + + it('does not call onChange when disabled', async () => { + const onChange = jest.fn(); + renderSwitch({ disabled: true, onChange }); + + await userEvent.click(screen.getByRole('switch')); + + expect(onChange).not.toHaveBeenCalled(); + }); + + it('renders with disabled attribute', () => { + renderSwitch({ disabled: true }); + + expect(screen.getByRole('switch')).toBeDisabled(); + }); + + it('renders label when provided', () => { + renderSwitch({ label: 'label' }); + + expect(screen.getByText('label')).toBeInTheDocument(); + }); + + it('does not render label when not provided', () => { + renderSwitch(); + + expect(screen.queryByText('label')).not.toBeInTheDocument(); + }); + + it('passes inputProps to input element', () => { + renderSwitch({ inputProps: { 'aria-label': 'toggle' } }); + + expect(screen.getByRole('switch')).toHaveAttribute('aria-label', 'toggle'); + }); +}); From 12378272efdcc0031a42f365d8b4f19375a0c4ea Mon Sep 17 00:00:00 2001 From: Denis Pereloma Date: Sun, 22 Mar 2026 10:09:48 +0300 Subject: [PATCH 2/3] YH-1788: update tests --- src/shared/ui/Switch/Switch.test.tsx | 159 +++++++++++++++++---------- src/shared/ui/Switch/Switch.tsx | 89 ++++++++------- src/shared/ui/Switch/constants.ts | 9 +- 3 files changed, 156 insertions(+), 101 deletions(-) diff --git a/src/shared/ui/Switch/Switch.test.tsx b/src/shared/ui/Switch/Switch.test.tsx index 3dd40e472..a0c5c519d 100644 --- a/src/shared/ui/Switch/Switch.test.tsx +++ b/src/shared/ui/Switch/Switch.test.tsx @@ -1,7 +1,11 @@ +import { describe } from 'node:test'; + import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import React, { createRef, RefObject } from 'react'; import { renderComponent } from '@/shared/libs'; +import { switchTestIds } from '@/shared/ui/Switch/constants'; import { Switch } from './Switch'; import { SwitchProps } from './types'; @@ -11,74 +15,115 @@ const defaultProps: SwitchProps = { onChange: jest.fn(), }; -const renderSwitch = (props?: Partial) => { +const renderSwitch = (props?: Partial & { ref?: RefObject }) => { renderComponent(); }; describe('Switch', () => { - it('renders switch input', () => { - renderSwitch(); - - expect(screen.getByRole('switch')).toBeInTheDocument(); - }); - - it('renders as checked when checked prop is true', () => { - renderSwitch({ checked: true }); - - const input = screen.getByRole('switch'); - - expect(input).toBeChecked(); - expect(input).toHaveAttribute('aria-checked', 'true'); - }); - - it('renders as unchecked when checked prop is false', () => { - renderSwitch({ checked: false }); - - const input = screen.getByRole('switch'); - - expect(input).not.toBeChecked(); - expect(input).toHaveAttribute('aria-checked', 'false'); - }); - - it('calls onChange when clicked', async () => { - const onChange = jest.fn(); - renderSwitch({ onChange }); - - await userEvent.click(screen.getByRole('switch')); - - expect(onChange).toHaveBeenCalledTimes(1); + describe('wrapper', () => { + test('render', () => { + renderSwitch(); + const wrapper = screen.getByTestId(switchTestIds.wrapper); + expect(wrapper).toBeInTheDocument(); + expect(wrapper).toHaveClass('align-center'); + }); }); - it('does not call onChange when disabled', async () => { - const onChange = jest.fn(); - renderSwitch({ disabled: true, onChange }); - - await userEvent.click(screen.getByRole('switch')); - - expect(onChange).not.toHaveBeenCalled(); + describe('switch', () => { + test('render', () => { + renderSwitch(); + const switchEl = screen.getByTestId(switchTestIds.switch); + expect(switchEl).toBeInTheDocument(); + }); }); - it('renders with disabled attribute', () => { - renderSwitch({ disabled: true }); - - expect(screen.getByRole('switch')).toBeDisabled(); + describe('input', () => { + test('render', () => { + renderSwitch(); + const input = screen.getByTestId(switchTestIds.input); + expect(input).toBeInTheDocument(); + expect(input).toHaveAttribute('type', 'checkbox'); + expect(input).toHaveAttribute('role', 'switch'); + expect(input).not.toHaveAttribute('checked'); + expect(input).toHaveAttribute('aria-checked', 'false'); + expect(input).not.toHaveAttribute('disabled'); + expect(input).toHaveClass('switch-input'); + }); + + test('inputRef props', () => { + const testRef = createRef(); + renderSwitch({ inputRef: testRef }); + const input = screen.getByTestId(switchTestIds.input); + expect(testRef.current).toBe(input); + expect(testRef.current?.tagName).toBe('INPUT'); + }); + + it('checked=true props', () => { + renderSwitch({ checked: true }); + const input = screen.getByTestId(switchTestIds.input); + expect(input).toBeChecked(); + expect(input).toHaveAttribute('aria-checked', 'true'); + }); + + it('disabled=true props', () => { + renderSwitch({ disabled: true }); + const input = screen.getByTestId(switchTestIds.input); + expect(input).toBeDisabled(); + }); + + it('calls onChange when clicked', async () => { + const onChange = jest.fn(); + renderSwitch({ onChange }); + const input = screen.getByTestId(switchTestIds.input); + await userEvent.click(input); + expect(onChange).toHaveBeenCalledTimes(1); + }); + + it('does not call onChange when disabled', async () => { + const onChange = jest.fn(); + renderSwitch({ disabled: true, onChange }); + const input = screen.getByTestId(switchTestIds.input); + await userEvent.click(input); + expect(onChange).not.toHaveBeenCalled(); + }); }); - it('renders label when provided', () => { - renderSwitch({ label: 'label' }); - - expect(screen.getByText('label')).toBeInTheDocument(); + describe('pin', () => { + test('render', () => { + renderSwitch(); + const pin = screen.getByTestId(switchTestIds.pin); + expect(pin).toBeInTheDocument(); + expect(pin).toHaveClass('switch-slider'); + }); + + test('render with pinClassName props', () => { + renderSwitch({ pinClassName: 'pin' }); + const pin = screen.getByTestId(switchTestIds.pin); + expect(pin).toBeInTheDocument(); + expect(pin).toHaveClass('switch-slider', 'pin'); + }); }); - it('does not render label when not provided', () => { - renderSwitch(); - - expect(screen.queryByText('label')).not.toBeInTheDocument(); - }); - - it('passes inputProps to input element', () => { - renderSwitch({ inputProps: { 'aria-label': 'toggle' } }); - - expect(screen.getByRole('switch')).toHaveAttribute('aria-label', 'toggle'); + describe('label', () => { + test('render without label props', () => { + renderSwitch(); + const label = screen.queryByTestId(switchTestIds.label); + expect(label).not.toBeInTheDocument(); + }); + + test('render with label props', () => { + renderSwitch({ label: 'Label' }); + const label = screen.queryByTestId(switchTestIds.label); + expect(label).toBeInTheDocument(); + expect(label).toHaveTextContent('Label'); + expect(label).toHaveClass('switch-label'); + }); + + test('render with labelClassName props', () => { + renderSwitch({ label: 'Label', labelClassName: 'label-classname' }); + const label = screen.queryByTestId(switchTestIds.label); + expect(label).toBeInTheDocument(); + expect(label).toHaveClass('switch-label', 'label-classname'); + }); }); }); diff --git a/src/shared/ui/Switch/Switch.tsx b/src/shared/ui/Switch/Switch.tsx index 912540fee..0f0b9e3ef 100644 --- a/src/shared/ui/Switch/Switch.tsx +++ b/src/shared/ui/Switch/Switch.tsx @@ -1,49 +1,54 @@ import classnames from 'classnames'; -import { forwardRef } from 'react'; import { Flex } from '@/shared/ui/Flex'; +import { switchTestIds } from './constants'; import styles from './Switch.module.css'; import { SwitchProps } from './types'; -export const Switch = forwardRef( - ( - { - checked, - disabled = false, - onChange, - inputRef, - inputProps = {}, - label, - labelClassName, - switchClassName, - pinClassName, - ...otherProps - }, - ref, - ): JSX.Element => { - return ( - - - {label && ( - {label} - )} - - ); - }, -); - -Switch.displayName = 'Switch'; +export const Switch = ({ + checked, + disabled = false, + onChange, + inputRef, + inputProps = {}, + label, + labelClassName, + switchClassName, + pinClassName, + ...otherProps +}: SwitchProps) => { + return ( + + + {label && ( + + {label} + + )} + + ); +}; diff --git a/src/shared/ui/Switch/constants.ts b/src/shared/ui/Switch/constants.ts index e33370356..f7a133935 100644 --- a/src/shared/ui/Switch/constants.ts +++ b/src/shared/ui/Switch/constants.ts @@ -1,2 +1,7 @@ -// SwitchNames.ts -export const SwitchNames = 'yeahub-switch'; +export const switchTestIds = { + wrapper: 'Switch_Wrapper', + switch: 'Switch_Switch', + input: 'Switch_Input', + pin: 'Switch_Pin', + label: 'Switch_Label', +}; From d01d397c03035dd54fb039e27e2f4de384119c7b Mon Sep 17 00:00:00 2001 From: KingPr0f Date: Sun, 22 Mar 2026 20:02:53 +0300 Subject: [PATCH 3/3] YH-1788: fix Switch tests after code review - Remove incorrect describe import from node:test - Add CSS class checks for switch element - Add test for switchClassName prop --- src/shared/ui/Switch/Switch.test.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/shared/ui/Switch/Switch.test.tsx b/src/shared/ui/Switch/Switch.test.tsx index a0c5c519d..68777c61b 100644 --- a/src/shared/ui/Switch/Switch.test.tsx +++ b/src/shared/ui/Switch/Switch.test.tsx @@ -1,5 +1,3 @@ -import { describe } from 'node:test'; - import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React, { createRef, RefObject } from 'react'; @@ -34,6 +32,13 @@ describe('Switch', () => { renderSwitch(); const switchEl = screen.getByTestId(switchTestIds.switch); expect(switchEl).toBeInTheDocument(); + expect(switchEl).toHaveClass('switch'); + }); + + test('render with switchClassName props', () => { + renderSwitch({ switchClassName: 'custom-switch' }); + const switchEl = screen.getByTestId(switchTestIds.switch); + expect(switchEl).toHaveClass('switch', 'custom-switch'); }); });