For developers
Testing
The unit and end-to-end suites, the guard tests that keep the rules honest, and how to run them.
The suites
| Suite | Tool | Covers |
|---|---|---|
| Unit | Vitest | Money, dates, gates R1–R14, RBAC, risk, sign-in limits, tenant isolation, seed integrity, backups, integrations |
| End-to-end | Playwright + axe-core | Every role's access, every module's main flow, portals, documents, exports, accessibility, and no sideways scroll at 360 px, on desktop, laptop and phone sizes |
pnpm test, pnpm typecheck and pnpm lint must pass before every commit.
Guard tests
These fail the build when a rule of the codebase is broken, so nobody has to remember:
| Test | Fails when |
|---|---|
apps/app/lib/access.test.ts | A page skips guardPage, or an action skips requireAccess or writeAudit (without a // no-audit: <reason> line) |
packages/db/tenant.test.ts | Org A can read org B's rows, or a table with orgId has no row-level security policy |
apps/app/lib/docs-coverage.test.ts | A panel screen has no page in these docs, or a docs page claims a screen that does not exist |
apps/app/lib/security-headers.test.ts | The panel's CSP or security headers change shape |
Running them
pnpm test # all unit tests
pnpm --filter @harbor/core test # just the business rules
The end-to-end suite runs against a production build:
cd apps/app
pnpm build
set -a && source ../../.env && set +a
PORT=3200 AUTH_TRUST_HOST=true SIGNUPS_PER_HOUR=100 node .next/standalone/apps/app/server.js &
BASE_URL=http://localhost:3200 npx playwright test --workers=2
What to write
| You added | Write |
|---|---|
A rule in packages/core | A Vitest test beside it, including the refusal message |
| A screen or flow | A Playwright spec in apps/app/e2e/ for the main flow, signed in as the roles that use it |
| A table | Nothing extra: tenant.test.ts checks it |
| A page or action | Nothing extra: access.test.ts checks it |
| A screen | Its docs page: docs-coverage.test.ts checks it |