Testing Overview
Test strategy, coverage summary, and how to run tests in this SaaS boilerplate
Test Strategy
This project uses two levels of testing:
| Type | Tool | Location | Status |
|---|---|---|---|
| E2E Tests | Playwright | apps/web/e2e/ | See E2E Tests |
| Unit Tests | Vitest | @repo/auth, apps/web, @repo/database | See Unit Tests |
| CLI tests | Vitest | scripts/**/*.test.ts | pnpm test:cli (root vitest.config.mts) — not inside pnpm test |
| Integration Tests | — | — | Not started |
pnpm test is cached turbo test and only runs packages with a test script (app, @repo/auth, @repo/database). CI (.github/workflows/ci.yml) always runs unit + pnpm test:cli. Playwright is .github/workflows/e2e.yml, gated on the e2e PR label — default CI does not run it.
Coverage Summary
E2E Coverage by Feature Area
See E2E Tests for the file-by-file breakdown (npx playwright test --list in apps/web). Folders: public/, auth/, account/, admin/, dashboard/, members/, payment/, plus setup/, fixtures/, helpers/, and opt-in capture/.
Unit Test Coverage
See Unit Tests for the file-by-file list. @repo/storage and @repo/utils have no test files (and no Vitest config at all).
| Package/App | Files |
|---|---|
@repo/auth | see Unit Tests |
apps/web | see Unit Tests |
@repo/database | redact.test.ts |
| root CLI | scripts/**/*.test.ts via pnpm test:cli |
Uncovered Areas
| Area | Type Needed | Priority |
|---|---|---|
Plan comparison helpers (comparePlans, getPlanLimits, getAnnualSavingsPercent) | Unit | Medium |
| Storage quota validation | Unit | Medium |
| Slug generation & validation | Unit | Low |
| Date utilities | Unit | Low |
Stripe webhook idempotency (claimWebhookEvent) | Integration | High |
Auth middleware / session validation (middleware.ts) | Integration | Medium |
Running Tests
E2E Tests (Playwright)
# E2E Postgres on 5433 + MailDev
docker compose -f docker-compose.e2e.yml up -d
# All default Playwright projects (not capture)
pnpm --filter app test:e2e
pnpm --filter app test:e2e:ui
pnpm --filter app test:e2e:auth # --project=no-auth
pnpm --filter app test:e2e:app # --project=authenticated
pnpm --filter app capture # CAPTURE=1, e2e/capture/*.capture.tsUnit Tests (Vitest)
# turbo test — app, @repo/auth, @repo/database only
pnpm test
# Setup CLI tests (not in turbo)
pnpm test:cli
pnpm --filter @repo/auth test
pnpm --filter app test
pnpm --filter @repo/database testTest File Organization
E2E Tests
E2E specs live in domain folders under apps/web/e2e/: account/, admin/, auth/, dashboard/, members/, payment/, public/, plus fixtures/, helpers/, and setup/ for shared test infrastructure (e.g. the Maildev REST helper — see Local Development). See E2E Tests for the full file list.
Unit Tests
Unit tests are co-located with their source files:
packages/auth/permissions.test.ts
packages/auth/billing-authorize.test.ts
packages/auth/helpers.test.ts
packages/auth/admin-bootstrap.test.ts
packages/auth/ba-i18n.test.ts
packages/auth/two-factor-hooks.test.ts
packages/auth/server-wiring.test.ts
apps/web/lib/routes.test.ts
apps/web/lib/parsers.test.ts
apps/web/app/[locale]/(app)/admin/users/guards.test.ts
apps/web/hooks/use-action-result.test.ts
apps/web/lib/auth/action-error.test.ts
apps/web/lib/billing/checkout-queries.test.ts
apps/web/lib/seo-config.test.ts
packages/database/redact.test.tsSee Unit Tests for what each file covers.
How E2E is wired
Four Playwright projects in apps/web/playwright.config.ts by default — auth-setup and org-setup run first and gate authenticated, while no-auth runs without a login. A fifth capture project is prepended only when CAPTURE=1 (pnpm --filter app capture). Local infra: docker compose -f docker-compose.e2e.yml up (Postgres on 5433, Maildev). CI (.github/workflows/e2e.yml) is gated on the e2e PR label. Project-by-project table: E2E Tests.