Appearance
Testing
E2E Tests (Playwright)
~94 tests in tests/e2e/ running sequentially (1 worker, shared database).
Test Files
| File | Tests | Tags | Coverage |
|---|---|---|---|
auth.spec.ts | 7 | @smoke | Setup form, login, logout, session persistence |
inbox.spec.ts | 16 | @smoke | List, search, pagination, metadata picker (11 fields), approve, delete |
library.spec.ts | 15 | @smoke | Grid/list view, filters, search, pagination, detail page, covers, downloads |
home.spec.ts | 7 | @smoke | Dashboard stats, currently reading, recently added |
reading-status.spec.ts | 8 | @smoke | Reading status computation and display |
book-progress.spec.ts | 8 | @smoke | Book progress tracking and updates |
hardcover.spec.ts | 7 | @smoke | Hardcover sync integration |
ingestion.spec.ts | 2 | @slow @external | Full EPUB/PDF pipeline: detect → parse → review → approve → library |
opds.spec.ts | 9 | @smoke | Feed structure, search, covers, downloads, Basic auth |
settings.spec.ts | 4 | @smoke | Server health, job queues, paths |
errors.spec.ts | 5 | @smoke | Auth redirects, invalid keys, conflicts, network errors |
stats.spec.ts | 6 | @smoke | Books finished, streaks, daily activity, genre distribution |
Tags
| Tag | Count | Meaning |
|---|---|---|
@smoke | ~87 | Critical paths — runs on PRs |
@slow | ~7 | File processing / queue waits |
@external | ~7 | Requires 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 fileDev-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 UIInfrastructure
| File | Purpose |
|---|---|
playwright.config.ts | Config: 1 worker, retries in CI, reporters, webServer auto-start |
global-setup.ts | Waits for API health, resets DB (delete all rows), seeds API key |
auth.setup.ts | Logs in via BFF, saves session cookie to .auth/user.json |
fixtures.ts | Custom fixtures: authedPage (pre-authenticated page) |
helpers/index.ts | seedOrganizedBook(), 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 checkEnvironments
| Environment | File | Base URL |
|---|---|---|
| Local | bruno/environments/Local.bru | http://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:importThis runs scripts/bruno-import.sh which:
- Starts the Nitro dev server if not already running (DB/Redis not required)
- Fetches the OpenAPI spec from
/_docs/openapi.json - Imports into
bruno/grouped by OpenAPI tags - Removes internal/test endpoints
- 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:
| Folder | Endpoints |
|---|---|
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— excludesservices/*/tests/**andtests/e2e/** - API service config:
services/api/vitest.config.ts— usesnitro-test-utils/configto start Nitro server - Run:
pnpm run test(root) orcd services/api && vitest run(API only)
Key Unit Test Files
| File | Coverage |
|---|---|
reading-status.test.ts | Reading status derivation from KoSync progress |
hardcover-client.test.ts | Hardcover 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:
@smokeE2E tests only - main push: Full E2E suite
- Test results posted as PR comments