npm test # unit + integration (vitest, node env)
npm run test:watch # watch mode
npm run test:coverage # v8 coverage over src/lib and src/app/api
npm run typecheck # tsc --noEmit
npm run lint # eslint (next/core-web-vitals)tests/
helpers/fixtures.ts — store/user/config factories, NextRequest builder
unit/ — isolated module tests
passwords.test.ts — scrypt hashing/verification
apiKeys.test.ts — key generation, scope enforcement, revocation
store.test.ts — MemoryStore invariants + FileStore persistence
models.test.ts — zod schema validation
mock-provisioner.test.ts — simulated container lifecycle
ui.test.tsx — component/format helpers (jsdom)
integration/
provision-service.test.ts — full lifecycle, port allocation, failure paths,
status sync, env injection (MockProvisioner)
docker-provisioner.test.ts — DockerProvisioner against a fake Docker Engine
API (node:http server over TCP) verifying
request payloads and response parsing
api-routes.test.ts — route handlers end-to-end: login → session →
instance/agent/key CRUD + v1 API with keys
setStoreForTesting(store)/setProvisionerForTesting(p, config)swap the singletons used by route handlers — no server needed; handlers are called directly withNextRequestobjects built by thereq()helper.DockerProvisioneracceptshost: "tcp://127.0.0.1:<port>", so integration tests run a fake daemon locally — no real Docker needed in CI.MockProvisioner.failNextCreateforces provisioning failures.
- Build state through
makeStore(),makeUser(),makeAgentConfig(). - For API tests: reset singletons in
beforeEach(setStoreForTestingbeforesetProvisionerForTesting, since the service binds the store), sign in via the real/api/auth/loginhandler orcreateSession, then call the route handler. - Component tests need
// @vitest-environment jsdomat the top.