Skip to content

Testing

The test suite is split into layers. Each layer catches a different kind of breakage, and the fast layers need no database, Docker or secrets. That way every pull request, including Dependabot's, gets a reliable result within a couple of minutes.

Layer What it catches Where the tests live Command
Lint Syntax errors, style drift everything outside extern/ yarn lint
Module loading Dependencies or source files that no longer require() test/unit/module-load.spec.js yarn test:unit
Unit Behaviour changes in parsing, formatting and query-building libraries src/**/*.spec.js, next to the code yarn test:unit
In-process HTTP Changes to Koa, routing, CORS, compression, auth and body parsing test/unit/http/ yarn test:unit
Integration Database, PostGIS, S3 and Redis wiring test/ctd/, test/eims/, test/integration/ yarn test:integration

CI

  • Lint and Unit Test (.github/workflows/unit-tests.yml) runs yarn lint and yarn test:unit on every pull request. It needs no app secrets.
  • Build and Test (.github/workflows/build-test-push.yml) builds the Docker image, starts the docker-compose stack with a test database, and runs yarn test inside the API container.

Both checks must pass before a pull request is merged. For Dependabot pull requests, both checks passing is the signal that a minor or patch update is safe to merge.

Running tests locally

Unit tests run on any machine with Node and the project's dependencies installed:

yarn install
yarn lint
yarn test:unit

test/unit/setup.js pins every environment variable the app reads to a harmless test value before the tests start, so your .env is ignored and nothing can reach a real database. Timestamps are parsed in America/Vancouver, matching the production image.

Integration tests need the full stack:

yarn deploy:local
docker compose exec -T api yarn test

Writing tests

  • New dependency: add a unit test that pins the behaviour you rely on. One assertion on the output you actually use is enough. A minor version of that package then can't change it without failing CI.
  • New middleware or DB-free route: add a test in test/unit/http/ using chai.request(createApp().callback()). createApp() in src/app.js builds the full app without starting a server or connecting to Redis.
  • New generic GET route: add it to the list in test/integration/route-smoke.spec.js.
  • New query feature: add a case to src/middlewares/action-handle.spec.js. It checks the SQL that knex generates without needing a database.
  • Unit tests must not need a database, network access or secrets. If one does, it belongs in the integration suite.