feat: create tests for shared/ui components
This commit is contained in:
85
src/shared/ui/CheckboxFilter/CheckboxFilter.svelte.test.ts
Normal file
85
src/shared/ui/CheckboxFilter/CheckboxFilter.svelte.test.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import type { Property } from '$shared/store/createFilterStore';
|
||||||
|
import {
|
||||||
|
fireEvent,
|
||||||
|
render,
|
||||||
|
screen,
|
||||||
|
} from '@testing-library/svelte';
|
||||||
|
import {
|
||||||
|
beforeEach,
|
||||||
|
describe,
|
||||||
|
expect,
|
||||||
|
it,
|
||||||
|
vi,
|
||||||
|
} from 'vitest';
|
||||||
|
import CheckboxFilter from './CheckboxFilter.svelte';
|
||||||
|
|
||||||
|
describe('CheckboxFilter', () => {
|
||||||
|
const mockProperties: Property[] = [
|
||||||
|
{ id: '1', name: 'Sans-serif', selected: false },
|
||||||
|
{ id: '2', name: 'Serif', selected: true },
|
||||||
|
{ id: '3', name: 'Display', selected: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
const mockOnPropertyToggle = vi.fn();
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockOnPropertyToggle.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders with correct label', () => {
|
||||||
|
render(CheckboxFilter, {
|
||||||
|
displayedLabel: 'Font Categories',
|
||||||
|
properties: mockProperties,
|
||||||
|
onPropertyToggle: mockOnPropertyToggle,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('Font Categories')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays all properties as checkboxes', () => {
|
||||||
|
render(CheckboxFilter, {
|
||||||
|
displayedLabel: 'Categories',
|
||||||
|
properties: mockProperties,
|
||||||
|
onPropertyToggle: mockOnPropertyToggle,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByLabelText('Sans-serif')).toBeInTheDocument();
|
||||||
|
expect(screen.getByLabelText('Serif')).toBeInTheDocument();
|
||||||
|
expect(screen.getByLabelText('Display')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows selected count badge when items selected', () => {
|
||||||
|
render(CheckboxFilter, {
|
||||||
|
displayedLabel: 'Categories',
|
||||||
|
properties: mockProperties,
|
||||||
|
onPropertyToggle: mockOnPropertyToggle,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.getByText('1')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not show badge when no items selected', () => {
|
||||||
|
const allUnselected = mockProperties.map(p => ({ ...p, selected: false }));
|
||||||
|
|
||||||
|
render(CheckboxFilter, {
|
||||||
|
displayedLabel: 'Categories',
|
||||||
|
properties: allUnselected,
|
||||||
|
onPropertyToggle: mockOnPropertyToggle,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(screen.queryByText('0')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls onPropertyToggle when checkbox clicked', async () => {
|
||||||
|
render(CheckboxFilter, {
|
||||||
|
displayedLabel: 'Categories',
|
||||||
|
properties: mockProperties,
|
||||||
|
onPropertyToggle: mockOnPropertyToggle,
|
||||||
|
});
|
||||||
|
|
||||||
|
const checkbox = screen.getByLabelText('Sans-serif');
|
||||||
|
await checkbox.click();
|
||||||
|
|
||||||
|
expect(mockOnPropertyToggle).toHaveBeenCalledWith('1');
|
||||||
|
});
|
||||||
|
});
|
||||||
308
src/shared/ui/ComboControl/ComboControl.svelte.test.ts
Normal file
308
src/shared/ui/ComboControl/ComboControl.svelte.test.ts
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
import {
|
||||||
|
fireEvent,
|
||||||
|
render,
|
||||||
|
} from '@testing-library/svelte';
|
||||||
|
import {
|
||||||
|
beforeEach,
|
||||||
|
describe,
|
||||||
|
expect,
|
||||||
|
it,
|
||||||
|
vi,
|
||||||
|
} from 'vitest';
|
||||||
|
import ComboControl from './ComboControl.svelte';
|
||||||
|
|
||||||
|
describe('ComboControl', () => {
|
||||||
|
const onChangeMock = vi.fn() as (value: number) => void;
|
||||||
|
const onIncreaseMock = vi.fn() as () => void;
|
||||||
|
const onDecreaseMock = vi.fn() as () => void;
|
||||||
|
|
||||||
|
it('renders with default values', () => {
|
||||||
|
const { container } = render(ComboControl, {
|
||||||
|
value: 50,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that the control button displays the value
|
||||||
|
const controlButton = container.querySelector(
|
||||||
|
'button[variant="outline"][size="icon"]:nth-child(2)',
|
||||||
|
);
|
||||||
|
expect(controlButton?.textContent).toBe('50');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders with custom min/max/step', () => {
|
||||||
|
const { container } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 10,
|
||||||
|
step: 0.5,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
});
|
||||||
|
|
||||||
|
const controlButton = container.querySelector(
|
||||||
|
'button[variant="outline"][size="icon"]:nth-child(2)',
|
||||||
|
);
|
||||||
|
expect(controlButton?.textContent).toBe('5');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls onIncrease when increase button is clicked', async () => {
|
||||||
|
const { getByLabelText } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
increaseLabel: 'Increase value',
|
||||||
|
});
|
||||||
|
|
||||||
|
const increaseButton = getByLabelText('Increase value');
|
||||||
|
await fireEvent.click(increaseButton);
|
||||||
|
|
||||||
|
expect(onIncreaseMock).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls onDecrease when decrease button is clicked', async () => {
|
||||||
|
const { getByLabelText } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
decreaseLabel: 'Decrease value',
|
||||||
|
});
|
||||||
|
|
||||||
|
const decreaseButton = getByLabelText('Decrease value');
|
||||||
|
await fireEvent.click(decreaseButton);
|
||||||
|
|
||||||
|
expect(onDecreaseMock).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('disables increase button when increaseDisabled is true', () => {
|
||||||
|
const { getByLabelText } = render(ComboControl, {
|
||||||
|
value: 100,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 100,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
increaseDisabled: true,
|
||||||
|
increaseLabel: 'Increase value',
|
||||||
|
});
|
||||||
|
|
||||||
|
const increaseButton = getByLabelText('Increase value');
|
||||||
|
expect(increaseButton).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('disables decrease button when decreaseDisabled is true', () => {
|
||||||
|
const { getByLabelText } = render(ComboControl, {
|
||||||
|
value: 0,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 100,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
decreaseDisabled: true,
|
||||||
|
decreaseLabel: 'Decrease value',
|
||||||
|
});
|
||||||
|
|
||||||
|
const decreaseButton = getByLabelText('Decrease value');
|
||||||
|
expect(decreaseButton).toBeDisabled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('opens popover when control button is clicked', async () => {
|
||||||
|
const { getByLabelText, queryByRole } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
controlLabel: 'Control value',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initially, popover content should not be visible
|
||||||
|
expect(queryByRole('dialog')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
const controlButton = getByLabelText('Control value');
|
||||||
|
await fireEvent.click(controlButton);
|
||||||
|
|
||||||
|
// After clicking, popover content should be visible
|
||||||
|
expect(queryByRole('dialog')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates value when slider changes', async () => {
|
||||||
|
const { getByLabelText, container } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 10,
|
||||||
|
step: 1,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
controlLabel: 'Control value',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open popover
|
||||||
|
const controlButton = getByLabelText('Control value');
|
||||||
|
await fireEvent.click(controlButton);
|
||||||
|
|
||||||
|
// Find slider - the Slider component should render an input with role slider
|
||||||
|
const slider = container.querySelector('[role="slider"]');
|
||||||
|
expect(slider).toBeInTheDocument();
|
||||||
|
|
||||||
|
// Simulate slider change
|
||||||
|
await fireEvent.input(slider!, { target: { value: '7' } });
|
||||||
|
|
||||||
|
expect(onChangeMock).toHaveBeenCalledWith(7);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('updates value when number input changes', async () => {
|
||||||
|
const { getByLabelText, container } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 10,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
controlLabel: 'Control value',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open popover
|
||||||
|
const controlButton = getByLabelText('Control value');
|
||||||
|
await fireEvent.click(controlButton);
|
||||||
|
|
||||||
|
// Find number input
|
||||||
|
const input = container.querySelector('input[type="text"], input[type="number"]');
|
||||||
|
expect(input).toBeInTheDocument();
|
||||||
|
|
||||||
|
// Simulate input change
|
||||||
|
await fireEvent.change(input!, { target: { value: '8' } });
|
||||||
|
|
||||||
|
expect(onChangeMock).toHaveBeenCalledWith(8);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects min and max values on input', () => {
|
||||||
|
const { getByLabelText, container } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 10,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
controlLabel: 'Control value',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open popover
|
||||||
|
const controlButton = getByLabelText('Control value');
|
||||||
|
fireEvent.click(controlButton);
|
||||||
|
|
||||||
|
// Find input
|
||||||
|
const input = container.querySelector('input[type="text"], input[type="number"]');
|
||||||
|
|
||||||
|
// Check min and max attributes
|
||||||
|
expect(input).toHaveAttribute('min', '0');
|
||||||
|
expect(input).toHaveAttribute('max', '10');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses custom aria-labels', () => {
|
||||||
|
const { getByLabelText } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
increaseLabel: 'Increase by step',
|
||||||
|
decreaseLabel: 'Decrease by step',
|
||||||
|
controlLabel: 'Change value',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(getByLabelText('Increase by step')).toBeInTheDocument();
|
||||||
|
expect(getByLabelText('Decrease by step')).toBeInTheDocument();
|
||||||
|
expect(getByLabelText('Change value')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses default min/max/step values when not provided', () => {
|
||||||
|
const { getByLabelText, container } = render(ComboControl, {
|
||||||
|
value: 50,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
controlLabel: 'Control value',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open popover
|
||||||
|
const controlButton = getByLabelText('Control value');
|
||||||
|
fireEvent.click(controlButton);
|
||||||
|
|
||||||
|
// Find input
|
||||||
|
const input = container.querySelector('input[type="text"], input[type="number"]');
|
||||||
|
|
||||||
|
// Check default values (0, 100, 1)
|
||||||
|
expect(input).toHaveAttribute('min', '0');
|
||||||
|
expect(input).toHaveAttribute('max', '100');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not call onChange when input value is invalid', async () => {
|
||||||
|
const { getByLabelText, container } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
controlLabel: 'Control value',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open popover
|
||||||
|
const controlButton = getByLabelText('Control value');
|
||||||
|
await fireEvent.click(controlButton);
|
||||||
|
|
||||||
|
// Find input
|
||||||
|
const input = container.querySelector('input[type="text"], input[type="number"]');
|
||||||
|
|
||||||
|
// Simulate invalid input
|
||||||
|
await fireEvent.change(input!, { target: { value: 'invalid' } });
|
||||||
|
|
||||||
|
expect(onChangeMock).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('displays current value in input field', async () => {
|
||||||
|
const { getByLabelText, container } = render(ComboControl, {
|
||||||
|
value: 42,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
controlLabel: 'Control value',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open popover
|
||||||
|
const controlButton = getByLabelText('Control value');
|
||||||
|
await fireEvent.click(controlButton);
|
||||||
|
|
||||||
|
// Find input
|
||||||
|
const input = container.querySelector('input[type="text"], input[type="number"]');
|
||||||
|
|
||||||
|
expect(input).toHaveValue('42');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles step value for slider precision', async () => {
|
||||||
|
const { getByLabelText, container } = render(ComboControl, {
|
||||||
|
value: 5,
|
||||||
|
minValue: 0,
|
||||||
|
maxValue: 10,
|
||||||
|
step: 0.25,
|
||||||
|
onChange: onChangeMock,
|
||||||
|
onIncrease: onIncreaseMock,
|
||||||
|
onDecrease: onDecreaseMock,
|
||||||
|
controlLabel: 'Control value',
|
||||||
|
});
|
||||||
|
|
||||||
|
// Open popover
|
||||||
|
const controlButton = getByLabelText('Control value');
|
||||||
|
await fireEvent.click(controlButton);
|
||||||
|
|
||||||
|
// Find slider
|
||||||
|
const slider = container.querySelector('[role="slider"]');
|
||||||
|
|
||||||
|
// Simulate slider change
|
||||||
|
await fireEvent.input(slider!, { target: { value: '5.5' } });
|
||||||
|
|
||||||
|
expect(onChangeMock).toHaveBeenCalledWith(5.5);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user