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