CodeVetter · Repo Unpack · Testing signals
expressjs/express
Testing is mocha + supertest with `after` for multi-assertion coordination, and it is unusually thorough for a codebase this size: 70 unit files under `test/` plus 18 acceptance files under `test/acceptance/`, totalling ~15,400 lines against ~5,500 lines of `lib/`. Unit files are named one-per-API (`res.send.js`, `req.host.js`, `app.param.js`), which makes the mapping from source method to test file mechanical. Acceptance tests do not use fixtures — they `require('../../examples/<name>')` and drive the real example apps, so `examples/` is effectively production test surface. Coverage runs through nyc in CI across the whole matrix, is merged with lcov and shipped to Coveralls.
- The runner is mocha with `--require test/support/env --check-leaks`, covering both `test/` and `test/acceptance/`; `--check-leaks` means any accidental global assignment fails the suite.
- `test/support/env.js` forces `NODE_ENV=test` (which suppresses `logerror` output and keeps `view cache` disabled) and sets `NO_DEPRECATION=body-parser,express` to silence `depd` warnings.
- HTTP assertions run through `supertest` against the app function directly, without binding a port — e.g. `request(app).get('/').expect(200, done)`.
- `test/support/utils.js` provides the shared assertion vocabulary: `shouldHaveBody`, `shouldHaveHeader`, `shouldNotHaveBody`, `shouldNotHaveHeader`, `shouldSkipQuery` — with body comparison done on hex-encoded buffers.
- `test/support/tmpl.js` is a hand-rolled `$var.path` template engine used as the canonical view-engine double, avoiding a real engine dependency in most view tests.
- The largest test files track the riskiest code: `app.router.js` (1217 lines), `res.sendFile.js` (913), `express.urlencoded.js` (828), `express.static.js` (815), `express.json.js` (755), `Router.js` (636), `res.send.js` (635).
- Path-traversal behaviour is explicitly covered: `express.static.js` asserts handling of `/users/../todo.txt`, `/users/../../todo.txt` and the URL-encoded `/users/%2e%2e/%2e%2e/todo.txt`, and `res.sendFile.js` covers `fake/../name.txt` and `../name.txt` under a `root`.
- All 18 acceptance files import example apps rather than fixtures — `test/acceptance/auth.js` requires `../../examples/auth` and drives the full login/session/restricted flow including cookie extraction.
- Seven of the 26 examples have no acceptance test: `online`, `route-middleware`, `search`, `session`, `static-files`, `view-constructor`, `view-locals` — leaving the custom-`View`-constructor extension point exercised only by the example itself.
- `test/exports.js` deliberately mutates `express.application`, `express.request` and `express.response` prototypes to prove the extension contract holds — meaning test ordering has real cross-file coupling.
- `test/regression.js` is a deliberately tiny guard file — currently one case asserting that throwing after `res.end()` still yields a clean 200 response.
- Coverage is produced per matrix cell (`npm run test-ci` → nyc lcovonly), uploaded as `coverage-node-<ver>-<os>` artifacts, then merged in a dedicated `coverage` job with `lcov -a` and pushed to Coveralls.
- nyc excludes `examples`, `test` and `benchmarks` from instrumentation, so the acceptance tests contribute coverage for `lib/` only — and the `benchmarks` exclude refers to a directory that no longer exists in the tree.
- CodeQL scans `javascript` and `actions` on push/PR to master plus a weekly cron, with `paths-ignore: test`; OpenSSF Scorecard runs weekly and on branch-protection changes, publishing SARIF to code scanning.
- Explicit `/* istanbul ignore next */` pragmas mark knowingly-uncovered branches, including `logerror`'s console path and the `stringify` escape default case.