diff --git a/frontend/src/lib/components/TagInput.svelte.spec.ts b/frontend/src/lib/components/TagInput.svelte.spec.ts index 73f51d45..a0c37b6d 100644 --- a/frontend/src/lib/components/TagInput.svelte.spec.ts +++ b/frontend/src/lib/components/TagInput.svelte.spec.ts @@ -3,7 +3,7 @@ import { cleanup, render } from 'vitest-browser-svelte'; import { page, userEvent } from 'vitest/browser'; import TagInput, { type Tag } from './TagInput.svelte'; -const waitForDebounce = () => new Promise((r) => setTimeout(r, 350)); +const waitForFetch = () => new Promise((r) => setTimeout(r, 50)); const tick = () => new Promise((r) => setTimeout(r, 0)); function mockFetchWithTagObjects(tags: Tag[]) { @@ -168,7 +168,7 @@ describe('TagInput – autocomplete', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Fa'); - await waitForDebounce(); + await waitForFetch(); await expect.element(page.getByRole('option', { name: 'Familie' })).toBeInTheDocument(); await expect.element(page.getByRole('option', { name: 'Freunde' })).toBeInTheDocument(); await page.screenshot({ path: 'test-results/screenshots/tag-input-suggestions.png' }); @@ -179,7 +179,7 @@ describe('TagInput – autocomplete', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('F'); - await waitForDebounce(); + await waitForFetch(); expect(fetch).not.toHaveBeenCalled(); }); @@ -188,7 +188,7 @@ describe('TagInput – autocomplete', () => { render(TagInput, { tags: [{ name: 'Familie' }], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Fr'); - await waitForDebounce(); + await waitForFetch(); await expect.element(page.getByRole('option', { name: 'Familie' })).not.toBeInTheDocument(); await expect.element(page.getByRole('option', { name: 'Freunde' })).toBeInTheDocument(); }); @@ -198,7 +198,7 @@ describe('TagInput – autocomplete', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Fa'); - await waitForDebounce(); + await waitForFetch(); document.querySelector('[role="option"]')!.click(); await tick(); await expect.element(page.getByText('Familie')).toBeInTheDocument(); @@ -211,7 +211,7 @@ describe('TagInput – autocomplete', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('__'); - await waitForDebounce(); + await waitForFetch(); await userEvent.keyboard('{ArrowDown}'); // index 0 → Aachen await userEvent.keyboard('{ArrowDown}'); // index 1 → Berlin await userEvent.keyboard('{Enter}'); @@ -223,7 +223,7 @@ describe('TagInput – autocomplete', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Fa'); - await waitForDebounce(); + await waitForFetch(); await expect.element(page.getByRole('option', { name: 'Familie' })).toBeInTheDocument(); document.body.click(); await tick(); @@ -238,7 +238,7 @@ describe('TagInput – autocomplete', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('El'); - await waitForDebounce(); + await waitForFetch(); const options = Array.from(document.querySelectorAll('[role="option"]')); const texts = options.map((el) => el.textContent?.replace(/›/g, '').trim() ?? ''); expect(texts.indexOf('Eltern')).toBeLessThan(texts.indexOf('Kind')); @@ -252,7 +252,7 @@ describe('TagInput – autocomplete', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Fa'); - await waitForDebounce(); + await waitForFetch(); await expect.element(page.getByRole('listbox')).toBeInTheDocument(); }); }); @@ -269,7 +269,7 @@ describe('TagInput – tree-aware ordering', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Brief'); - await waitForDebounce(); + await waitForFetch(); const options = Array.from(document.querySelectorAll('[role="option"]')); const texts = options.map((el) => el.textContent?.replace(/›/g, '').trim() ?? ''); expect(texts).toContain('Briefe'); @@ -287,7 +287,7 @@ describe('TagInput – tree-aware ordering', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Hochzeit'); - await waitForDebounce(); + await waitForFetch(); const options = Array.from(document.querySelectorAll('[role="option"]')); const texts = options.map((el) => el.textContent?.replace(/›/g, '').trim() ?? ''); expect(texts.indexOf('Briefe')).toBeLessThan(texts.indexOf('Hochzeit')); @@ -305,7 +305,7 @@ describe('TagInput – tree-aware ordering', () => { render(TagInput, { tags: [], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Hochzeit'); - await waitForDebounce(); + await waitForFetch(); await userEvent.keyboard('{ArrowDown}'); // first item: Briefe (context ancestor) await userEvent.keyboard('{Enter}'); // successful add clears the input; if .tag unwrap is missing, addTag returns early @@ -320,7 +320,7 @@ describe('TagInput – tree-aware ordering', () => { render(TagInput, { tags: [{ id: 'p1', name: 'Briefe' }], allowCreation: true }); const input = page.getByRole('textbox'); await input.fill('Fa'); - await waitForDebounce(); + await waitForFetch(); await expect.element(page.getByRole('option', { name: 'Familienbriefe' })).toBeInTheDocument(); // the already-selected parent must not appear as a suggestion const optionNames = Array.from(document.querySelectorAll('[role="option"]')).map( @@ -356,7 +356,7 @@ describe('TagInput – onTextInput callback', () => { render(TagInput, { tags: [], allowCreation: false, onTextInput }); const input = page.getByRole('textbox'); await input.fill('Ka'); - await waitForDebounce(); + await waitForFetch(); const option = page.getByRole('option', { name: 'Kaufvertrag' }); await option.click(); await expect.poll(() => onTextInput.mock.calls.at(-1)).toEqual(['']);