Files
Jamie Tanna d91e6088ff fixup! test: set up mutation testing with Stryker
The `mutation-pr`/`mutation-full` CI jobs were failing outright, and a
full `stryker run` never got past the initial dry run, so none of this
was actually usable yet.

- `mutation.yml`: pin all actions to a commit SHA, add a `permissions`
  block, set `persist-credentials: false`, and pass the base ref/changed
  files through `env` instead of interpolating them into the shell
  script directly (zizmor was flagging all of these). Also switch to the
  project's own `./.github/actions/setup-node` composite action instead
  of `pnpm/action-setup`/`actions/setup-node` (which additionally
  referenced a non-existent `.node-version` file), and fix the `pnpm
  mutation`/`pnpm stryker run --mutate` calls to use the actual
  `test:mutation`/`test:mutation:changed` script names.
- Drop the now-unused `@stryker-mutator/typescript-checker` dependency,
  left over from when `stryker.config.json` still had `checkers:
  ["typescript"]`.
- `lib/util/timestamp.ts`: the local-timezone-offset fallback used in
  `asTimestamp()` was cached in a module-level constant computed once at
  import time. Combined with vitest's `threads` pool (used by Stryker's
  vitest-runner) not reliably honouring a `process.env.TZ` set from our
  own `test/setup.ts`, this made `asTimestamp()` parse plain dates (e.g.
  Jenkins' `buildDate: 'Jan 02, 2020'`) using the host's real timezone
  instead of UTC. Compute the offset per call instead, and set `TZ=UTC`
  in the actual environment via the `test:mutation*` scripts, since that's
  the one thing that reliably works across pools.
- `test/setup.ts`: restore real timers in a top-level `afterAll`, so a
  spec that leaves fake timers running (there's at least one) can't leak
  a frozen clock into whichever spec runs next in the same worker -
  something that's only reachable under low-concurrency/single-threaded
  execution.
- Raise `dryRunTimeoutMinutes` and the global vitest `testTimeout`: our
  full suite's per-test coverage instrumentation run took ~25 minutes
  end-to-end, well past Stryker's 5 minute default, and a couple of
  CPU-heavy specs (WASM PGP crypto) timed out under that contention too.
- Ignore `.stryker-tmp/` (Stryker's sandbox dir, which can survive an
  interrupted run) in ls-lint/oxlint/biome/prettier/vitest, since a
  leftover sandbox copy of the repo was otherwise picked up as extra
  source/test files and broke those tools outright.

Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-10 15:38:01 +01:00
..