Browse documentation

Per-workspace test setup

WorkspaceRunnerNotes
apps/serverVitest, environment: nodetests/**/*.test.ts, setup vitest.setup.ts
apps/studioVitest, environment: jsdomglobals: true, clearMocks: true, @ → src alias
packages/clientvitest run --typecheckType-level assertions run with the tests
packages/ssr, packages/aivitest run
packages/clinode --testNode's built-in runner
npm test                       # turbo run test (builds first)
npm test -w @motherbase/server
npm test -w studio
npm run test:watch -w @motherbase/server
npm test -w @motherbase/server -- <name-filter>

turbo.json makes test depend on build, so tests always run against built packages rather than stale dist output.

Server test conventions

apps/server/tests holds ~190 files, split by suffix:

SuffixMeaning
*.unit.test.tsNo external services
*.integration.test.tsNeeds a real Postgres
*.test.tsService-level tests
*.shSmoke tests run against a deployed VPS

Some import tests skip themselves unless RUN_IMPORT_VERIFICATION_DB_TESTS=1 is set with a real database available — CI sets it.

Extra suites:

npm run test:contracts -w @motherbase/server   # SDK ↔ server contract
npm test -w @motherbase/server -- sdk-contract # regenerates the compatibility matrix

Studio mocks

apps/studio/src/mocks (browser.ts, handlers.ts, fixtures.ts) backs both the component tests and npm run studio:mock, so UI work needs no backend.

CI

.github/workflows/ci.yml, on push to master, on every PR, and manually.

The ci job runs on ubuntu-24.04 with a postgres:16.14-alpine3.23 service and a 15-minute timeout:

  1. Validate deployment Compose files — docker compose config --quiet on deploy/console/docker-compose.yml, deploy/docker-compose.prod.yml and deploy/traefik/docker-compose.yml, with placeholder secrets. A malformed compose file fails before anything is built.
  2. npm ci
  3. npm run prisma:generate
  4. npm run prisma:deploy
  5. npm run lint — all seven workspaces
  6. npm run build
  7. npm test
  8. npm run test:contracts -w @motherbase/server
  9. Regenerate the SDK compatibility matrix and fail on drift in packages/client/COMPATIBILITY.md.
Note

Step 9 exists because the supabase-js compatibility matrix is generated, never hand-written. CI regenerates it against its own Postgres and fails if the committed copy differs — a matrix that can lie is exactly what this guards against. If it fails, run npm run test -w apps/server -- sdk-contract and commit the result.

Deploy job

deploy-vps runs only after ci, never on pull requests, and only on main/master. It:

  • skips itself cleanly when VPS_HOST/VPS_SSH_KEY are not configured;
  • refuses to deploy as root;
  • SSHes in, fast-forwards the branch, and runs ./setup.sh --yes --skip-dns-check;
  • runs tests/vps-smoke.sh, and tests/critical-flows-smoke.sh when the smoke-test variables are configured.

Concurrency is grouped per branch with cancel-in-progress: false, so two deploys never interleave.