import { render, screen, fireEvent } from '@testing-library/react'; import * as React from 'react'; import { SliderField, SLIDER_LABEL_TEST_ID, SLIDER_RANGE_TEST_ID, SLIDER_ROOT_TEST_ID, SLIDER_TRACK_TEST_ID, } from '../SliderField'; import { Heading } from '../../Heading'; import { testFlexProps, expectFlexContainerStyleProps, } from '../../Flex/__tests__/Flex.test'; import { ComponentClassNames } from '../../shared/constants'; import { AUTO_GENERATED_ID_PREFIX } from '../../utils/useStableId'; // Jest uses JSDom, which apparently doesn't support the ResizeObserver API // This will get around that API reference error in Jest // We don't necessarily test its functionality since Radix should be responsible for that window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), observe: jest.fn(), unobserve: jest.fn(), })); describe('SliderField:', () => { describe('Flex wrapper', () => { it('should render all flex style props', async () => { render( ); const sliderField = await screen.findByTestId('slider-field'); expectFlexContainerStyleProps(sliderField); }); }); describe('Label', () => { it('should render expected field classname', async () => { render(); const label = await screen.findByTestId(SLIDER_LABEL_TEST_ID); expect(label).toHaveClass( ComponentClassNames.Label, ComponentClassNames.SliderFieldLabel ); }); it('should forward ref to DOM element', async () => { const ref = React.createRef(); const testId = 'sliderTestId'; render( ); await screen.findByTestId(testId); expect(ref.current?.nodeName).toBe('SPAN'); }); it('should have `amplify-visually-hidden` class when labelHidden is true', async () => { render(); const label = await screen.findByTestId(SLIDER_LABEL_TEST_ID); expect(label).toHaveClass('amplify-visually-hidden'); }); it('should set autogenerated id', async () => { render(); const label = await screen.findByTestId(SLIDER_LABEL_TEST_ID); expect(label.id.startsWith(AUTO_GENERATED_ID_PREFIX)).toBeTruthy(); }); it('should display value if isValueHidden is false', () => { render(); const value = screen.queryByText('10'); expect(value).toBeInTheDocument(); }); it('should display string formatted value if formatValue is provided', async () => { render( { return `${value}%`; }} /> ); const value = await screen.findByText('10%'); expect(value).toBeInTheDocument(); }); it('should display component-based formatted value if formatValue is provided', async () => { render( { return {value}; }} /> ); const heading = await screen.findByText('10'); expect(heading).toHaveClass(ComponentClassNames.Heading); }); it('should not display value if isValueHidden is true', () => { render(); const value = screen.queryByText('10'); expect(value).not.toBeInTheDocument(); }); }); describe('Slider', () => { const ControlledSliderField = () => { const [value, setValue] = React.useState(5); return ; }; it('should work as uncontrolled component', async () => { render(); const slider = await screen.findByRole('slider'); expect(slider).toHaveAttribute('aria-valuenow', '10'); fireEvent.keyDown(slider, { key: 'ArrowUp', code: 'ArrowUp' }); expect(slider).toHaveAttribute('aria-valuenow', '11'); fireEvent.keyDown(slider, { key: 'ArrowUp', code: 'ArrowUp' }); expect(slider).toHaveAttribute('aria-valuenow', '12'); fireEvent.keyDown(slider, { key: 'ArrowDown', code: 'ArrowDown' }); expect(slider).toHaveAttribute('aria-valuenow', '11'); fireEvent.keyDown(slider, { key: 'ArrowDown', code: 'ArrowDown' }); expect(slider).toHaveAttribute('aria-valuenow', '10'); }); it('should work as controlled component', async () => { render(); const slider = await screen.findByRole('slider'); expect(slider).toHaveAttribute('aria-valuenow', '5'); fireEvent.keyDown(slider, { key: 'ArrowUp', code: 'ArrowUp' }); expect(slider).toHaveAttribute('aria-valuenow', '6'); fireEvent.keyDown(slider, { key: 'ArrowUp', code: 'ArrowUp' }); expect(slider).toHaveAttribute('aria-valuenow', '7'); fireEvent.keyDown(slider, { key: 'ArrowDown', code: 'ArrowDown' }); expect(slider).toHaveAttribute('aria-valuenow', '6'); fireEvent.keyDown(slider, { key: 'ArrowDown', code: 'ArrowDown' }); expect(slider).toHaveAttribute('aria-valuenow', '5'); }); it('should set step', async () => { render(); const slider = await screen.findByRole('slider'); expect(slider).toHaveAttribute('aria-valuenow', '0'); fireEvent.keyDown(slider, { key: 'ArrowUp', code: 'ArrowUp' }); expect(slider).toHaveAttribute('aria-valuenow', '3'); fireEvent.keyDown(slider, { key: 'ArrowUp', code: 'ArrowUp' }); expect(slider).toHaveAttribute('aria-valuenow', '6'); fireEvent.keyDown(slider, { key: 'ArrowDown', code: 'ArrowDown' }); expect(slider).toHaveAttribute('aria-valuenow', '3'); fireEvent.keyDown(slider, { key: 'ArrowDown', code: 'ArrowDown' }); expect(slider).toHaveAttribute('aria-valuenow', '0'); }); it('should render size classes for SliderField', async () => { render(
); const small = await screen.findByTestId('small'); const large = await screen.findByTestId('large'); expect(small.classList).toContain( `${ComponentClassNames['Field']}--small` ); expect(large.classList).toContain( `${ComponentClassNames['Field']}--large` ); }); describe('Root', () => { it('should render default and custom classname', async () => { const className = 'class-test'; render( ); const root = await screen.findByTestId(SLIDER_ROOT_TEST_ID); expect(root).toHaveClass( ComponentClassNames.SliderFieldRoot, className ); }); it('should pass orientation prop', async () => { render( ); const root = await screen.findByTestId(SLIDER_ROOT_TEST_ID); expect(root).toHaveAttribute('data-orientation', 'vertical'); }); it('should be disabled', async () => { render(); const root = await screen.findByTestId(SLIDER_ROOT_TEST_ID); expect(root).toHaveAttribute('data-disabled', ''); }); }); describe('Track', () => { it('should render default classname', async () => { render(); const track = await screen.findByTestId(SLIDER_TRACK_TEST_ID); expect(track).toHaveClass(ComponentClassNames.SliderFieldTrack); }); it('should set empty track color', async () => { render( ); const track = await screen.findByTestId(SLIDER_TRACK_TEST_ID); expect(track).toHaveStyle('background-color: red'); }); it('should set track width for horizontal slider', async () => { render(); const track = await screen.findByTestId(SLIDER_TRACK_TEST_ID); expect(track).toHaveStyle('height: 3px'); }); it('should set track width for vertical slider', async () => { render( ); const track = await screen.findByTestId(SLIDER_TRACK_TEST_ID); expect(track).toHaveStyle('width: 3px'); }); }); describe('Range', () => { it('should render default classname', async () => { render(); const range = await screen.findByTestId(SLIDER_RANGE_TEST_ID); expect(range).toHaveClass(ComponentClassNames.SliderFieldRange); }); it('should render orientation classes for SliderField', async () => { render( ); const vertical = await screen.findByTestId(SLIDER_RANGE_TEST_ID); expect(vertical).toHaveClass( `${ComponentClassNames.SliderFieldRange}--vertical` ); }); it('should set filled track color', async () => { render( ); const range = await screen.findByTestId(SLIDER_RANGE_TEST_ID); expect(range).toHaveStyle('background-color: teal'); }); }); describe('Thumb', () => { it('should render default classname', async () => { render(); const thumb = await screen.findByRole('slider'); expect(thumb).toHaveClass(ComponentClassNames.SliderFieldThumb); }); it('should pass min and max props', async () => { render( ); const thumb = await screen.findByRole('slider'); expect(thumb).toHaveAttribute('aria-valuemin', '-100'); expect(thumb).toHaveAttribute('aria-valuemax', '100'); }); it('should set thumb color', async () => { render( ); const thumb = await screen.findByRole('slider'); expect(thumb).toHaveStyle('background-color: orange'); }); it('should map to label correctly', async () => { render( ); const thumb = await screen.findByRole('slider'); expect(thumb).toHaveAccessibleName('slider 0'); }); it('should set aria-valuetext', async () => { render( ); const thumb = await screen.findByRole('slider'); expect(thumb).toHaveAttribute('aria-valuetext', 'Monday'); }); }); }); describe('Error messages', () => { const errorMessage = 'This is an error message'; it('should not show when hasError is false', () => { render( ); const errorText = screen.queryByText(errorMessage); expect(errorText).not.toBeInTheDocument(); }); it('show when hasError and errorMessage', () => { render( ); const errorText = screen.queryByText(errorMessage); expect(errorText?.innerHTML).toContain(errorMessage); }); }); describe('descriptive message', () => { it('should render descriptiveText if it is provided', () => { render( ); const descriptiveText = screen.queryByText('Description'); expect(descriptiveText?.innerHTML).toContain('Description'); }); it('should map to descriptive text correctly', async () => { render( ); const slider = await screen.findByRole('slider'); expect(slider).toHaveAccessibleDescription('Description'); }); }); });