@t09tanaka/test-gates 0.3.4 → 0.4.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/dist/index.d.cts CHANGED
@@ -233,6 +233,10 @@ interface ReportMutant {
233
233
  replacement?: string;
234
234
  status: string;
235
235
  location: ReportLocation;
236
+ /** Ids of the tests that ran the mutated code (`coverageAnalysis: perTest`). */
237
+ coveredBy?: string[];
238
+ /** Ids of the tests that failed with the mutant. */
239
+ killedBy?: string[];
236
240
  }
237
241
  interface ReportFile {
238
242
  source?: string;
@@ -241,6 +245,12 @@ interface ReportFile {
241
245
  /** The part of the mutation-testing-elements JSON report that the verdict depends on. */
242
246
  interface MutationReport {
243
247
  files?: Record<string, ReportFile>;
248
+ /** The spec files, with the ids of their tests (read by `mutation --affected`). */
249
+ testFiles?: Record<string, {
250
+ tests?: Array<{
251
+ id: string;
252
+ }>;
253
+ }>;
244
254
  }
245
255
  /** A survivor that no allowance covers. `allowance` can be pasted into `equivalentMutants`. */
246
256
  interface UnallowedSurvivor {
package/dist/index.d.ts CHANGED
@@ -233,6 +233,10 @@ interface ReportMutant {
233
233
  replacement?: string;
234
234
  status: string;
235
235
  location: ReportLocation;
236
+ /** Ids of the tests that ran the mutated code (`coverageAnalysis: perTest`). */
237
+ coveredBy?: string[];
238
+ /** Ids of the tests that failed with the mutant. */
239
+ killedBy?: string[];
236
240
  }
237
241
  interface ReportFile {
238
242
  source?: string;
@@ -241,6 +245,12 @@ interface ReportFile {
241
245
  /** The part of the mutation-testing-elements JSON report that the verdict depends on. */
242
246
  interface MutationReport {
243
247
  files?: Record<string, ReportFile>;
248
+ /** The spec files, with the ids of their tests (read by `mutation --affected`). */
249
+ testFiles?: Record<string, {
250
+ tests?: Array<{
251
+ id: string;
252
+ }>;
253
+ }>;
244
254
  }
245
255
  /** A survivor that no allowance covers. `allowance` can be pasted into `equivalentMutants`. */
246
256
  interface UnallowedSurvivor {
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  readText,
21
21
  resolveSettings,
22
22
  validateEquivalentMutants
23
- } from "./chunk-XMZ6NBV7.js";
23
+ } from "./chunk-AK2NTFQO.js";
24
24
 
25
25
  // src/commands/check.ts
26
26
  import fs from "fs";
package/dist/jest.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  NO_SPEC_PATTERN,
11
11
  gateSpecs,
12
12
  loadGates
13
- } from "./chunk-XMZ6NBV7.js";
13
+ } from "./chunk-AK2NTFQO.js";
14
14
 
15
15
  // src/jest.ts
16
16
  import path from "path";
package/dist/stryker.cjs CHANGED
@@ -31,9 +31,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var stryker_exports = {};
32
32
  __export(stryker_exports, {
33
33
  DEFAULT_MAX_TEST_RUNNER_REUSE: () => DEFAULT_MAX_TEST_RUNNER_REUSE,
34
- createStrykerGatesConfig: () => createStrykerGatesConfig
34
+ createStrykerGatesConfig: () => createStrykerGatesConfig,
35
+ defaultConcurrency: () => defaultConcurrency
35
36
  });
36
37
  module.exports = __toCommonJS(stryker_exports);
38
+ var import_node_os = __toESM(require("os"), 1);
39
+
40
+ // src/core/selfcheck.ts
41
+ function inCi(env) {
42
+ const ci = (env.CI ?? "").trim().toLowerCase();
43
+ return ci !== "" && ci !== "false" && ci !== "0";
44
+ }
37
45
 
38
46
  // src/load.ts
39
47
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -609,6 +617,9 @@ function resolveRootDir(rootDir) {
609
617
  // src/stryker.ts
610
618
  var WEAKENING_OPTIONS = ["ignoreStatic", "ignorers"];
611
619
  var DEFAULT_MAX_TEST_RUNNER_REUSE = 50;
620
+ function defaultConcurrency(parallelism, ci) {
621
+ return ci ? 2 : Math.min(8, Math.max(1, Math.floor(parallelism / 2)));
622
+ }
612
623
  function createStrykerGatesConfig(options = {}) {
613
624
  const { rootDir: rootDirOption, ...overrides } = options;
614
625
  for (const option of WEAKENING_OPTIONS) {
@@ -634,6 +645,7 @@ function createStrykerGatesConfig(options = {}) {
634
645
  incrementalFile: "reports/stryker-incremental.json",
635
646
  tempDirName: ".stryker-tmp",
636
647
  maxTestRunnerReuse: DEFAULT_MAX_TEST_RUNNER_REUSE,
648
+ concurrency: defaultConcurrency(import_node_os.default.availableParallelism(), inCi(process.env)),
637
649
  clearTextReporter: { logTests: false, reportTests: false },
638
650
  ...overrides,
639
651
  mutate: manifest.gates.map((gate) => gate.path),
@@ -645,5 +657,6 @@ function createStrykerGatesConfig(options = {}) {
645
657
  // Annotate the CommonJS export names for ESM import in node:
646
658
  0 && (module.exports = {
647
659
  DEFAULT_MAX_TEST_RUNNER_REUSE,
648
- createStrykerGatesConfig
660
+ createStrykerGatesConfig,
661
+ defaultConcurrency
649
662
  });
@@ -12,13 +12,27 @@ interface StrykerGatesOptions {
12
12
  * mutants the speed stayed the same to the end.
13
13
  */
14
14
  declare const DEFAULT_MAX_TEST_RUNNER_REUSE = 50;
15
+ /**
16
+ * How many test runners Stryker starts when neither the config nor the command line says
17
+ * (`concurrency`). Stryker's own default is one fewer than the cores (on more than four), but
18
+ * each of its runners is a Jest or Vitest that does work besides the tests (transforms, coverage),
19
+ * and the machine is rarely free for the run alone: half of the cores, at most 8. Measured on
20
+ * two projects on a machine with 12 cores, 6 runners took about half the time of 2, with the
21
+ * same numbers of killed, survived and timed-out mutants. In CI (`CI` set) 2, the cores of the
22
+ * usual hosted runner: more runners than cores only make the mutants run out of time.
23
+ *
24
+ * @param parallelism What `os.availableParallelism()` says.
25
+ */
26
+ declare function defaultConcurrency(parallelism: number, ci: boolean): number;
15
27
  /**
16
28
  * Stryker config for the gates: mutate exactly the gates, never fail on the score
17
29
  * (`thresholds.break: null`), and write the JSON report that `test-gates mutation` judges.
18
30
  *
19
31
  * `mutate`, `thresholds.break` and `jsonReporter.fileName` are always set here, and `json` is
20
32
  * always among the reporters. Options that take mutants out of the evaluation are rejected.
33
+ * `concurrency` is defaultConcurrency unless the options set it; `--concurrency` on Stryker's
34
+ * command line wins over both.
21
35
  */
22
36
  declare function createStrykerGatesConfig(options?: StrykerGatesOptions): Record<string, unknown>;
23
37
 
24
- export { DEFAULT_MAX_TEST_RUNNER_REUSE, type StrykerGatesOptions, createStrykerGatesConfig };
38
+ export { DEFAULT_MAX_TEST_RUNNER_REUSE, type StrykerGatesOptions, createStrykerGatesConfig, defaultConcurrency };
package/dist/stryker.d.ts CHANGED
@@ -12,13 +12,27 @@ interface StrykerGatesOptions {
12
12
  * mutants the speed stayed the same to the end.
13
13
  */
14
14
  declare const DEFAULT_MAX_TEST_RUNNER_REUSE = 50;
15
+ /**
16
+ * How many test runners Stryker starts when neither the config nor the command line says
17
+ * (`concurrency`). Stryker's own default is one fewer than the cores (on more than four), but
18
+ * each of its runners is a Jest or Vitest that does work besides the tests (transforms, coverage),
19
+ * and the machine is rarely free for the run alone: half of the cores, at most 8. Measured on
20
+ * two projects on a machine with 12 cores, 6 runners took about half the time of 2, with the
21
+ * same numbers of killed, survived and timed-out mutants. In CI (`CI` set) 2, the cores of the
22
+ * usual hosted runner: more runners than cores only make the mutants run out of time.
23
+ *
24
+ * @param parallelism What `os.availableParallelism()` says.
25
+ */
26
+ declare function defaultConcurrency(parallelism: number, ci: boolean): number;
15
27
  /**
16
28
  * Stryker config for the gates: mutate exactly the gates, never fail on the score
17
29
  * (`thresholds.break: null`), and write the JSON report that `test-gates mutation` judges.
18
30
  *
19
31
  * `mutate`, `thresholds.break` and `jsonReporter.fileName` are always set here, and `json` is
20
32
  * always among the reporters. Options that take mutants out of the evaluation are rejected.
33
+ * `concurrency` is defaultConcurrency unless the options set it; `--concurrency` on Stryker's
34
+ * command line wins over both.
21
35
  */
22
36
  declare function createStrykerGatesConfig(options?: StrykerGatesOptions): Record<string, unknown>;
23
37
 
24
- export { DEFAULT_MAX_TEST_RUNNER_REUSE, type StrykerGatesOptions, createStrykerGatesConfig };
38
+ export { DEFAULT_MAX_TEST_RUNNER_REUSE, type StrykerGatesOptions, createStrykerGatesConfig, defaultConcurrency };
package/dist/stryker.js CHANGED
@@ -2,12 +2,17 @@ import {
2
2
  resolveRootDir
3
3
  } from "./chunk-C4R3RDHF.js";
4
4
  import {
5
+ inCi,
5
6
  loadGates
6
- } from "./chunk-XMZ6NBV7.js";
7
+ } from "./chunk-AK2NTFQO.js";
7
8
 
8
9
  // src/stryker.ts
10
+ import os from "os";
9
11
  var WEAKENING_OPTIONS = ["ignoreStatic", "ignorers"];
10
12
  var DEFAULT_MAX_TEST_RUNNER_REUSE = 50;
13
+ function defaultConcurrency(parallelism, ci) {
14
+ return ci ? 2 : Math.min(8, Math.max(1, Math.floor(parallelism / 2)));
15
+ }
11
16
  function createStrykerGatesConfig(options = {}) {
12
17
  const { rootDir: rootDirOption, ...overrides } = options;
13
18
  for (const option of WEAKENING_OPTIONS) {
@@ -33,6 +38,7 @@ function createStrykerGatesConfig(options = {}) {
33
38
  incrementalFile: "reports/stryker-incremental.json",
34
39
  tempDirName: ".stryker-tmp",
35
40
  maxTestRunnerReuse: DEFAULT_MAX_TEST_RUNNER_REUSE,
41
+ concurrency: defaultConcurrency(os.availableParallelism(), inCi(process.env)),
36
42
  clearTextReporter: { logTests: false, reportTests: false },
37
43
  ...overrides,
38
44
  mutate: manifest.gates.map((gate) => gate.path),
@@ -43,5 +49,6 @@ function createStrykerGatesConfig(options = {}) {
43
49
  }
44
50
  export {
45
51
  DEFAULT_MAX_TEST_RUNNER_REUSE,
46
- createStrykerGatesConfig
52
+ createStrykerGatesConfig,
53
+ defaultConcurrency
47
54
  };
package/dist/vitest.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  NO_SPEC_PATTERN,
11
11
  gateSpecs,
12
12
  loadGates
13
- } from "./chunk-XMZ6NBV7.js";
13
+ } from "./chunk-AK2NTFQO.js";
14
14
 
15
15
  // src/vitest.ts
16
16
  import path from "path";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@t09tanaka/test-gates",
3
- "version": "0.3.4",
3
+ "version": "0.4.0",
4
4
  "description": "Test gates for the code that must not be wrong: per-file 100% coverage as the floor, mutation testing with a per-mutant allow list as the real check.",
5
5
  "author": "t09tanaka",
6
6
  "license": "MIT",