|
1 | 1 | import { test, expect } from './setup/coverage.js' |
2 | 2 | import { fixtureData } from './fixtures/index.js' |
3 | 3 | import { files, explore, dismissImportNotification } from './setup/locators.js' |
| 4 | +import { selectViewMode, toggleSearchFilter } from '../helpers/grid' |
4 | 5 | import all from 'it-all' |
5 | 6 | import filesize from 'filesize' |
6 | 7 | import * as kuboRpcModule from 'kubo-rpc-client' |
@@ -297,4 +298,118 @@ test.describe('Files screen', () => { |
297 | 298 | // confirm navigation back to files root |
298 | 299 | await page.waitForURL('/#/files') |
299 | 300 | }) |
| 301 | + |
| 302 | + test.describe('Search filter', () => { |
| 303 | + // inline CIDs for small text content (no network needed) |
| 304 | + const orangeCid = 'bafkqaddjnzzxazldoqwxizltoq' |
| 305 | + const appleCid = 'bafkqac3imvwgy3zao5xxe3de' |
| 306 | + const orangeFile = 'search-orange.txt' |
| 307 | + const appleFile = 'search-apple.txt' |
| 308 | + |
| 309 | + /** |
| 310 | + * Import a file via "Add by path" using an inline CID. |
| 311 | + */ |
| 312 | + async function importByPath (page, cid, filename) { |
| 313 | + await files.importButton(page).click() |
| 314 | + await expect(files.addByPathOption(page)).toBeVisible() |
| 315 | + await files.addByPathOption(page).click() |
| 316 | + |
| 317 | + const pathInput = files.dialogInput(page, 'path') |
| 318 | + await expect(pathInput).toBeVisible() |
| 319 | + await pathInput.fill(`/ipfs/${cid}`) |
| 320 | + await files.dialogInput(page, 'name').fill(filename) |
| 321 | + await page.keyboard.press('Enter') |
| 322 | + |
| 323 | + // wait for dialog to close |
| 324 | + await expect(pathInput).not.toBeVisible({ timeout: 10000 }) |
| 325 | + } |
| 326 | + |
| 327 | + test.beforeEach(async ({ page }) => { |
| 328 | + test.slow() |
| 329 | + |
| 330 | + // import two files with distinct names |
| 331 | + await importByPath(page, orangeCid, orangeFile) |
| 332 | + await dismissImportNotification(page) |
| 333 | + await importByPath(page, appleCid, appleFile) |
| 334 | + await dismissImportNotification(page) |
| 335 | + |
| 336 | + // verify both files are visible before each test |
| 337 | + await expect(page.getByTestId('file-row').filter({ hasText: orangeFile })).toBeVisible({ timeout: 30000 }) |
| 338 | + await expect(page.getByTestId('file-row').filter({ hasText: appleFile })).toBeVisible({ timeout: 30000 }) |
| 339 | + }) |
| 340 | + |
| 341 | + test('search is hidden by default', async ({ page }) => { |
| 342 | + await expect(files.searchInput(page)).not.toBeVisible() |
| 343 | + |
| 344 | + await files.searchToggle(page).click() |
| 345 | + await expect(files.searchInput(page)).toBeVisible() |
| 346 | + }) |
| 347 | + |
| 348 | + test('filter by name in list view', async ({ page }) => { |
| 349 | + await selectViewMode(page, 'list') |
| 350 | + await toggleSearchFilter(page, true) |
| 351 | + |
| 352 | + await files.searchInput(page).fill('orange') |
| 353 | + |
| 354 | + // only the orange file should be visible |
| 355 | + await expect(page.getByTestId('file-row').filter({ hasText: orangeFile })).toBeVisible() |
| 356 | + await expect(page.getByTestId('file-row').filter({ hasText: appleFile })).not.toBeVisible() |
| 357 | + |
| 358 | + // filtered count should show "1 /" |
| 359 | + await expect(page.getByText(/^1\s*\/\s*\d+$/)).toBeVisible() |
| 360 | + }) |
| 361 | + |
| 362 | + test('filter by CID in list view', async ({ page }) => { |
| 363 | + await selectViewMode(page, 'list') |
| 364 | + await toggleSearchFilter(page, true) |
| 365 | + |
| 366 | + // get the CID from the orange file row |
| 367 | + const orangeRow = page.getByTestId('file-row').filter({ hasText: orangeFile }) |
| 368 | + const cidText = await orangeRow.locator('div.monospace').textContent() |
| 369 | + // use last 10 chars of the CID to avoid shared prefix between inline CIDs |
| 370 | + const trimmed = cidText.trim() |
| 371 | + const cidFragment = trimmed.slice(-10) |
| 372 | + |
| 373 | + await files.searchInput(page).fill(cidFragment) |
| 374 | + |
| 375 | + await expect(page.getByTestId('file-row').filter({ hasText: orangeFile })).toBeVisible() |
| 376 | + await expect(page.getByTestId('file-row').filter({ hasText: appleFile })).not.toBeVisible() |
| 377 | + }) |
| 378 | + |
| 379 | + test('filter by name in grid view', async ({ page }) => { |
| 380 | + await selectViewMode(page, 'grid') |
| 381 | + await toggleSearchFilter(page, true) |
| 382 | + |
| 383 | + await files.searchInput(page).fill('apple') |
| 384 | + |
| 385 | + // only the apple file should be visible |
| 386 | + await expect(files.gridFileByName(page, appleFile)).toBeVisible() |
| 387 | + await expect(files.gridFileByName(page, orangeFile)).not.toBeVisible() |
| 388 | + }) |
| 389 | + |
| 390 | + test('hiding search clears filter', async ({ page }) => { |
| 391 | + await selectViewMode(page, 'list') |
| 392 | + await toggleSearchFilter(page, true) |
| 393 | + |
| 394 | + await files.searchInput(page).fill('orange') |
| 395 | + // only orange visible |
| 396 | + await expect(page.getByTestId('file-row').filter({ hasText: appleFile })).not.toBeVisible() |
| 397 | + |
| 398 | + // hide the search filter |
| 399 | + await toggleSearchFilter(page, false) |
| 400 | + |
| 401 | + await expect(files.searchInput(page)).not.toBeVisible() |
| 402 | + // both files should be visible again |
| 403 | + await expect(page.getByTestId('file-row').filter({ hasText: orangeFile })).toBeVisible() |
| 404 | + await expect(page.getByTestId('file-row').filter({ hasText: appleFile })).toBeVisible() |
| 405 | + }) |
| 406 | + |
| 407 | + test('no matches message', async ({ page }) => { |
| 408 | + await toggleSearchFilter(page, true) |
| 409 | + |
| 410 | + await files.searchInput(page).fill('nonexistent-file-xyz') |
| 411 | + |
| 412 | + await expect(page.getByText('No files match your search')).toBeVisible() |
| 413 | + }) |
| 414 | + }) |
300 | 415 | }) |
0 commit comments