Files
frontend-svelte/src/shared/ui/ComboControl/ComboControl.svelte.test.ts
T

136 lines
5.5 KiB
TypeScript

import { createTypographyControl } from '$shared/lib';
import {
fireEvent,
render,
screen,
waitFor,
} from '@testing-library/svelte';
import ComboControl from './ComboControl.svelte';
function makeControl(value: number, opts: { min?: number; max?: number; step?: number } = {}) {
return createTypographyControl({
value,
min: opts.min ?? 0,
max: opts.max ?? 100,
step: opts.step ?? 1,
});
}
describe('ComboControl', () => {
describe('Rendering', () => {
it('renders decrease and increase buttons', () => {
render(ComboControl, { control: makeControl(50) });
expect(screen.getByLabelText('Decrease')).toBeInTheDocument();
expect(screen.getByLabelText('Increase')).toBeInTheDocument();
});
it('renders the current integer value', () => {
render(ComboControl, { control: makeControl(42) });
expect(screen.getByText('42')).toBeInTheDocument();
});
it('formats decimal value to 1 decimal place when step >= 0.1', () => {
render(ComboControl, { control: makeControl(1.5, { step: 0.1 }) });
expect(screen.getByText('1.5')).toBeInTheDocument();
});
it('formats decimal value to 2 decimal places when step < 0.1', () => {
render(ComboControl, { control: makeControl(1.55, { step: 0.01 }) });
expect(screen.getByText('1.55')).toBeInTheDocument();
});
it('renders label when label prop is provided', () => {
render(ComboControl, { control: makeControl(16), label: 'Size' });
expect(screen.getByText('Size')).toBeInTheDocument();
});
it('applies custom aria-labels to buttons', () => {
render(ComboControl, {
control: makeControl(50),
decreaseLabel: 'Decrease font size',
increaseLabel: 'Increase font size',
});
expect(screen.getByLabelText('Decrease font size')).toBeInTheDocument();
expect(screen.getByLabelText('Increase font size')).toBeInTheDocument();
});
});
describe('Disabled state', () => {
it('disables decrease button when at min', () => {
render(ComboControl, { control: makeControl(0, { min: 0 }) });
expect(screen.getByLabelText('Decrease')).toBeDisabled();
});
it('disables increase button when at max', () => {
render(ComboControl, { control: makeControl(100, { max: 100 }) });
expect(screen.getByLabelText('Increase')).toBeDisabled();
});
it('enables both buttons when value is within bounds', () => {
render(ComboControl, { control: makeControl(50, { min: 0, max: 100 }) });
expect(screen.getByLabelText('Decrease')).not.toBeDisabled();
expect(screen.getByLabelText('Increase')).not.toBeDisabled();
});
});
describe('Click interactions', () => {
it('decreases value on decrease button click', async () => {
const control = makeControl(50, { step: 5 });
render(ComboControl, { control });
await fireEvent.click(screen.getByLabelText('Decrease'));
expect(control.value).toBe(45);
});
it('increases value on increase button click', async () => {
const control = makeControl(50, { step: 5 });
render(ComboControl, { control });
await fireEvent.click(screen.getByLabelText('Increase'));
expect(control.value).toBe(55);
});
it('clamps decrease at min', async () => {
const control = makeControl(2, { min: 0, step: 5 });
render(ComboControl, { control });
await fireEvent.click(screen.getByLabelText('Decrease'));
expect(control.value).toBe(0);
});
it('clamps increase at max', async () => {
const control = makeControl(98, { max: 100, step: 5 });
render(ComboControl, { control });
await fireEvent.click(screen.getByLabelText('Increase'));
expect(control.value).toBe(100);
});
it('updates displayed value after click', async () => {
const control = makeControl(50);
render(ComboControl, { control });
await fireEvent.click(screen.getByLabelText('Increase'));
await waitFor(() => expect(screen.getByText('51')).toBeInTheDocument());
});
});
describe('Popover', () => {
it('opens popover with vertical slider on trigger click', async () => {
render(ComboControl, { control: makeControl(50), controlLabel: 'Size control' });
expect(screen.queryByRole('slider')).not.toBeInTheDocument();
await fireEvent.click(screen.getByText('Size control'));
await waitFor(() => expect(screen.getByRole('slider')).toBeInTheDocument());
});
});
describe('Reduced mode', () => {
it('renders horizontal slider directly without popover trigger', () => {
render(ComboControl, { control: makeControl(50), reduced: true });
expect(screen.getByRole('slider')).toBeInTheDocument();
expect(screen.queryByLabelText('Decrease')).not.toBeInTheDocument();
expect(screen.queryByLabelText('Increase')).not.toBeInTheDocument();
});
it('shows formatted value in reduced mode', () => {
const { container } = render(ComboControl, { control: makeControl(75), reduced: true });
expect(container.textContent).toContain('75');
});
});
});