@hughescr/stryker-bun-runner 1.2.0 → 1.2.2

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/README.md CHANGED
@@ -77,6 +77,7 @@ This approach provides reliable test-to-mutant correlation, even with multiple t
77
77
  | `bun.inspectorTimeout` | `number` | `5000` | Timeout for Inspector WebSocket connection in milliseconds |
78
78
  | `bun.env` | `object` | `undefined` | Additional environment variables to pass to bun test |
79
79
  | `bun.bunArgs` | `string[]` | `undefined` | Additional bun test flags (e.g., `['--bail']`) |
80
+ | `bun.testFiles` | `string[]` | `undefined` | Explicit list of test file paths (absolute or relative to cwd). When provided, skips auto-discovery and uses this list verbatim. Relative paths resolve against the bun subprocess's cwd. Useful for restricting mutation testing to a subset of test files. |
80
81
 
81
82
  ### Example with all options
82
83
 
@@ -38,8 +38,8 @@ function formatCoverageData(mutantCoverage, counterToName) {
38
38
  };
39
39
  }
40
40
  function writeCoverageToFile(coverageFile, data) {
41
- appendFileSync(coverageFile, JSON.stringify(data) + `
42
- `, "utf-8");
41
+ appendFileSync(coverageFile, `${JSON.stringify(data)}
42
+ `, "utf8");
43
43
  }
44
44
  export {
45
45
  writeCoverageToFile,
package/dist/index.d.ts CHANGED
@@ -19,6 +19,7 @@ export declare class BunTestRunner implements TestRunner {
19
19
  private readonly inspectorTimeout;
20
20
  private readonly env?;
21
21
  private readonly bunArgs?;
22
+ private readonly testFilesOverride?;
22
23
  private readonly mutateGlobs;
23
24
  private preloadScriptPath?;
24
25
  private coverageFilePath?;
@@ -28,7 +29,9 @@ export declare class BunTestRunner implements TestRunner {
28
29
  private cachedTestNames?;
29
30
  private baseNameIndex?;
30
31
  private cachedTestFiles?;
32
+ private cachedTestFilesCwd?;
31
33
  private cachedEagerModules?;
34
+ private cachedEagerModulesCwd?;
32
35
  private lastRegistryTmpPath?;
33
36
  constructor(logger: Logger, options: StrykerOptions);
34
37
  /**
@@ -44,6 +47,21 @@ export declare class BunTestRunner implements TestRunner {
44
47
  */
45
48
  capabilities(): TestRunnerCapabilities;
46
49
  /**
50
+ * Return the test file list to use for this run.
51
+ * When `bun.testFiles` was provided it is returned verbatim and
52
+ * auto-discovery is skipped entirely. Otherwise the result is cached after
53
+ * the first real discovery call so that subsequent callers (dryRun, mutantRun)
54
+ * do not re-glob the filesystem.
55
+ */
56
+ private getOrDiscoverTestFiles;
57
+ /**
58
+ * Test-file cache hit for a given cwd.
59
+ * Returns the cached list synchronously when available, or undefined to
60
+ * signal that async re-discovery is needed (cwd changed or first call).
61
+ * Used by dryRun() to avoid introducing a microtask yield on the hot path.
62
+ */
63
+ private testFilesCacheHit;
64
+ /**
47
65
  * Initialize the test runner
48
66
  */
49
67
  init(): Promise<void>;
@@ -65,7 +83,12 @@ export declare class BunTestRunner implements TestRunner {
65
83
  */
66
84
  private loadRegistryFile;
67
85
  /**
68
- * Build test results from inspector data
86
+ * Build test results from inspector data.
87
+ *
88
+ * @param inspectorIdToProjectFile - Optional mapping from inspector ID to project file path.
89
+ * When provided, the project file is used for TestResult.id, name, and fileName instead of
90
+ * testInfo.url. This is important for tests defined via helpers (e.g. RuleTester.run()) where
91
+ * Bun's inspector reports a url pointing to node_modules rather than the user's test file.
69
92
  */
70
93
  private buildTestsFromInspector;
71
94
  /**
@@ -73,10 +96,62 @@ export declare class BunTestRunner implements TestRunner {
73
96
  */
74
97
  dryRun(): Promise<DryRunResult>;
75
98
  /**
99
+ * Build the in-memory test name cache and base-name index, then atomically
100
+ * persist them to a well-known file so other worker processes can lazy-load
101
+ * them when handling static-coverage mutants (testFilter is empty for those).
102
+ *
103
+ * Writing to a .tmp path then renaming is atomic on POSIX: readers always see
104
+ * either the previous complete file or the new one — never a partial write.
105
+ */
106
+ private buildAndPersistTestRegistry;
107
+ /**
76
108
  * Run tests with an active mutant
77
109
  */
78
110
  mutantRun(options: MutantRunOptions): Promise<MutantRunResult>;
79
111
  /**
112
+ * Build the MutantRunResult for a killed mutant (non-zero exit code).
113
+ * Handles runtime error detection and killedBy resolution.
114
+ */
115
+ private buildMutantKilledResult;
116
+ /**
117
+ * Check if the process failed due to a runtime error (no tests ran).
118
+ * Returns a MutantRunResult if this is a runtime error, or null to continue.
119
+ */
120
+ private checkRuntimeError;
121
+ /**
122
+ * Check for dry run process failures (timeout or non-zero exit).
123
+ * Returns a DryRunResult to short-circuit if the process failed, or null to proceed.
124
+ */
125
+ private checkDryRunProcessResult;
126
+ /**
127
+ * Collect coverage from the coverage file and remap counter-based IDs to
128
+ * full test names using the inspector's execution order.
129
+ */
130
+ private collectAndRemapCoverage;
131
+ /**
132
+ * Build local index structures from testFilter for killedBy resolution.
133
+ *
134
+ * testFilter carries the full registry IDs Stryker wants us to run, including
135
+ * any " [N]" dedup suffixes. Building the index here means all workers behave
136
+ * identically on the first shot, eliminating incremental drift caused by workers
137
+ * that never ran dryRun falling through to raw names.
138
+ */
139
+ private buildLocalTestFilterIndex;
140
+ /**
141
+ * Resolve raw failed test names from console output against the test registry.
142
+ *
143
+ * Console-parser output lacks the [N] dedup suffix that dryRun appends when
144
+ * multiple tests share the same base name (e.g. it.each with %s).
145
+ *
146
+ * Fallback chain — stops at the FIRST successful resolution for each name:
147
+ * 1. Exact match in localRegistry (built from testFilter)
148
+ * 2. Base-name match in localBaseIndex (built from testFilter)
149
+ * 3. Exact match in this.cachedTestNames (instance registry from dryRun)
150
+ * 4. Base-name match in this.baseNameIndex (instance registry from dryRun)
151
+ * 5. Raw name as-is with a warn log — last resort if nothing resolves.
152
+ */
153
+ private resolveKilledBy;
154
+ /**
80
155
  * Cleanup resources
81
156
  */
82
157
  dispose(): Promise<void>;
@@ -91,8 +166,14 @@ export interface BunTestRunnerOptions {
91
166
  */
92
167
  bunPath?: string;
93
168
  /**
94
- * Timeout per test in milliseconds
169
+ * Child-process timeout in milliseconds — the maximum wall-clock time that the
170
+ * entire `bun test` subprocess is allowed to run before it is killed.
95
171
  * @default 10000
172
+ *
173
+ * Note: this is distinct from Bun's per-test timeout configured via
174
+ * `[test].timeout` in `bunfig.toml`. The two are independent: `bunfig.toml`
175
+ * controls when Bun itself declares a single test timed out; this option
176
+ * controls when the Stryker runner forcibly kills the whole child process.
96
177
  */
97
178
  timeout?: number;
98
179
  /**
@@ -109,6 +190,25 @@ export interface BunTestRunnerOptions {
109
190
  * @example ['--bail', '--only']
110
191
  */
111
192
  bunArgs?: string[];
193
+ /**
194
+ * Explicit list of test file paths (must be non-empty when provided).
195
+ * When provided, BunTestRunner skips auto-discovery (which globs
196
+ * `**\/*.test.ts` from the current working directory) and uses exactly this
197
+ * list. Useful for restricting mutation testing to a subset, or for callers
198
+ * that run outside Stryker's sandboxed cwd and need to point at a specific
199
+ * file set. Relative paths resolve against the bun subprocess's cwd.
200
+ *
201
+ * IMPORTANT: In a Stryker mutation-testing run, each worker's cwd is set to
202
+ * a sandbox directory (`.stryker-tmp/sandbox-XYZ/`) containing sandbox copies
203
+ * of the project files. Relative paths are resolved against that sandbox cwd
204
+ * and therefore point at the mutated copies. Absolute paths bypass the sandbox
205
+ * and always point at the ORIGINAL (unmutated) files — mutations will be
206
+ * silently ignored. Always prefer relative paths in Stryker context.
207
+ *
208
+ * An empty array (`[]`) is invalid — use `undefined` or omit the option to
209
+ * fall back to auto-discovery.
210
+ */
211
+ testFiles?: string[];
112
212
  }
113
213
  /**
114
214
  * Extended Stryker options with Bun-specific configuration
@@ -168,6 +268,14 @@ export declare const strykerValidationSchema: {
168
268
  type: string;
169
269
  };
170
270
  };
271
+ testFiles: {
272
+ type: string;
273
+ description: string;
274
+ minItems: number;
275
+ items: {
276
+ type: string;
277
+ };
278
+ };
171
279
  };
172
280
  additionalProperties: boolean;
173
281
  };