@systemfsoftware/stryker-js 11.0.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # @systemfsoftware/stryker-js
2
2
 
3
+ ## 12.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - A piped `stdout` now gets human output, exactly like a terminal. Machine consumers ask for the NDJSON event stream explicitly, with `--json` or `STRYKER_MODE=machine`; `--format text` names the human format, and passing it together with `--json` is a usage error (exit 2). Under `--json`, `stdout` carries wire records and nothing else, while progress status lines and log output stay on `stderr`.
8
+
9
+ Every run also writes those wire records to `reports/mutation-stream.jsonl` in human mode too, so a job that shows a readable log still produces the artifact `stryker merge-reports` rebuilds a shard's report from.
10
+
11
+ If a script or CI step read NDJSON from a piped run without requesting it, pass `--json` (or set `STRYKER_MODE=machine`) there.
12
+
13
+ Custom `RunEventDrain` implementations must accept a required `toStdout` argument in `drainFramed`; pass-throughs can ignore it.
14
+
15
+ ### Patch Changes
16
+
17
+ - A run whose selected files produce no mutants, for example because no loaded framework claims them, now runs every test in the dry run and finishes with an empty report. With `testRunner: 'vm'` or `'vitest'` it used to fail with "No tests were executed", because the dry run only looked for tests related to those files. The dry run now relates tests only to the files that carry mutants.
18
+
19
+ - A run whose `mutate` patterns match no file now finishes successfully instead of stopping with an instrument error. It performs the dry run, writes a mutation report with no files, and passes regardless of `thresholds.break`, the same as upstream StrykerJS. A sharded run whose shard receives no file no longer fails.
20
+
21
+ `stryker merge-reports` shows `n/a` for a package whose report has no tested mutant, instead of a score of `0.00`.
22
+
23
+ Errors reported for the prepare, dry-run, and mutation-testing stages now carry their reason as the error message, so a printed cause no longer shows up as a bare error name.
24
+
25
+ - `stryker merge-reports` now rebuilds a package's partial report from the mutants recorded in its stream part when the run ended before writing its final report. Earlier versions recognized none of the recorded mutants and reported the package as having no report.
26
+
27
+ - Mutation runs with `testRunner: 'vm'` finish in about half the time, with the same verdicts. The engine checks mutant groups on every checker process at once, stops the checkers as soon as checking ends, hands their share of `concurrency` to the test runners, and shares a Node compile cache with every worker it starts. The Vitest runner starts the next isolated worker thread while the current test file runs, so each file still gets a fresh thread but no longer waits for one to boot. On a 319-mutant TypeScript project with the TypeScript checker, a run went from 24.9 s to 12.6 s.
28
+
29
+ - `testRunner: 'vm'` runs Vitest itself on Vitest's isolated `threads` pool instead of an in-process reimplementation, and stays the default `testRunner`. It reports the same test ids, outcomes and per-mutant verdicts as `testRunner: 'vitest'`, so a project whose Vitest config enables browser mode is refused at startup with a message naming `testRunner: 'vitest'`.
30
+
31
+ Stryker no longer discovers test files for `vm`: Vitest selects them from your config, as it does for `testRunner: 'vitest'`. A run that loads no test files fails the dry run naming `testFiles`.
32
+
33
+ ## 12.0.0
34
+
35
+ ### Major Changes
36
+
37
+ - Restore `defineConfig` and `mergeConfig` on `@systemfsoftware/stryker-js/config`. `defineConfig` accepts an options object, a promise of one, or a `(env: ConfigEnv) => …` factory, as in 10.1.1, and `mergeConfig(defaults, overrides)` composes presets again. `StrykerConfig` is again the partial-options type, so `const config: StrykerConfig = defineConfig({ … })` typechecks. Config files written against the 10.1.1 `./config` surface load and typecheck without edits.
38
+
39
+ This removes the 11.0.0 `StrykerConfig` class value. If you adopted it:
40
+
41
+ - Replace `StrykerConfig.define(…)` with `defineConfig(…)` and `StrykerConfig.merge(…)` with `mergeConfig(…)`, imported from `@systemfsoftware/stryker-js/config`.
42
+ - Replace `StrykerConfig.createDefaultOptions()` and `StrykerConfig.defaultOptions` with `Configuration.createDefaultOptions()` and `Configuration.defaultOptions` from the package entry point.
43
+
44
+ ### Patch Changes
45
+
46
+ - A failed dry run now says which tests broke and why. The refusal names every failing test with its failure message in the error output and in the log at the default level, instead of reporting only how many failed.
47
+
48
+ - Installing `@systemfsoftware/stryker-js` on its own now works. `effect` was declared an optional peer even though Stryker imports it at runtime. Package managers never install optional peers, so a project without `effect` failed with `Failed to read config` before the run started. `effect` is now a required peer: pnpm and npm install it automatically, and a project that already uses Effect shares its own copy with Stryker.
49
+
50
+ - The packages now build on the latest `@systemfsoftware/effect-cell-types` 10.2 cell kinds, with no change to their published behavior.
51
+
52
+ - `@systemfsoftware/stryker-test-contribution` exports its evaluator as `Judge`, `TestContribution`, and `TestContributionEvaluator`, and now depends on `effect` directly.
53
+
3
54
  ## 11.0.0
4
55
 
5
56
  ### Patch Changes
package/README.md CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  The modern mutation testing framework for JavaScript and TypeScript.
4
4
  A ground-up, breaking-change fork of `@stryker-mutator/core` built with Effect 4:
5
- provides the `stryker` executable, in-process `vm` and isolated Vitest runners,
6
- and the typed `./config` authoring surface.
5
+ provides the `stryker` executable, the `vm` and `vitest` test runners, and the
6
+ typed `./config` authoring surface.
7
7
 
8
8
  ## Install
9
9
 
@@ -24,9 +24,9 @@ pnpm add -D @systemfsoftware/stryker-js \
24
24
  Create `stryker.config.ts` in your project root:
25
25
 
26
26
  ```ts
27
- import { StrykerConfig } from '@systemfsoftware/stryker-js/config'
27
+ import { defineConfig } from '@systemfsoftware/stryker-js/config'
28
28
 
29
- export default StrykerConfig.define({
29
+ export default defineConfig({
30
30
  testRunner: 'vitest',
31
31
  checkers: ['typescript'],
32
32
  plugins: [
@@ -54,19 +54,22 @@ pnpm exec stryker run
54
54
 
55
55
  ## Zero-Plugin Built-in Runners
56
56
 
57
- The `vm` runner is the default: with no `testRunner` and no `testFiles`
58
- configured, it discovers `*.test` / `*.spec` files itself and runs them. It loads
59
- your suites through your project's `vitest`, so `vitest` must be installed.
60
- Set `testFiles` explicitly, or pick one of the runners below, to take control.
57
+ The `vm` runner is the default and needs no plugin packages: `testRunner: 'vm'`
58
+ runs Vitest itself, on Vitest's isolated `threads` pool, through the project's
59
+ own `vitest` install (`vitest` must be installed). With no `testFiles`
60
+ configured, Vitest selects the test files from your config, exactly as
61
+ `vitest run` does. The runner reports the same test ids, outcomes and
62
+ per-mutant verdicts as `vitest run`. Set `testFiles` explicitly, or pick one of
63
+ the runners below, to take control.
61
64
 
62
65
  ### 1. Shell Command Runner (`testRunner: 'command'`)
63
66
 
64
67
  Execute any test suite without extra plugins:
65
68
 
66
69
  ```ts
67
- import { StrykerConfig } from '@systemfsoftware/stryker-js/config'
70
+ import { defineConfig } from '@systemfsoftware/stryker-js/config'
68
71
 
69
- export default StrykerConfig.define({
72
+ export default defineConfig({
70
73
  testRunner: 'command',
71
74
  commandRunner: {
72
75
  command: 'npm test',
@@ -75,34 +78,42 @@ export default StrykerConfig.define({
75
78
  })
76
79
  ```
77
80
 
78
- ### 2. In-Process `vm` Runner (`testRunner: 'vm'`)
81
+ ### 2. The `vm` Runner (`testRunner: 'vm'`)
79
82
 
80
- Runs Vitest suites in-process, in one worker thread per test runner, loading each test file as native ESM through Node's module hooks. No child process and no bundler step. Each file gets its own module state by default; your `vitest.config.*` (environment, setup files, globals, projects) is picked up through your project's `vitest` install. Vitest browser-mode suites are refused with an error naming `testRunner: 'vitest'`; pick the `vitest` runner for those.
83
+ Runs the Vitest runner on Vitest's isolated `threads` pool. Each test file keeps
84
+ Vitest's own per-file isolation, and module mocking, snapshots, environments,
85
+ setup files, projects and custom transforms behave as they do under
86
+ `vitest run`. A Vitest config that enables browser mode is refused with an
87
+ error naming `testRunner: 'vitest'`; pick the `vitest` runner for those.
81
88
 
82
89
  ```ts
83
- import { StrykerConfig } from '@systemfsoftware/stryker-js/config'
90
+ import { defineConfig } from '@systemfsoftware/stryker-js/config'
84
91
 
85
- export default StrykerConfig.define({
92
+ export default defineConfig({
86
93
  testRunner: 'vm',
87
94
  testFiles: ['test/**/*.test.ts'],
88
95
  mutate: ['src/**/*.ts', '!src/**/*.test.ts'],
89
96
  })
90
97
  ```
91
98
 
99
+ Suites that need Vitest's `forks` pool (for example `process.chdir`, or native
100
+ addons that are not thread-safe) use `testRunner: 'vitest'` with the
101
+ `@systemfsoftware/stryker-js-vitest-runner` plugin instead.
102
+
92
103
  ## Configuration API (`@systemfsoftware/stryker-js/config`)
93
104
 
94
- The `./config` subpath exports the typed configuration authoring surface:
105
+ The `./config` subpath exports the typed configuration authoring surface, including the `StrykerConfig` type naming the partial options a config file writes: a config annotated `const config: StrykerConfig = defineConfig({ ... })` typechecks and loads.
95
106
 
96
107
  ```ts
97
- import { StrykerConfig } from '@systemfsoftware/stryker-js/config'
108
+ import { defineConfig, type StrykerConfig } from '@systemfsoftware/stryker-js/config'
98
109
  ```
99
110
 
100
- ### `StrykerConfig.define(options | configFactory)`
111
+ ### `defineConfig(options | configFactory)`
101
112
 
102
113
  Identity function providing strict autocompletion and type checking without runtime dependencies. Can take a configuration object or a factory receiving `ConfigEnv`:
103
114
 
104
115
  ```ts
105
- export default StrykerConfig.define(({ isCi, command }) => ({
116
+ export default defineConfig(({ isCi, command }) => ({
106
117
  testRunner: 'vitest',
107
118
  plugins: ['@systemfsoftware/stryker-js-vitest-runner'],
108
119
  mutate: ['src/**/*.ts', '!src/**/*.test.ts'],
@@ -110,15 +121,15 @@ export default StrykerConfig.define(({ isCi, command }) => ({
110
121
  }))
111
122
  ```
112
123
 
113
- ### `StrykerConfig.merge(base, overrides)`
124
+ ### `mergeConfig(base, overrides)`
114
125
 
115
126
  Deeply merges configuration presets. Keys in records merge recursively; scalar values and arrays in `overrides` completely replace base values:
116
127
 
117
128
  ```ts
118
- import { StrykerConfig } from '@systemfsoftware/stryker-js/config'
129
+ import { mergeConfig } from '@systemfsoftware/stryker-js/config'
119
130
  import baseConfig from './stryker.base.config.ts'
120
131
 
121
- export default StrykerConfig.merge(baseConfig, {
132
+ export default mergeConfig(baseConfig, {
122
133
  concurrency: 8,
123
134
  mutate: ['packages/core/src/**/*.ts'],
124
135
  })
@@ -143,9 +154,20 @@ pnpm exec stryker run --incremental
143
154
  pnpm exec stryker run --concurrency 4
144
155
 
145
156
  # Merge partial mutation reports from parallel CI shards
146
- pnpm exec stryker merge-reports --output reports/mutation/mutation.json "reports/shards/*.json"
157
+ pnpm exec stryker merge-reports --parts reports/shards --out reports/mutation
147
158
  ```
148
159
 
160
+ ## Output Modes
161
+
162
+ Human output is the default, whether or not `stdout` is a terminal. A machine consumer opts into the NDJSON event stream explicitly:
163
+
164
+ ```bash
165
+ pnpm exec stryker run --json # wire records on stdout, diagnostics on stderr
166
+ STRYKER_MODE=machine pnpm exec stryker run # the same, named by environment
167
+ ```
168
+
169
+ `--format text` names the human format explicitly; `--json` together with `--format text` is a usage error (exit 2). Under `--json`, `stdout` carries wire records and nothing else — progress lines and log output stay on `stderr`. Every run also writes the same records to `reports/mutation-stream.jsonl` (`--progressStreamFile`) in both modes, which is the artifact `stryker merge-reports` rebuilds a shard's partial report from.
170
+
149
171
  ## Programmatic API
150
172
 
151
173
  ### Effect 4 Native Interface
@@ -180,11 +202,11 @@ console.log(`Mutation score: ${verdict.score}%`)
180
202
 
181
203
  ## Published Subpaths
182
204
 
183
- | Subpath | Description |
184
- | ------------ | ------------------------------------------------------------------ |
185
- | `.` | Main entry point: `strykerCell`, runtime layers, and error schemas |
186
- | `./config` | `StrykerConfig` authoring surface (`define`, `merge`) |
187
- | `./promises` | `run()` wrapper returning standard JavaScript promises |
205
+ | Subpath | Description |
206
+ | ------------ | ------------------------------------------------------------------------- |
207
+ | `.` | Main entry point: `strykerCell`, runtime layers, and error schemas |
208
+ | `./config` | Config authoring surface (`defineConfig`, `mergeConfig`, `StrykerConfig`) |
209
+ | `./promises` | `run()` wrapper returning standard JavaScript promises |
188
210
 
189
211
  ## License
190
212