🔬 stryker-js-effect is an Effect 4 mutation testing framework and drop-in alternative to
@stryker-mutator/core. 🤖 Emits line-by-line NDJSON streams and classified exit codes designed for automated CI runs, test runners, and AI coding agents. ⚡ Real-time mutant streaming, cancel-safe partial reports, reliable incremental cache, and day-one TypeScript 7 support.
pnpm add -D @systemfsoftware/stryker-js-cli
pnpm exec stryker runCode coverage only tells you which lines ran during tests; it cannot tell you if assertions catch broken logic. Mutation testing introduces small syntax and logic defects (mutants) into source files to verify test efficacy:
- 💀 Killed: A test failed while the mutant was active. The test caught the defect.
- 🧟 Survived: All tests passed despite the defect. Exposes missing test assertions.
- ⏳ Timeout: The mutant caused an infinite loop or hung process.
- 🚫 No Coverage: No test touched the mutated code path during dry run.
| Feature | Upstream StrykerJS | stryker-js-effect |
|---|---|---|
| Output Protocol | TUI progress bar, terminal scrapers | Real-time NDJSON stream on stdout |
| Interrupted Runs | Ctrl+C / cancel yields 0 reports |
Emits partial report up to last completed mutant |
| Incremental State | stryker-incremental.json frequently goes stale |
Reliable state validation surviving aborted runs |
| Agent / CI Mode | Generic CLI exit codes (0 or 1) |
Machine mode auto-detection (AGENT, CLAUDECODE, CODEX_SANDBOX) + classified exit codes |
| Effect-TS Ecosystem | Equivalent mutant noise on Schema & Brand types | Dedicated @systemfsoftware/stryker-plugins ignorers |
| Runtime Engine | Procedural JavaScript with mutable state | Pure functional Effect 4 architecture with typed errors |
The CLI emits newline-delimited JSON events directly to stdout. Automated CI runners and AI agents can process results incrementally without parsing terminal escape codes:
$ pnpm exec stryker run
{"kind":"stream","schemaVersion":"1.0","runId":"06FY3DSBM7TYC2RZQ0F3EGVZ88","mode":"machine","signal":"tty"}
{"kind":"phase","phase":"instrument","elapsedMs":102}
{"kind":"phase","phase":"dry-run","elapsedMs":6658}
{"kind":"plan","total":2}
{"kind":"tick","elapsedMs":8200,"completed":1,"total":2}
{"kind":"verdict","schemaVersion":"1.0","score":100,"thresholds":{"high":100,"low":80,"break":0},"counts":{"killed":2,"survived":0,"timeout":0,"noCoverage":0},"reportFile":"reports/mutation/mutation.json"}Every mutation run emits a deterministic sequence of typed event objects:
Event kind |
Description | Key Attributes |
|---|---|---|
stream |
Run initialization | runId, mode, signal, schemaVersion |
phase |
Phase transitions (instrument, dry-run) |
phase, elapsedMs |
plan |
Test plan prepared | total mutants planned |
tick |
Progress heartbeat per batch | elapsedMs, completed, total |
verdict |
Final run verdict | score, thresholds, counts, reportFile |
error |
Fatal execution error | failure, remediation |
Machine mode activates automatically when stdout is non-interactive or when AGENT, CLAUDECODE, or CODEX_SANDBOX environment variables are present. Enforce manually with STRYKER_MODE=machine.
Granular exit codes allow automated systems to handle distinct failure classes without text scraping:
| Exit Code | Classification | Meaning |
|---|---|---|
0 |
Success | Mutation score met or exceeded configured break threshold |
1 |
Verdict Failed | Mutation score fell below required break threshold |
2 |
Config Error | Invalid configuration or unresolvable options schema |
3 |
Runtime Error | Test runner crashed or instrumenter encountered invalid AST |
4 |
Internal Error | Unhandled engine defect or unexpected runtime fault |
128 + n |
Process Signal | Terminated by POSIX signal n (130 for SIGINT) |
pnpm add -D @systemfsoftware/stryker-js-cli \
@systemfsoftware/stryker-js-vitest-runner \
@systemfsoftware/stryker-js-typescript-checkerCreate stryker.config.json in your project root:
{
"testRunner": "vitest",
"plugins": [
"@systemfsoftware/stryker-js-vitest-runner",
"@systemfsoftware/stryker-js-typescript-checker"
],
"mutate": [
"src/**/*.ts",
"!src/**/*.d.ts",
"!src/**/__tests__/**"
],
"thresholds": {
"high": 100,
"low": 80,
"break": 100
}
}pnpm exec stryker runThis monorepo publishes a modular ecosystem of packages under the @systemfsoftware scope:
| Package | Role |
|---|---|
@systemfsoftware/stryker-js-cli |
Terminal & CI runner binary with NDJSON streaming output |
@systemfsoftware/stryker-js-language |
Pure domain core: mutant models, schemas, and exit classifications |
@systemfsoftware/stryker-js-plugin-interface |
Shared plugin contracts (declarePlugin, composePlugins) |
@systemfsoftware/stryker-js-engine |
Mutation run lifecycle engine and test orchestration |
@systemfsoftware/stryker-js-instrumenter |
AST mutation engine powered by OXC parser |
@systemfsoftware/stryker-js-vitest-runner |
Vitest runner integration for mutation sandboxes |
@systemfsoftware/stryker-js-typescript-checker |
TypeScript type-checker plugin validating mutants pre-execution |
@systemfsoftware/stryker-js-html-reporter |
Interactive HTML mutation report generator |
@systemfsoftware/stryker-plugins |
Domain ignorers for Effect Schema brands & tagged unions |
@systemfsoftware/stryker-test-contribution |
Suite hygiene plugin enforcing unique mutant kills per test file |
How does this package family differ from upstream StrykerJS?
stryker-js-effect is an Effect 4 native fork maintained by System F Software. It streams NDJSON mutant events in real time, emits partial reports on cancellation, guarantees clean incremental test caching, and includes purpose-built ignorer plugins for Effect-TS schemas.
Why do mutants survive on my Effect Schema definitions?
Schema definitions and branded type markers often produce equivalent mutants that cannot be observed or failed at runtime. Install @systemfsoftware/stryker-plugins and enable effect-schema-ignorer in your stryker.config.json to filter them out automatically.
What versions of Node.js and TypeScript are supported?
All packages require Node.js 20 or later (>=20.0.0, with CLI packages targeting Node.js >=20.19.0). TypeScript 5.x through 7.x are supported out of the box.
Development setup, verification gates, and pull request guidelines are documented in CONTRIBUTING.md.
Licensed under the Apache-2.0 License.