[READ-ONLY] a fast, modern browser for the npm registry
at main 241 lines 8.5 kB view raw
1import { expect, test } from './test-utils' 2 3test.describe('Compare Page', () => { 4 test('no-dep column renders separately from package columns', async ({ page, goto }) => { 5 await goto('/compare?packages=vue,__no_dependency__', { waitUntil: 'hydration' }) 6 7 const grid = page.locator('.comparison-grid') 8 await expect(grid).toBeVisible({ timeout: 15000 }) 9 10 // Should have the no-dep column with special styling 11 const noDepColumn = grid.locator('.comparison-cell-nodep') 12 await expect(noDepColumn).toBeVisible() 13 14 // The no-dep column should not contain a link 15 await expect(noDepColumn.locator('a')).toHaveCount(0) 16 }) 17 18 test('no-dep column is always last even when packages are added after', async ({ 19 page, 20 goto, 21 }) => { 22 // Start with vue and no-dep 23 await goto('/compare?packages=vue,__no_dependency__', { waitUntil: 'hydration' }) 24 25 const grid = page.locator('.comparison-grid') 26 await expect(grid).toBeVisible({ timeout: 15000 }) 27 28 // Add another package via the input 29 const input = page.locator('#package-search') 30 await input.fill('nuxt') 31 32 // Wait for search results and click on nuxt 33 const nuxtOption = page.locator('button:has-text("nuxt")').first() 34 await expect(nuxtOption).toBeVisible({ timeout: 10000 }) 35 await nuxtOption.click() 36 37 // URL should have no-dep at the end, not in the middle 38 await expect(page).toHaveURL(/packages=vue,nuxt,__no_dependency__/) 39 40 // Verify column order in the grid: vue, nuxt, then no-dep 41 const headerLinks = grid.locator('.comparison-cell-header a.truncate') 42 await expect(headerLinks).toHaveCount(2) 43 await expect(headerLinks.nth(0)).toContainText('vue') 44 await expect(headerLinks.nth(1)).toContainText('nuxt') 45 46 // No-dep should still be visible as the last column 47 const noDepColumn = grid.locator('.comparison-cell-nodep') 48 await expect(noDepColumn).toBeVisible() 49 }) 50}) 51 52test.describe('Search Pages', () => { 53 test('/search?q=vue → keyboard navigation (arrow keys + enter)', async ({ page, goto }) => { 54 await goto('/search?q=vue', { waitUntil: 'hydration' }) 55 56 await expect(page.locator('text=/found \\d+|showing \\d+/i').first()).toBeVisible({ 57 timeout: 15000, 58 }) 59 60 const firstResult = page.locator('[data-result-index="0"]').first() 61 await expect(firstResult).toBeVisible() 62 63 // Global keyboard navigation works regardless of focus 64 // ArrowDown selects the next result 65 await page.keyboard.press('ArrowDown') 66 67 // ArrowUp selects the previous result 68 await page.keyboard.press('ArrowUp') 69 70 // Enter navigates to the selected result 71 // URL is /package/vue or /org/vue or /user/vue. Not /vue 72 await page.keyboard.press('Enter') 73 await expect(page).toHaveURL(/\/(package|org|user)\/vue/) 74 }) 75 76 test('/search?q=vue → "/" focuses the search input from results', async ({ page, goto }) => { 77 await goto('/search?q=vue', { waitUntil: 'hydration' }) 78 79 await expect(page.locator('text=/found \\d+|showing \\d+/i').first()).toBeVisible({ 80 timeout: 15000, 81 }) 82 83 await page.locator('[data-result-index="0"]').first().focus() 84 await page.keyboard.press('/') 85 await expect(page.locator('input[type="search"]')).toBeFocused() 86 }) 87 88 test('/ (homepage) → search, keeps focus on search input', async ({ page, goto }) => { 89 await goto('/', { waitUntil: 'hydration' }) 90 91 const homeSearchInput = page.locator('#home-search') 92 await homeSearchInput.click() 93 await page.keyboard.type('vue') 94 95 // Wait for navigation to /search (debounce is 250ms) 96 await expect(page).toHaveURL(/\/search/, { timeout: 10000 }) 97 98 await expect(page.locator('[data-result-index="0"]').first()).toBeVisible({ 99 timeout: 15000, 100 }) 101 102 // Home search input should be gone (we're on /search now) 103 await expect(homeSearchInput).not.toBeVisible() 104 105 // Header search input should now exist and be focused 106 const headerSearchInput = page.locator('#header-search') 107 await expect(headerSearchInput).toBeVisible() 108 await expect(headerSearchInput).toBeFocused() 109 }) 110 111 test('/settings → search, keeps focus on search input', async ({ page, goto }) => { 112 await goto('/settings', { waitUntil: 'hydration' }) 113 114 const searchInput = page.locator('input[type="search"]') 115 await expect(searchInput).toBeVisible() 116 117 await searchInput.click() 118 await searchInput.fill('vue') 119 120 await expect(page).toHaveURL(/\/search/, { timeout: 10000 }) 121 122 await expect(page.locator('[data-result-index="0"]').first()).toBeVisible({ 123 timeout: 15000, 124 }) 125 126 const headerSearchInput = page.locator('#header-search') 127 await expect(headerSearchInput).toBeFocused() 128 }) 129}) 130 131test.describe('Keyboard Shortcuts', () => { 132 test('"c" navigates to /compare', async ({ page, goto }) => { 133 await goto('/settings', { waitUntil: 'hydration' }) 134 135 await page.keyboard.press('c') 136 137 await expect(page).toHaveURL(/\/compare/) 138 }) 139 140 test('"c" does not navigate when any modifier key is pressed', async ({ page, goto }) => { 141 await goto('/settings', { waitUntil: 'hydration' }) 142 143 await page.keyboard.press('Shift+c') 144 await expect(page).toHaveURL(/\/settings/) 145 await page.keyboard.press('Control+c') 146 await expect(page).toHaveURL(/\/settings/) 147 await page.keyboard.press('Alt+c') 148 await expect(page).toHaveURL(/\/settings/) 149 await page.keyboard.press('Meta+c') 150 await expect(page).toHaveURL(/\/settings/) 151 await page.keyboard.press('ControlOrMeta+Shift+c') 152 await expect(page).toHaveURL(/\/settings/) 153 }) 154 155 test('"c" on package page navigates to /compare with package pre-filled', async ({ 156 page, 157 goto, 158 }) => { 159 await goto('/package/vue', { waitUntil: 'hydration' }) 160 161 await page.keyboard.press('c') 162 163 // Should navigate to /compare with the package in the query 164 await expect(page).toHaveURL(/\/compare\?packages=vue/) 165 }) 166 167 test('"c" does not navigate when search input is focused', async ({ page, goto }) => { 168 await goto('/settings', { waitUntil: 'hydration' }) 169 170 const searchInput = page.locator('#header-search') 171 await searchInput.focus() 172 await expect(searchInput).toBeFocused() 173 174 await page.keyboard.press('c') 175 176 // Should still be on settings, not navigated to compare 177 await expect(page).toHaveURL(/\/settings/) 178 // The 'c' should have been typed into the input 179 await expect(searchInput).toHaveValue('c') 180 }) 181 182 test('"c" on package page does not navigate when any modifier key is pressed', async ({ 183 page, 184 goto, 185 }) => { 186 await goto('/package/vue', { waitUntil: 'hydration' }) 187 188 await page.keyboard.press('Shift+c') 189 await expect(page).toHaveURL(/\/vue/) 190 await page.keyboard.press('Control+c') 191 await expect(page).toHaveURL(/\/vue/) 192 await page.keyboard.press('Alt+c') 193 await expect(page).toHaveURL(/\/vue/) 194 await page.keyboard.press('Meta+c') 195 await expect(page).toHaveURL(/\/vue/) 196 await page.keyboard.press('ControlOrMeta+Shift+c') 197 await expect(page).toHaveURL(/\/vue/) 198 }) 199 200 test('"," navigates to /settings', async ({ page, goto }) => { 201 await goto('/compare', { waitUntil: 'hydration' }) 202 203 await page.keyboard.press(',') 204 205 await expect(page).toHaveURL(/\/settings/) 206 }) 207 208 test('"," does not navigate when any modifier key is pressed', async ({ page, goto }) => { 209 await goto('/settings', { waitUntil: 'hydration' }) 210 211 const searchInput = page.locator('#header-search') 212 await searchInput.focus() 213 await expect(searchInput).toBeFocused() 214 215 await page.keyboard.press('Shift+,') 216 await expect(page).toHaveURL(/\/settings/) 217 await page.keyboard.press('Control+,') 218 await expect(page).toHaveURL(/\/settings/) 219 await page.keyboard.press('Alt+,') 220 await expect(page).toHaveURL(/\/settings/) 221 await page.keyboard.press('Meta+,') 222 await expect(page).toHaveURL(/\/settings/) 223 await page.keyboard.press('ControlOrMeta+Shift+,') 224 await expect(page).toHaveURL(/\/settings/) 225 }) 226 227 test('"," does not navigate when search input is focused', async ({ page, goto }) => { 228 await goto('/compare', { waitUntil: 'hydration' }) 229 230 const searchInput = page.locator('#header-search') 231 await searchInput.focus() 232 await expect(searchInput).toBeFocused() 233 234 await page.keyboard.press(',') 235 236 // Should still be on compare, not navigated to settings 237 await expect(page).toHaveURL(/\/compare/) 238 // The ',' should have been typed into the input 239 await expect(searchInput).toHaveValue(',') 240 }) 241})