From d8cca4d87fbce6c8d74091fc8ae459e18bed8d0c Mon Sep 17 00:00:00 2001 From: Marcel Date: Mon, 11 May 2026 17:20:31 +0200 Subject: [PATCH] test(document): rewrite FileSwitcherStrip test with behavioral assertions Replaces 3 setTimeout sleeps with vi.waitFor on document.activeElement during keyboard nav, and converts 2 .not.toThrow smoke tests on the prev/next buttons into no-op assertions: with a single file in the strip the active chip stays selected and onSelect is not invoked. Co-Authored-By: Claude Opus 4.7 --- .../document/FileSwitcherStrip.svelte.test.ts | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/frontend/src/lib/document/FileSwitcherStrip.svelte.test.ts b/frontend/src/lib/document/FileSwitcherStrip.svelte.test.ts index 3defb75a..7490573c 100644 --- a/frontend/src/lib/document/FileSwitcherStrip.svelte.test.ts +++ b/frontend/src/lib/document/FileSwitcherStrip.svelte.test.ts @@ -120,36 +120,43 @@ describe('FileSwitcherStrip', () => { expect(announcer?.textContent).toContain('Ein Brief.pdf'); }); - it('clicking prev button does not throw with no scroll target available', async () => { + it('prev button on a single-file strip is a no-op (active chip stays)', async () => { + const onSelect = vi.fn(); render(FileSwitcherStrip, { props: { files: [makeEntry('f1', 'A.pdf')], activeId: 'f1', - onSelect: () => {}, + onSelect, onRemove: () => {} } }); - const prevBtn = Array.from(document.querySelectorAll('button')).find((b) => - /vorherige|prev/i.test(b.getAttribute('aria-label') ?? '') - ) as HTMLButtonElement; - expect(() => prevBtn.click()).not.toThrow(); + await page.getByRole('button', { name: /vorherige datei/i }).click(); + + // The active chip is still f1 and onSelect was not invoked with a different id. + expect(document.querySelector('[data-chip-id="f1"]')?.getAttribute('aria-current')).toBe( + 'true' + ); + expect(onSelect).not.toHaveBeenCalled(); }); - it('clicking next button does not throw', async () => { + it('next button on a single-file strip is a no-op (active chip stays)', async () => { + const onSelect = vi.fn(); render(FileSwitcherStrip, { props: { files: [makeEntry('f1', 'A.pdf')], activeId: 'f1', - onSelect: () => {}, + onSelect, onRemove: () => {} } }); - const nextBtn = Array.from(document.querySelectorAll('button')).find((b) => - /nächste|next/i.test(b.getAttribute('aria-label') ?? '') - ) as HTMLButtonElement; - expect(() => nextBtn.click()).not.toThrow(); + await page.getByRole('button', { name: /nächste datei/i }).click(); + + expect(document.querySelector('[data-chip-id="f1"]')?.getAttribute('aria-current')).toBe( + 'true' + ); + expect(onSelect).not.toHaveBeenCalled(); }); it('navigates with ArrowRight key on focused chip', async () => { @@ -166,8 +173,9 @@ describe('FileSwitcherStrip', () => { f1.focus(); f1.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight', bubbles: true })); - await new Promise((r) => setTimeout(r, 30)); - expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2'); + await vi.waitFor(() => { + expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2'); + }); }); it('navigates with ArrowLeft key on focused chip (wraps around)', async () => { @@ -184,9 +192,10 @@ describe('FileSwitcherStrip', () => { f1.focus(); f1.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft', bubbles: true })); - await new Promise((r) => setTimeout(r, 30)); - // ArrowLeft from index 0 wraps to last (f2) - expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2'); + await vi.waitFor(() => { + // ArrowLeft from index 0 wraps to last (f2). + expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2'); + }); }); it('ArrowDown is treated as ArrowRight (vertical key alias)', async () => { @@ -203,7 +212,8 @@ describe('FileSwitcherStrip', () => { f1.focus(); f1.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })); - await new Promise((r) => setTimeout(r, 30)); - expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2'); + await vi.waitFor(() => { + expect(document.activeElement?.getAttribute('data-chip-id')).toBe('f2'); + }); }); });