Skip to content

Testing

E2E Tests (Playwright)

~94 tests in tests/e2e/ running sequentially (1 worker, shared database).

Test Files

FileTestsTagsCoverage
auth.spec.ts7@smokeSetup form, login, logout, session persistence
inbox.spec.ts16@smokeList, search, pagination, metadata picker (11 fields), approve, delete
library.spec.ts15@smokeGrid/list view, filters, search, pagination, detail page, covers, downloads
home.spec.ts7@smokeDashboard stats, currently reading, recently added
reading-status.spec.ts8@smokeReading status computation and display
book-progress.spec.ts8@smokeBook progress tracking and updates
hardcover.spec.ts7@smokeHardcover sync integration
ingestion.spec.ts2@slow @externalFull EPUB/PDF pipeline: detect → parse → review → approve → library
opds.spec.ts9@smokeFeed structure, search, covers, downloads, Basic auth
settings.spec.ts4@smokeServer health, job queues, paths
errors.spec.ts5@smokeAuth redirects, invalid keys, conflicts, network errors
stats.spec.ts6@smokeBooks finished, streaks, daily activity, genre distribution

Tags

TagCountMeaning
@smoke~87Critical paths — runs on PRs
@slow~7File processing / queue waits
@external~7Requires external API access

Running Tests

Docker mode (recommended):

bash
./scripts/test-e2e.sh                       # all tests
./scripts/test-e2e.sh --grep @smoke         # smoke only
./scripts/test-e2e.sh tests/e2e/auth.spec.ts  # single file

Dev-server mode (faster iteration):

bash
docker compose -f docker-compose.test.yml up -d --wait
cp .env.test.example .env.test
pnpm run test:e2e                              # all tests
cd tests/e2e && pnpm exec playwright test --grep @smoke   # smoke only
cd tests/e2e && pnpm exec playwright test --ui            # interactive Playwright UI

Infrastructure

FilePurpose
playwright.config.tsConfig: 1 worker, retries in CI, reporters, webServer auto-start
global-setup.tsWaits for API health, resets DB (delete all rows), seeds API key
auth.setup.tsLogs in via BFF, saves session cookie to .auth/user.json
fixtures.tsCustom fixtures: authedPage (pre-authenticated page)
helpers/index.tsseedOrganizedBook(), deleteAllBooks(), waitForJob(), goPath(), etc.

Database Seeding

Tests seed data via direct PostgreSQL queries (not API calls), using the postgres client from helpers/index.ts. Each spec's beforeEach cleans up its own data.

Debugging

  • Screenshots/videos/traces on failure: tests/e2e/test-results/
  • HTML report: tests/e2e/playwright-report/index.html
  • Debug mode: PWDEBUG=1 ./scripts/test-e2e.sh -g "test name"

API Exploration (Bruno)

The bruno/ directory contains a Bruno API collection auto-generated from the OpenAPI spec. It provides a ready-to-use set of all API endpoints for manual testing and exploration.

Opening the Collection

GUI: Open Bruno → Open Collection → select the bruno/ folder → pick the Local environment from the top-right dropdown.

CLI:

bash
bru run --env Local bruno/            # Run all requests
bru run --env Local bruno/library/    # Run a specific folder
bru run --env Local bruno/health/     # Quick health check

Environments

EnvironmentFileBase URL
Localbruno/environments/Local.bruhttp://localhost:3000

Requests use which resolves from the selected environment.

Regenerating the Collection

When API routes change, regenerate the collection from the OpenAPI spec:

bash
pnpm run bruno:import

This runs scripts/bruno-import.sh which:

  1. Starts the Nitro dev server if not already running (DB/Redis not required)
  2. Fetches the OpenAPI spec from /_docs/openapi.json
  3. Imports into bruno/ grouped by OpenAPI tags
  4. Removes internal/test endpoints
  5. Preserves existing environment files

The collection is committed to git so it's available immediately after cloning.

Structure

Requests are organized by OpenAPI tag into folders:

FolderEndpoints
auth/Setup, API key CRUD
books/Approve metadata, delete, get candidates
credentials/Service credential management
dashboard/Dashboard data
events/SSE stream
hardcover/Sync status, trigger sync, sync log
health/Health check
inbox/List, get, upload, rescan, cover images, status
jobs/Queue status, failed jobs, retry
kosync/KoReader sync (auth, progress read/write)
library/List, get, update, covers, downloads, refetch, reorg
opds/OPDS catalog feeds, search, downloads
Reading Status/Status counts, filtered lists
search/Command palette suggestions
settings/Get/update settings
stats/Reading statistics

Unit Tests (Vitest)

  • Root config: vitest.config.ts — excludes services/*/tests/** and tests/e2e/**
  • API service config: services/api/vitest.config.ts — uses nitro-test-utils/config to start Nitro server
  • Run: pnpm run test (root) or cd services/api && vitest run (API only)

Key Unit Test Files

FileCoverage
reading-status.test.tsReading status derivation from KoSync progress
hardcover-client.test.tsHardcover GraphQL API client

Test DB for unit tests uses in-memory PGlite (0.test-db.ts plugin) with mocked BullMQ queues.

CI Pipeline

See ci-cd.md for the full CI workflow. Summary:

  • PRs: @smoke E2E tests only
  • main push: Full E2E suite
  • Test results posted as PR comments