-
-
Notifications
You must be signed in to change notification settings - Fork 471
fix: arrow key navigation in search skips keyword buttons #1704
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -73,6 +73,66 @@ test.describe('Search Pages', () => { | |
| await expect(page).toHaveURL(/\/(package|org|user)\/vue/) | ||
| }) | ||
|
|
||
| test('/search?q=vue → ArrowDown navigates only between results, not keyword buttons', async ({ | ||
| page, | ||
| goto, | ||
| }) => { | ||
| await goto('/search?q=vue', { waitUntil: 'hydration' }) | ||
|
|
||
| await expect(page.locator('text=/found \\d+|showing \\d+/i').first()).toBeVisible({ | ||
| timeout: 15000, | ||
| }) | ||
|
|
||
| const firstResult = page.locator('[data-result-index="0"]').first() | ||
| const secondResult = page.locator('[data-result-index="1"]').first() | ||
| await expect(firstResult).toBeVisible() | ||
| await expect(secondResult).toBeVisible() | ||
|
|
||
| // ArrowDown from input focuses the first result | ||
| await page.keyboard.press('ArrowDown') | ||
| await expect(firstResult).toBeFocused() | ||
|
|
||
| // Second ArrowDown focuses the second result (not a keyword button within the first) | ||
| await page.keyboard.press('ArrowDown') | ||
| await expect(secondResult).toBeFocused() | ||
| }) | ||
|
|
||
| test('/search?q=vue → ArrowUp from first result returns focus to search input', async ({ | ||
| page, | ||
| goto, | ||
| }) => { | ||
| await goto('/search?q=vue', { waitUntil: 'hydration' }) | ||
|
|
||
| await expect(page.locator('text=/found \\d+|showing \\d+/i').first()).toBeVisible({ | ||
| timeout: 15000, | ||
| }) | ||
|
|
||
| // Navigate to first result | ||
| await page.keyboard.press('ArrowDown') | ||
| await expect(page.locator('[data-result-index="0"]').first()).toBeFocused() | ||
|
|
||
| // ArrowUp returns to the search input | ||
| await page.keyboard.press('ArrowUp') | ||
| await expect(page.locator('input[type="search"]')).toBeFocused() | ||
| }) | ||
|
Comment on lines
+76
to
+117
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make the “from search input” precondition explicit in both new keyboard tests. At Line 91 and Line 110, the tests assert behaviour “from input”, but they never focus/assert the header search input before the first Suggested hardening diff test('/search?q=vue → ArrowDown navigates only between results, not keyword buttons', async ({
page,
goto,
}) => {
await goto('/search?q=vue', { waitUntil: 'hydration' })
@@
+ const headerSearchInput = page.locator('#header-search')
+ await headerSearchInput.focus()
+ await expect(headerSearchInput).toBeFocused()
+
const firstResult = page.locator('[data-result-index="0"]').first()
const secondResult = page.locator('[data-result-index="1"]').first()
@@
test('/search?q=vue → ArrowUp from first result returns focus to search input', async ({
page,
goto,
}) => {
await goto('/search?q=vue', { waitUntil: 'hydration' })
@@
+ const headerSearchInput = page.locator('#header-search')
+ await headerSearchInput.focus()
+ await expect(headerSearchInput).toBeFocused()
+
// Navigate to first result
await page.keyboard.press('ArrowDown')
await expect(page.locator('[data-result-index="0"]').first()).toBeFocused()
@@
// ArrowUp returns to the search input
await page.keyboard.press('ArrowUp')
- await expect(page.locator('input[type="search"]')).toBeFocused()
+ await expect(headerSearchInput).toBeFocused()
}) |
||
|
|
||
| test('/search?q=vue → Escape returns focus to search input', async ({ page, goto }) => { | ||
| await goto('/search?q=vue', { waitUntil: 'hydration' }) | ||
|
|
||
| await expect(page.locator('text=/found \\d+|showing \\d+/i').first()).toBeVisible({ | ||
| timeout: 15000, | ||
| }) | ||
|
|
||
| // Navigate into results | ||
| await page.keyboard.press('ArrowDown') | ||
| await page.keyboard.press('ArrowDown') | ||
| await expect(page.locator('[data-result-index="1"]').first()).toBeFocused() | ||
|
|
||
| // Escape returns to the search input | ||
| await page.keyboard.press('Escape') | ||
| await expect(page.locator('input[type="search"]')).toBeFocused() | ||
| }) | ||
|
|
||
| test('/search?q=vue → "/" focuses the search input from results', async ({ page, goto }) => { | ||
| await goto('/search?q=vue', { waitUntil: 'hydration' }) | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Escape is handled too globally.
At Line 469,
preventDefault()runs for every Escape press on the page, even outside result navigation. This can interfere with expected Escape behaviour in other UI contexts (e.g. overlays/popovers). Scope this branch to when a result/suggestion item is focused (or when search navigation state is active).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this a fair point @serhalp?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, we should have some checks here, since Escape is used for dismissing popover menus and dropdowns and, eventually, tooltips.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, FWIW, the / key also returns the focus to the search box. Do we need an additional key?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, friends! I was a bit overeager here. Removed the new
Escbinding.