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) runsyarn lintandyarn test:uniton every pull request. It needs no app secrets. - Build and Test (
.github/workflows/build-test-push.yml) builds the Docker image, starts thedocker-composestack with a test database, and runsyarn testinside 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/usingchai.request(createApp().callback()).createApp()insrc/app.jsbuilds 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.