Testing
Simmetric Chat uses Jest 30 with the @swc/jest transform (unit + integration) and Playwright (E2E), orchestrated by Turborepo. The root jest.config.cjs aggregates the 5 projects (shared, server, frontend, collector, widget).
Simmetric Chat uses Jest 30 with the @swc/jest transform (unit + integration) and Playwright (E2E), orchestrated by Turborepo. The root jest.config.cjs aggregates the 5 projects (shared, server, frontend, collector, widget).
Levels
| Level | Runner | DB | Scope |
|---|---|---|---|
| Unit | Jest 30 + @swc/jest | mock Prisma (no DB) | services, utilities, validation |
| Integration | Jest 30 + supertest 7 | real PostgreSQL worker | routes, middleware, DB flows |
| E2E | Playwright | complete app | user-facing UI (13 specs) |
Unit tests
Prisma mocked via jest.mock (no real DB). Covers: services (RAG, backup, encryption, DLP, agent budget), utilities (RBAC, license, chunker), Zod schemas, webhook dispatch. Server unit: moduleNameMapper mocks for the heavy deps (uuid, jsdom, pdfjs-dist, pg-boss...) and @simmetric-chat/shared mapped to shared/dist (rebuild shared after edits - the turbo ^build gotcha; frontend/widget map the source).
pnpm test # all 5 packages via turbo (Postgres-free)
pnpm test:all # same suites via jest.config.cjs (plain Jest)
pnpm --filter server test
pnpm --filter shared testConventions: *.test.ts files in __tests__/ next to the source (frontend *.test.tsx in a jsdom environment). Snapshots only for deterministic outputs (never LLM). Use jest.mock('../prisma') to isolate the DB; a server unit file starts with import "./helpers/setupEnv".
Integration tests
Real PostgreSQL worker DB on localhost:5434 (per .env.test). The simmetricchat_test_template template is cloned per test file (path SHA-256) for isolation. Covers Express routes (supertest 7), middleware (auth, RBAC, license, rate limit), complete DB flows (workspaces, chats, documents, backup restore). The collector has a dedicated integration suite on the pgvector_test DB, port 5433 (jest.config.integration.cjs).
Setup:
- Test env variables (test DB, test
JWT_SECRET, shared secrets - tracked inpackages/server/.env.test). - Migrations applied to the template (
jest.globalSetup.js: migrate deploy + seed); each test file clones a fresh DB; teardown drops the template. - Sequential runs (suites may read the cached
DATABASE_URL- known debt).
pnpm --filter server test:integration # --forceExit included
pnpm --filter collector test:integrationE2E (Playwright)
13 specs in e2e/. They cover user-facing flows: auth/admin, chat streaming, chat edit/regenerate, document upload → RAG, unified upload destinations, widget embed, MCP install (marketplace lifecycle), MCP pin/use, admin settings nav, synthesis run, RBAC UI (project sidebar), theme switch.
pnpm test:e2e
# with UI: pnpm exec playwright test --uiPrerequisites: app up (pnpm dev or compose), migrated DB, built @simmetric-chat/shared + frontend, browsers installed (pnpm exec playwright install). The root .env must also carry WIDGET_API_KEY and API_KEY_HMAC_SECRET: the widget webServer fails loud at boot without them (Zod .min(1)), and the plaintext must match the api_keys row e2e/globalSetup.ts seeds. Playwright boots the 3 web servers itself (backend tsx, frontend vite preview, widget - all reuseExistingServer); globalSetup is idempotent (setup wizard → admin/admin123, E2E widget + E2E_WIDGET_ID, mustChangePassword reset). Config in playwright.config.ts (30s timeout, 2 retries). Enterprise-gated specs self-skip without LICENSE_KEY.
Coverage
No coverage thresholds are configured in any Jest config and coverage is not a CI gate; the closest quality gate is the test-count guard (3900-declaration cap for the community suite). Local reports:
pnpm test:all -- --coverage
pnpm --filter server test -- --coverageManual testing focus on the critical services: agent orchestrator, hybridSearch, backup, encryption, license, RBAC.
Critical-flow tests (checklist)
- Hybrid RAG: vector + FTS + RRF fusion + archive fallback (D-07) + embedding-mismatch guard (D-01) + metadata filtering (pre-filters + SQL predicates + server-side backstop).
- ReAct agent: loop detection, unknown-tool circuit breaker (BOT-03), budget wallclock/token/context, per-user concurrency, provider fallback.
- Widget: anonymous session + expiry, double-layer rate limit (per-widget burst + per-widget+IP daily), lead capture, IDOR prevention (
WidgetWorkspacewhitelist), transparent SSE proxy. - Backup: dump → archive → checksum → upload retry → restore atomicity (psql single-transaction) + retention.
- MCP: transport fallback (D-09), install/uninstall, pin resolution (strict union), health check (pg-boss cron, 3-level staleness).
- License: graceful Enterprise→Community degradation, 402 gating, numeric limits.
Debugging tests
pnpm --filter server test -- src/__tests__/auth.test.ts # by file (positional)
pnpm --filter server test -- -t "test name" # by name
pnpm --filter server test:integration -- --runInBand # serial for DB
DEBUG=1 pnpm test:e2e -- --headedCI
Turborepo caches tests; typical pipeline: lint → typecheck → test → test:integration → build → test:e2e. The integration worker DB requires a PostgreSQL service in CI (pgvector/pgvector:pg16). Test-relevant jobs: test-unit (+ air-gap grep gate + FTS locale gate + test-count guard), test-airgap (NETWORK_EGRESS_BLOCKED=1), test-e2e, build (+ freshness check).
v0.28.1 Provenance
| Statement | Source |
|---|---|
E2E: WIDGET_API_KEY + API_KEY_HMAC_SECRET required (widget webServer loud-fail; match to the seeded api_keys row) | docs/DEVELOPMENT.md (E2E, row-time) |
Operational reference - Simmetric Chat v0.28.1 (docs updated 2026-10-02, census SHA `aca5b8ff`).
Cross-link
- Conventions: 10 - Development
- Tested internals: 05 - Feature Guide