fix(picker): honest combobox — keyboard navigation, listbox roles, no-results state
The input declared role=combobox + aria-autocomplete=list while arrow keys did nothing (WCAG 4.1.2). Wired the useTypeahead activeIndex the same way PersonTypeahead does: ArrowUp/Down cycle, Enter/Space select, Escape closes, aria-activedescendant tracks the active option; the list is a real listbox with option roles again (the interim role downgrade is reverted). Zero hits now render a 'Keine Treffer' row instead of silently vanishing, aria-expanded matches the visible state, and the hook sets loading at setQuery so the debounce window can't read as 'no results'. DocumentMultiSelect renders the shared error state too. _uid counter replaced with $props.id(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import { cleanup, render } from 'vitest-browser-svelte';
|
||||
import { page, userEvent } from 'vitest/browser';
|
||||
import DocumentMultiSelect from './DocumentMultiSelect.svelte';
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
|
||||
const waitForDebounce = () => new Promise((r) => setTimeout(r, 350));
|
||||
|
||||
@@ -124,6 +125,28 @@ describe('DocumentMultiSelect — search and select', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('DocumentMultiSelect — search failure', () => {
|
||||
it('shows an error row when the search request fails instead of looking like "no results"', async () => {
|
||||
vi.stubGlobal(
|
||||
'fetch',
|
||||
vi.fn().mockResolvedValue({
|
||||
ok: false,
|
||||
status: 500,
|
||||
json: vi.fn().mockResolvedValue({ code: 'INTERNAL_ERROR' })
|
||||
})
|
||||
);
|
||||
|
||||
render(DocumentMultiSelect);
|
||||
|
||||
await userEvent.fill(page.getByPlaceholder('Dokument suchen…'), 'Eug');
|
||||
await waitForDebounce();
|
||||
|
||||
const alert = page.getByRole('alert');
|
||||
await expect.element(alert).toBeInTheDocument();
|
||||
await expect.element(alert).toHaveTextContent(m.comp_typeahead_error());
|
||||
});
|
||||
});
|
||||
|
||||
describe('DocumentMultiSelect — remove', () => {
|
||||
it('removes a chip when its × button is clicked', async () => {
|
||||
render(DocumentMultiSelect, {
|
||||
|
||||
Reference in New Issue
Block a user