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');
});
});
});