Sthora
Contributing

Testing

Which command proves which change, and the suites that exist to stay unbroken.

Run the narrowest command for what you changed. Never a root-level build unless the change is whole-workspace orchestration.

No test command needs a running database

The backend suites use a stateful in-memory client fake at apps/backend/test/prisma.fake.ts. The whole suite runs with no external services.

Which command

ChangeCommand
Backend TypeScriptpnpm --filter @sthora/backend lint
Backend logicpnpm --filter @sthora/backend test
Backend routes, bootstrap, config, or API docspnpm --filter @sthora/backend test:e2e
Prisma schemadb:generate, then build, then test:e2e
Shared contractspnpm --filter @sthora/shared build, then each consumer's tests
Dashboardpnpm --filter @sthora/dashboard test, then build
Marketing sitepnpm --filter @sthora/website test, then build
These docspnpm --filter @sthora/docs test, then build
Frontend route files added or renamedRegenerate the route tree, then build
Whole workspacepnpm build

Fix lint failures before running tests. Fix failing tests before widening scope. Report the exact commands you ran and their outcome.

The suites that exist to stay unbroken

Three files are security regression suites. A case is never deleted to make a change pass.

FileGuards
compose-sanitiser.spec.tsOne case per reject rule
archive-entry-path.spec.tsZip-slip and path traversal
proxy.service.spec.tsThe Traefik dashboard staying unexposed, and the socket staying read-only

Two more are worth knowing about:

  • openssh-key-interop.spec.ts checks generated deploy keys against ssh-keygen itself.
  • The TOTP implementation is verified against RFC 6238's own published test vectors.

Test quality

  • High signal over assertion count. A few strong regression tests beat many shallow ones.
  • Every bug fix adds at least one test that fails before the fix and passes after it.
  • Test observable behaviour, not implementation detail. A refactor that preserves behaviour must not require test edits.
  • Name a test as a sentence describing the behaviour and its condition, not the method name.
  • Tests are deterministic: no real network, no wall-clock dependence, no shared mutable state, no ordering assumptions.

Placement

KindLocation
UnitBeside the code under test
End-to-endThe package's top-level test/ folder
Component or route (frontend)Beside the component or route file

Frontend specifics

Query by accessible role and text, the way a user finds things — never by class name or internal component structure. Mock network calls at the transport boundary, not by stubbing the app's own data-fetching hooks. Keep at least one smoke test per app that renders its entry route, so a broken shell fails fast.

This site's own tests

apps/docs asserts that every page in content/docs/ carries a title and a description, that every page reaches the sitemap, and that the Markdown URL encoding round-trips. A page with no description is invisible until a search result renders empty, and a page missing from the sitemap is invisible to a crawler — neither shows up by looking at the page.

On this page