Testing
This is a security control, so the test posture is strict: the core package is held to 100% coverage (branches, functions, lines, statements) and a Biome cognitive-complexity ceiling of 15 — and the whole suite runs without Docker.
That numeric gate covers @authlock/core only: the NestJS adapter is a thin DI
shell, behavior-tested in its own test:nestjs lane (guard and module specs)
rather than held to a coverage percentage.
How your own tests can use it
The engine takes an injectable clock (now) and ships a single-process
InMemoryLockoutStore, so lockout flows are testable hermetically and
deterministically:
let clock = 0;
const manager = new LockoutManager({
store: new InMemoryLockoutStore(),
limit: 3,
cooloffMs: 60_000,
parameters: [['username']],
now: () => clock,
});
// …trip the lock, then:
clock = 60_000; // the cooloff has elapsed — no sleeping in tests
How the library itself is tested
- One store contract, every backend. A shared behavioral contract runs against the in-memory store, the Postgres store, the SQLite store — and, gated, against real servers — so every backend is held to identical semantics, including the window reset.
- Real database engines in-process. The Postgres store is exercised through
PGlite (the actual Postgres engine compiled to WASM)
and the SQLite store through
better-sqlite3— the stores' realON CONFLICT … RETURNINGSQL runs on everynpm test, no services needed. MySQL has no in-process engine, so its store drives the realdrizzle-orm/mysql2query builder against a recording fake client. - Concurrency / no lost updates. 25 simultaneous
incrementcalls must yield a count of exactly 25 — the cross-instance atomicity guarantee — run hermetically and against real Postgres and MySQL. - Both failure modes.
failMode: 'open'(allow + log on store error) and'closed'(deny) each have dedicated paths through the manager and the NestJS guard. - Neutrality acceptance. A bare-Express sample proves the core works with zero framework coupling, over real HTTP.
- Gated real-server round-trips. With
LOCKOUT_POSTGRES_URL/LOCKOUT_MYSQL_URLset (CI provisions services; locallynpm run infra:up && npm run test:full), the same store contract runs against live Postgres and MySQL. - Both ends of the NestJS peer range. The default install and lockfile
stay on NestJS 11. A dedicated CI leg installs
@nestjs/*@^12on top of that lockfile (--no-save, in every workspace), proves from inside every workspace that each@nestjs/*package it installed resolved to 12 from the rootnode_modules, then re-runs the adapter typecheck, both suites, and the samples; a 10/11 matrix typechecks the adapter for backward compatibility. Supporting a major means testing it, not declaring it — see the support policy.