|
1 | 1 | import { expect, test } from '@nuxt/test-utils/playwright' |
2 | 2 |
|
3 | 3 | test.describe('Search Pages', () => { |
| 4 | + // TODO: these tests depend on external npm registry API - we should add data fixtures |
| 5 | + test.describe.configure({ retries: 2 }) |
4 | 6 | test('/search?q=vue → keyboard navigation (arrow keys + enter)', async ({ page, goto }) => { |
5 | | - await goto('/search?q=vue', { waitUntil: 'domcontentloaded' }) |
| 7 | + await goto('/search?q=vue', { waitUntil: 'hydration' }) |
6 | 8 |
|
7 | | - await expect(page.locator('text=/found \\d+/i')).toBeVisible() |
| 9 | + await expect(page.locator('text=/found \\d+|showing \\d+/i').first()).toBeVisible({ |
| 10 | + timeout: 15000, |
| 11 | + }) |
8 | 12 |
|
9 | 13 | const firstResult = page.locator('[data-result-index="0"]').first() |
10 | 14 | await expect(firstResult).toBeVisible() |
11 | 15 |
|
12 | | - const searchInput = page.locator('input[type="search"]') |
13 | | - |
14 | | - // ArrowDown changes visual selection but keeps focus in input |
| 16 | + // Global keyboard navigation works regardless of focus |
| 17 | + // ArrowDown selects the next result |
15 | 18 | await page.keyboard.press('ArrowDown') |
16 | | - await expect(searchInput).toBeFocused() |
17 | 19 |
|
18 | | - // ArrowUp goes back to first result |
| 20 | + // ArrowUp selects the previous result |
19 | 21 | await page.keyboard.press('ArrowUp') |
20 | | - await expect(searchInput).toBeFocused() |
21 | 22 |
|
22 | | - // First result is selected, Enter navigates to it |
| 23 | + // Enter navigates to the selected result |
23 | 24 | // URL is /vue not /package/vue (cleaner URLs) |
24 | 25 | await page.keyboard.press('Enter') |
25 | 26 | await expect(page).toHaveURL(/\/vue/) |
26 | 27 | }) |
27 | 28 |
|
28 | 29 | test('/search?q=vue → "/" focuses the search input from results', async ({ page, goto }) => { |
29 | | - await goto('/search?q=vue', { waitUntil: 'domcontentloaded' }) |
| 30 | + await goto('/search?q=vue', { waitUntil: 'hydration' }) |
30 | 31 |
|
31 | | - await expect(page.locator('text=/found \\d+/i')).toBeVisible() |
| 32 | + await expect(page.locator('text=/found \\d+|showing \\d+/i').first()).toBeVisible({ |
| 33 | + timeout: 15000, |
| 34 | + }) |
32 | 35 |
|
33 | 36 | await page.locator('[data-result-index="0"]').first().focus() |
34 | 37 | await page.keyboard.press('/') |
35 | 38 | await expect(page.locator('input[type="search"]')).toBeFocused() |
36 | 39 | }) |
37 | 40 |
|
| 41 | + test('/ (homepage) → search, keeps focus on search input', async ({ page, goto }) => { |
| 42 | + await goto('/', { waitUntil: 'hydration' }) |
| 43 | + |
| 44 | + const homeSearchInput = page.locator('#home-search') |
| 45 | + await homeSearchInput.click() |
| 46 | + await page.keyboard.type('vue') |
| 47 | + |
| 48 | + // Wait for navigation to /search (debounce is 250ms) |
| 49 | + await expect(page).toHaveURL(/\/search/, { timeout: 10000 }) |
| 50 | + |
| 51 | + await expect(page.locator('[data-result-index="0"]').first()).toBeVisible({ timeout: 15000 }) |
| 52 | + |
| 53 | + // Home search input should be gone (we're on /search now) |
| 54 | + await expect(homeSearchInput).not.toBeVisible() |
| 55 | + |
| 56 | + // Header search input should now exist and be focused |
| 57 | + const headerSearchInput = page.locator('#header-search') |
| 58 | + await expect(headerSearchInput).toBeVisible() |
| 59 | + await expect(headerSearchInput).toBeFocused() |
| 60 | + }) |
| 61 | + |
38 | 62 | test('/settings → search, keeps focus on search input', async ({ page, goto }) => { |
39 | | - await goto('/settings', { waitUntil: 'domcontentloaded' }) |
| 63 | + await goto('/settings', { waitUntil: 'hydration' }) |
40 | 64 |
|
41 | 65 | const searchInput = page.locator('input[type="search"]') |
| 66 | + await expect(searchInput).toBeVisible() |
| 67 | + |
| 68 | + await searchInput.click() |
42 | 69 | await searchInput.fill('vue') |
43 | 70 |
|
44 | | - await page.waitForURL(/\/search/) |
| 71 | + await expect(page).toHaveURL(/\/search/, { timeout: 10000 }) |
45 | 72 |
|
46 | | - await expect(page.locator('text=/found \\d+/i')).toBeVisible() |
| 73 | + await expect(page.locator('[data-result-index="0"]').first()).toBeVisible({ timeout: 15000 }) |
47 | 74 |
|
48 | | - await expect(searchInput).toBeFocused() |
| 75 | + const headerSearchInput = page.locator('#header-search') |
| 76 | + await expect(headerSearchInput).toBeFocused() |
49 | 77 | }) |
50 | 78 | }) |
0 commit comments