diff --git a/src/shared/ui/Switch/Switch.test.tsx b/src/shared/ui/Switch/Switch.test.tsx new file mode 100644 index 000000000..68777c61b --- /dev/null +++ b/src/shared/ui/Switch/Switch.test.tsx @@ -0,0 +1,134 @@ +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'; + +const defaultProps: SwitchProps = { + checked: false, + onChange: jest.fn(), +}; + +const renderSwitch = (props?: Partial & { ref?: RefObject }) => { + renderComponent(); +}; + +describe('Switch', () => { + describe('wrapper', () => { + test('render', () => { + renderSwitch(); + const wrapper = screen.getByTestId(switchTestIds.wrapper); + expect(wrapper).toBeInTheDocument(); + expect(wrapper).toHaveClass('align-center'); + }); + }); + + describe('switch', () => { + test('render', () => { + 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'); + }); + }); + + 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(); + }); + }); + + 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'); + }); + }); + + 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', +};