test(document): cover FileSwitcherStrip branches

Prev/next nav buttons, chip count per file, aria-current matrix for
active id, error-state data attribute, onSelect callback, onRemove
callback, sr-only announcer for active title.

7 tests covering ~25 branches.

Refs #496.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-10 01:35:23 +02:00
parent ef63ca18d2
commit 4230f03e0e

View File

@@ -0,0 +1,122 @@
import { describe, it, expect, vi, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import FileSwitcherStrip from './FileSwitcherStrip.svelte';
afterEach(cleanup);
const makeEntry = (id: string, title: string, overrides: Record<string, unknown> = {}) => ({
id,
title,
status: 'idle' as 'idle' | 'error',
previewUrl: '',
...overrides
});
describe('FileSwitcherStrip', () => {
it('renders the prev and next buttons', async () => {
render(FileSwitcherStrip, {
props: {
files: [makeEntry('f1', 'A.pdf')],
activeId: 'f1',
onSelect: () => {},
onRemove: () => {}
}
});
await expect.element(page.getByRole('button', { name: /vorherige datei/i })).toBeVisible();
await expect.element(page.getByRole('button', { name: /nächste datei/i })).toBeVisible();
});
it('renders one chip per file', async () => {
render(FileSwitcherStrip, {
props: {
files: [makeEntry('f1', 'A.pdf'), makeEntry('f2', 'B.pdf'), makeEntry('f3', 'C.pdf')],
activeId: 'f1',
onSelect: () => {},
onRemove: () => {}
}
});
const chips = document.querySelectorAll('[data-chip-id]');
expect(chips.length).toBe(3);
});
it('marks the active chip with aria-current=true', async () => {
render(FileSwitcherStrip, {
props: {
files: [makeEntry('f1', 'A'), makeEntry('f2', 'B')],
activeId: 'f2',
onSelect: () => {},
onRemove: () => {}
}
});
const f2 = document.querySelector('[data-chip-id="f2"]') as HTMLElement;
const f1 = document.querySelector('[data-chip-id="f1"]') as HTMLElement;
expect(f2.getAttribute('aria-current')).toBe('true');
expect(f1.getAttribute('aria-current')).toBeNull();
});
it('shows the error indicator on chips with status="error"', async () => {
render(FileSwitcherStrip, {
props: {
files: [makeEntry('f1', 'A.pdf', { status: 'error' })],
activeId: 'f1',
onSelect: () => {},
onRemove: () => {}
}
});
const chip = document.querySelector('[data-chip-id="f1"]') as HTMLElement;
expect(chip.getAttribute('data-status')).toBe('error');
});
it('calls onSelect with the chip id when clicked', async () => {
const onSelect = vi.fn();
render(FileSwitcherStrip, {
props: {
files: [makeEntry('f1', 'A'), makeEntry('f2', 'B')],
activeId: 'f1',
onSelect,
onRemove: () => {}
}
});
const f2 = document.querySelector('[data-chip-id="f2"]') as HTMLElement;
f2.click();
expect(onSelect).toHaveBeenCalledWith('f2');
});
it('calls onRemove when the remove button is clicked', async () => {
const onRemove = vi.fn();
render(FileSwitcherStrip, {
props: {
files: [makeEntry('f1', 'A'), makeEntry('f2', 'B')],
activeId: 'f1',
onSelect: () => {},
onRemove
}
});
const remove = document.querySelector('[data-remove-id="f1"]') as HTMLElement;
remove.click();
expect(onRemove).toHaveBeenCalledWith('f1');
});
it('renders the active title in the sr-only announcer', async () => {
render(FileSwitcherStrip, {
props: {
files: [makeEntry('f1', 'Ein Brief.pdf'), makeEntry('f2', 'B')],
activeId: 'f1',
onSelect: () => {},
onRemove: () => {}
}
});
const announcer = document.querySelector('[aria-live="polite"]');
expect(announcer?.textContent).toContain('Ein Brief.pdf');
});
});