Skip to content

Smoke tests

Smoke tests cover the service-reachability and end-to-end-pipeline layer: every service responds to /health, the gateway can accept and route orders, OAuth flows succeed, and core data paths return expected shapes. The platform has two distinct smoke surfaces: backend smoke (run in CI against a testcontainers stack) and frontend deploy-gate smoke (run in CI against a deployed Vite build).

Smoke does not assert correctness of business logic; that is the job of unit and integration tests. It asserts only that requests reach handlers and return well-formed responses.

File: backend/src/tests/smoke.full.tc.test.ts (full suite) and backend/src/tests/smoke.tc.test.ts (fast critical-path subset) Run: deno task test:testcontainers Checks: 11 critical-path checks (fast subset), plus 65 end-to-end checks across the full suite

The full backend smoke (smoke.full.tc.test.ts) groups its 62 checks into three top-level Deno.test blocks so each block can boot the minimum service set it needs:

| Block | Services booted | Checks | | --- | --- | --- | | Service health and version | All 29 services | 3 | | Core trading flows | 9 core services, all 9 algo strategies | 41 | | Peripheral services | 4 core services, 12 peripheral services | 18 |

  • Core trading flows boots: market-sim, EMS, OMS, user-service, journal, gateway, fix-archive, observability, risk-engine.
  • Peripheral services boots: market-sim, journal, user-service, gateway, plus news, analytics, recommendation, feature, signal, scenario, llm-advisory, replay, rfq, dark-pool, ccp, market-data.

Every block is gated on RUN_TESTCONTAINERS=1, runs inside scripts/run-testcontainers.sh, and wraps its body in try { ... } finally { await stack.teardown() }.

  • CI (test:testcontainers task): runs on every push and PR. scripts/run-testcontainers.sh sets RUN_TESTCONTAINERS=1 and brings up an ephemeral Postgres + Redpanda per Deno.test block.
  • Local development: deno task test:testcontainers works in the dev container with Docker available. The full smoke suite (smoke.full.tc.test.ts) takes 90 to 150 seconds depending on how many services each block boots.
  • Pre-commit: testcontainers smoke is not run by the pre-commit hook because the hook stays fast for tight edit loops. Pre-commit covers unit tests + integration tests (the latter auto-skipped if the local stack is offline).

smoke.tc.test.ts is a curated 11-check subset that boots a small 8-service stack and runs in around 30 seconds. It catches the most common deployment-class bugs quickly. smoke.full.tc.test.ts is the comprehensive 62-check port; it boots larger stacks and takes longer, but covers every check the legacy smoke.test.ts used to assert.

Both files use the same testcontainers helpers (startStack, login from ./testcontainers/auth.ts) and the same RUN_TESTCONTAINERS=1 gate.

File: frontend/tests/gate/smoke.spec.ts Run: cd frontend && npx playwright test --config playwright.gate.config.ts Checks: 5 end-user-flow assertions

The frontend smoke is a small Playwright suite that runs against a deployed environment, not the dev stack. It verifies the user-visible surface is wired up:

  1. Login page renders (homepage is reachable, no 502).
  2. /sessions/me returns 401 for an anonymous request (the user-service is routable through the gateway and is gating on auth).
  3. After OAuth login, the dashboard mounts and the gateway-proxied market-sim /prices endpoint returns price data within 30s (the full happy path works).
  4. A WebSocket to the gateway emits at least one marketUpdate frame within 10s (real-time data is flowing).

This is the gate that decides whether a deploy is good. If the backend smoke passes but this fails, the deployment's plumbing (Traefik routes, OAuth client config, WebSocket upgrade headers) is wrong: the services are up but the user-facing path is broken.

Smoke does not verify trading logic, P&L maths, FIX message shapes, or any business behaviour. Those are covered by unit and integration tests. Smoke is the layer that verifies delivery: that the unit-tested code is reachable from a fresh stack boot, with services correctly wired to Postgres and Redpanda, and that the gateway can authenticate users and route orders.

A smoke failure means a routing, wiring, or auth path is broken. A unit or integration failure means the code logic is broken. The runbooks for these two are different.

The legacy smoke.test.ts (now removed) ran against localhost or a remote VETA_BASE_URL and contained 62 checks. It was originally written as a manual post-deploy gate, but in practice ran nowhere: the pre-commit hook auto-skipped it when local services were offline, CI did not invoke it, and the production deploy script uses container healthchecks rather than this suite. The 62 checks were ported to smoke.full.tc.test.ts (which runs in CI via the testcontainers gate) and the legacy file was removed.