Restructuring frontend tests & add Vitest projects#611
Conversation
Restructure the frontend test layout and test tooling: move many __tests__ into organized fe/src/test/* folders, add test factories, mocks, stubs and utility helpers, and remove the checked-in fe/eslint-report.json. Add a Vitest multi-project entry (fe/vitest.projects.ts) and a test-structure guard script (fe/scripts/check-test-structure.mjs), update vitest and TypeScript configs and Vite settings, and remove the old vitest.no-setup.config.ts. Update fe/README.md with guidance on running Vitest projects and the new frontend verification gate, add npm verify scripts in package.json, and adjust .gitignore entries to ignore eslint-report.json. Miscellaneous edits: VS Code file nesting settings and other small config tweaks to support the new test layout.
Change Cypress baseUrl and centralize API intercepts by adding a support helper. Updated fe/cypress.config.ts to use port 4173. Added fe/cypress/support/api.ts exporting apiPath() (wraps endpoints with /api/v*) and stubAppShellApi() to centralize common stubs. Refactored multiple e2e specs to use apiPath for intercept URLs and to use stubAppShellApi in settings, plus minor test cleanup/formatting and consistent mock response shapes. Affected files: cypress.config.ts, support/api.ts, and several tests under fe/cypress/e2e (file-naming-patterns.cy.ts, hardlink-move-flow.cy.ts, move-flow.cy.ts, settings-root-folders.cy.ts, settings.cy.ts).
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Reorganizes the frontend testing/tooling setup around Vitest projects, colocated test/ folders, shared test utilities, and updated Cypress e2e stubs for versioned API routes.
Changes:
- Added Vitest project-based configuration (node/jsdom/smoke) with coverage configuration and a test structure guard script.
- Introduced shared frontend test utilities (mounting helpers, waits, storage mocks, factories, stubs, API/SignalR mocks).
- Updated Cypress e2e tests to use a version-aware API path helper and aligned baseUrl/verification scripts.
Reviewed changes
Copilot reviewed 89 out of 116 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| scripts/lint-staged.mjs | Runs frontend lint/format via local node bin paths to improve Windows/Git Bash reliability. |
| package.json | Adds a root convenience script for running the frontend verification gate. |
| fe/vitest.projects.ts | Defines Vitest projects and globs for runtime separation. |
| fe/vitest.no-setup.config.ts | Removes the legacy “no setup” Vitest config. |
| fe/vitest.config.ts | Switches to project-based Vitest config and adds unit coverage settings/thresholds. |
| fe/vite.config.ts | Tweaks production-only build minify/esbuild options. |
| fe/tsconfig.vitest.json | Updates test TS includes and library targets for Vitest typechecking. |
| fe/tsconfig.node.json | Updates Node TS includes (adds vitest projects/config patterns; removes stale configs). |
| fe/tsconfig.app.json | Excludes new colocated src/**/test/**/* paths from app TS build. |
| fe/src/test/utils/wait.ts | Adds shared async helpers (delay/flush/waitFor/deferred). |
| fe/src/test/utils/storage.ts | Adds a Vitest storage mock helper. |
| fe/src/test/utils/mount.ts | Adds reusable mount helpers for Pinia/router + stubs merging. |
| fe/src/test/stubs.ts | Adds shared component stubs (modal/base/app). |
| fe/src/test/mocks/signalr.ts | Adds a SignalR service mock factory. |
| fe/src/test/mocks/api.ts | Adds API service/module mock factories. |
| fe/src/test/factories/settings.ts | Adds settings factory helper. |
| fe/src/test/factories/searchResult.ts | Adds SearchResult factory helper. |
| fe/src/test/factories/rootFolder.ts | Adds RootFolder factory helper. |
| fe/src/test/factories/qualityProfile.ts | Adds QualityProfile factory helper. |
| fe/src/test/factories/indexer.ts | Adds Indexer factory helper. |
| fe/src/test/factories/downloadClient.ts | Adds download client configuration factory helper. |
| fe/src/test/factories/download.ts | Adds Download factory helper. |
| fe/src/test/factories/audiobook.ts | Adds Audiobook factory helper. |
| fe/src/test/README.md | Documents the new frontend test layout and rules. |
| fe/src/components/base/BrandLogo.vue | Makes logo source a bound constant (helps tests/static asset handling). |
| fe/src/tests/useScore.spec.ts | Refactors to use shared SearchResult factory. |
| fe/src/tests/useScore.rejection.spec.ts | Refactors to use shared SearchResult factory. |
| fe/src/tests/test-setup.ts | Removes the global Vitest setup file and its centralized mocks/polyfills. |
| fe/src/tests/startupConfigCache.test.ts | Refactors concurrency test to use shared deferred helper. |
| fe/src/tests/sessionTokenStorage.test.ts | Uses explicit storage mock + module reset; switches to async import. |
| fe/src/tests/searchResultHelpers.spec.ts | Adjusts casting to align with new lint rules for tests. |
| fe/src/tests/searchResultFormatting.spec.ts | Adjusts casting to align with new lint rules for tests. |
| fe/src/tests/sanity.spec.js | Removes legacy sanity test (JS). |
| fe/src/tests/sanity.js | Removes legacy sanity test (JS). |
| fe/src/tests/libraryImport.store.spec.ts | Uses shared flush helper and adjusts test casts. |
| fe/src/tests/import-activity.spec.ts | Updates path reference for ActivityView compile check. |
| fe/src/tests/grabsSortable.spec.ts | Uses shared stubs/factories/wait helpers; improves polling logic. |
| fe/src/tests/debug_AddNew.spec.ts | Removes debug placeholder spec. |
| fe/src/tests/customFilterEvaluator.spec.ts | Adjusts casting style for tests. |
| fe/src/tests/audiobook-detailview.signalr.spec.ts | Uses shared delay helper; adjusts SignalR callback injection. |
| fe/src/tests/api.removeFromLibrary.spec.ts | Adjusts fetch call typing/casting. |
| fe/src/tests/api.ensureImageCached.spec.ts | Switches to alias imports + unmock; adjusts casting. |
| fe/src/tests/api.downloadLogs.spec.ts | Switches to alias imports for unmock + dynamic import. |
| fe/src/tests/api.csrf-retry.spec.ts | Tightens apiService shape and normalizes casting. |
| fe/src/tests/api.advancedSearch.spec.ts | Adjusts fetch call typing/casting. |
| fe/src/tests/WantedView.spec.ts | Uses shared delay helper; adjusts store typing casts. |
| fe/src/tests/SettingsView.spec.ts | Refactors to shared mount helpers and introduces mocked auth store. |
| fe/src/tests/SearchResultCard.spec.ts | Adjusts casting style for tests. |
| fe/src/tests/RootFoldersSettings.spec.ts | Uses deferred + flush helpers; normalizes API spy typing. |
| fe/src/tests/RenamePreviewModal.spec.ts | Adds modal stubs and local API mock for test stability. |
| fe/src/tests/QualityProfilesTab.spec.ts | Uses vi.doMock + flush helper; adds base stubs. |
| fe/src/tests/NotificationsTab.spec.ts | Adds modal stubs; normalizes casts. |
| fe/src/tests/ManualSearchModal.spec.ts | Centralizes modal stubs; swaps ad-hoc waits for shared delay helper. |
| fe/src/tests/LibraryImportSearchModal.spec.ts | Adds modal stubs and uses shared flush helper. |
| fe/src/tests/LibraryImportFooter.spec.ts | Uses shared flush helper and normalizes casts. |
| fe/src/tests/IndexersTab.spec.ts | Adds modal stubs + flush helper; normalizes vi.doMock typing. |
| fe/src/tests/IndexerFormModal.spec.ts | Adjusts casting style for tests. |
| fe/src/tests/EditAudiobookModal.relativePath.spec.ts | Uses shared delay helper; simplifies casts. |
| fe/src/tests/EditAudiobookModal.moveOptions.spec.ts | Adds modal stubs and replaces sleeps with shared delay helper. |
| fe/src/tests/DownloadsView.spec.ts | Uses shared delay helper. |
| fe/src/tests/DownloadClientsTab.spec.ts | Uses factory helper; normalizes vi.doMock typing/casts. |
| fe/src/tests/DownloadClientFormModal.spec.ts | Switches to hoisted API mock and adds modal stubs. |
| fe/src/tests/CollectionView.spec.ts | Uses shared flush helper; normalizes global stubs and casts. |
| fe/src/tests/AudiobooksView.spec.ts | Adds explicit browser/storage mocks; improves cleanup across tests. |
| fe/src/tests/AudiobookDetailView.spec.ts | Uses shared delay/flush helpers; normalizes casts. |
| fe/src/tests/AppActivityBadge.spec.ts | Uses shared delay helper; normalizes casts. |
| fe/src/tests/ApiKeyControl.spec.ts | Uses shared flush helper; normalizes navigator clipboard mocking. |
| fe/src/tests/AddNewView.spec.ts | Adds explicit API/SignalR mocks; uses storage + delay helpers. |
| fe/src/tests/AddLibraryModal.relativePath.spec.ts | Adds modal stubs and uses shared delay helper. |
| fe/src/tests/AddLibraryModal.editableMetadata.spec.ts | Adds modal stubs for consistent modal rendering. |
| fe/src/tests/AddLibraryModal.accessibility.spec.ts | Adds modal stubs and uses shared flush helper. |
| fe/src/tests/ActivityView.spec.ts | Uses shared flush helper; normalizes interval mock typing. |
| fe/src/tests/ActivityView.mobile.spec.ts | Uses shared delay helper; normalizes interval mock typing. |
| fe/scripts/check-test-structure.mjs | Adds a guard script enforcing colocated tests and config rules. |
| fe/package.json | Adds frontend verify gate, coverage script, structure lint, and Vitest project runs. |
| fe/eslint.config.ts | Updates Vitest lint file globs and relaxes no-explicit-any for tests. |
| fe/cypress/support/api.ts | Adds apiPath + shared app shell API stubs for e2e tests. |
| fe/cypress/e2e/settings.cy.ts | Updates Settings e2e stubs to version-aware API paths and current UI fields. |
| fe/cypress/e2e/settings-root-folders.cy.ts | Updates Root Folders e2e to version-aware API paths. |
| fe/cypress/e2e/move-flow.cy.ts | Updates move flow e2e to version-aware API paths. |
| fe/cypress/e2e/hardlink-move-flow.cy.ts | Updates hardlink/copy move flow e2e to version-aware API paths. |
| fe/cypress/e2e/file-naming-patterns.cy.ts | Updates file naming e2e coverage to version-aware API paths. |
| fe/cypress.config.ts | Aligns Cypress baseUrl to port 4173 (matches e2e scripts). |
| fe/README.md | Updates documentation for Vitest projects and the frontend verify script. |
| fe/.vscode/settings.json | Removes Playwright nesting references and updates config nesting. |
| fe/.gitignore | Updates ignored tooling outputs (eslint report) in frontend. |
| CONTRIBUTING.md | Updates contributor instructions to run the new frontend verification gate. |
| .husky/pre-push | Runs version sync + backend format + FE typecheck + FE tests with Node PATH workaround. |
| .husky/pre-commit | Replaces npm wrapper invocation with node script + adds enforcement checks. |
| .gitignore | Updates ignored tooling outputs (eslint report) at repo root. |
Files not reviewed (1)
- fe/package-lock.json: Language not supported
Comments suppressed due to low confidence (2)
fe/src/test/utils/storage.ts:1
installStorageMock()referenceswindowunconditionally, which will throw aReferenceErrorif this helper is ever imported/used from a node-environment Vitest project (unit-node). Guard theseObject.defineProperty(window, ...)calls behind atypeof window !== 'undefined'check (and rely onvi.stubGlobalfor non-DOM environments), so the helper is safe in both runtimes.
fe/src/test/utils/mount.ts:1- Swallowing
router.isReady()failures makes test failures harder to debug and can mask navigation/setup problems (tests may proceed with a router that isn’t actually ready). Prefer letting the rejection propagate, or rethrow with additional context so failures are actionable.
| if (fs.existsSync(path.join(srcRoot, '__tests__'))) { | ||
| failures.push('src/__tests__ must not exist; colocate tests in src/**/test/.') | ||
| } |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 93c7c1bd64
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| fi | ||
|
|
||
| echo "Syncing version..." | ||
| node scripts/sync-fe-version-from-csproj.mjs |
There was a problem hiding this comment.
Stop push when version sync mutates tracked files
Running node scripts/sync-fe-version-from-csproj.mjs inside the pre-push hook can rewrite package.json/lockfiles, but the hook continues without checking for new diffs. When versions are out of sync, this means the push sends commits that were not validated against the exact files being pushed, and it also leaves the developer’s worktree dirty after a successful push. The hook should fail (or require recommit) if sync changes tracked files so the validated content matches the pushed commit.
Useful? React with 👍 / 👎.
Add esbuild@0.28.0 to fe/package.json as a dev dependency.
Remove esbuild from front-end dependencies and update Vite config to use the 'oxc' minifier. Add production minification options (drop console/debugger, mangle and codegen) via Rollup output config and keep sourcemaps enabled for bundle analysis. Also tidy the visualizer plugin cast/comment to avoid TypeScript signature mismatches.
Introduce a reusable SignalR test mock and an opt-in Vitest setup file for SignalR. Adds src/test/mocks/signalr.ts with a callback registry, emit/reset helpers and a signalRServiceMock, and a setup file src/test/setup/signalr.ts that auto-mocks the real service and resets the mock after each test. Update a spec to use the new mock (remove manual spy/callback plumbing), add the setup file to vitest.config.ts, and extend the test README to document the allowed global mock and guidelines. Also tighten check-test-structure.mjs to only permit the specific setup file and to allow only that setupFiles config, and add a few asset/font entries to .gitignore.
Summary
Reorganizes the frontend test architecture around colocated
test/folders, adds Vitest projects for clearer runtime separation, cleans up shared test utilities, and updates Cypress e2e mocks to match the current versioned API routes.Changes
Added
/api/v*/...e2e route stubs.Changed
src/__tests__layout into colocatedtest/folders.*.node.spec.tsconvention.settings.cy.tsto test the current General Settings UI instead of removed proxy/output-path controls.baseUrlwith the e2e script port4173.Fixed
/api/v1/...app requests.Removed
fe/src/__tests__structure.Testing
npm run verify:frontendnpm run lint:eslintnode node_modules/typescript/bin/tsc -p cypress/tsconfig.json --noEmitnode node_modules/cypress/bin/cypress verifycypress/e2e/settings.cy.ts./.husky/pre-commit