Addresses three blockers raised in PR #350 review (Felix, Sara, Tobias):
1. Replace all waitForTimeout(400) calls with waitForListbox() which uses
waitForSelector('[role="listbox"]', { state: 'visible' }) — auto-waits
for the debounce to resolve, faster on fast machines and reliable under CI.
2. Remove all conditional if (hasResults) / if (hasDropdown) wrappers.
Tests now use unconditional expect(dropdown).toBeVisible() assertions so
a missing-data condition causes an explicit failure instead of a silent
green run.
3. Replace waitForSelector('[data-hydrated]') with waitForLoadState('networkidle')
in getDocumentEditUrl — the data-hydrated attribute does not exist in the
app markup and would cause a 30s timeout on every test.
4. Extract page: Page type import from @playwright/test and introduce
waitForListbox(page: Page) helper to avoid repeating the selector pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the missing 'ArrowDown from last wraps to first option' test to
close the asymmetric coverage gap noted by Sara (QA) in the review of
PR #350. The ArrowUp backward-wrap test already existed; this test
verifies the % modulo wrap works in the forward direction too.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The dropdown was clipped by parent containers using overflow, transform,
or stacking context via shadow-sm + z-index combinations. Adopts the same
fixed-position strategy as PersonMultiSelect: binds to the input element,
computes position via getBoundingClientRect(), and registers svelte:window
scroll/resize listeners to keep it current.
Also adds full ARIA combobox pattern (role=combobox, aria-expanded,
aria-haspopup, aria-controls, aria-activedescendant) and keyboard
navigation (ArrowDown/Up, Enter, Escape) matching TagInput's reference
implementation.
Removes the now-dead z-30/z-10 z-index workarounds from ConversationFilterBar.
Closes#343
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>