Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ rust/target/
test-results/
playwright-report/
blob-report/
.stryker-tmp/
reports/
7 changes: 6 additions & 1 deletion ts/packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
"lint": "turbo run _lint",
"_lint": "eslint . --fix --cache --max-warnings 0",
"conformance-check": "turbo run _conformance-check",
"_conformance-check": "vitest run test/conformance.test.ts"
"_conformance-check": "vitest run test/conformance.test.ts",
"mutation": "turbo run _mutation",
"_mutation": "stryker run stryker.config.ts"
},
"dependencies": {
"cbor2": "2.3.0",
Expand All @@ -41,6 +43,9 @@
"@semantic-release/github": "12.0.9",
"@semantic-release/npm": "13.1.5",
"@semantic-release/release-notes-generator": "14.1.1",
"@stryker-mutator/api": "10.0.0",
"@stryker-mutator/core": "10.0.0",
"@stryker-mutator/typescript-checker": "10.0.0",
"@types/node": "26.4.1",
"conventional-changelog-conventionalcommits": "10.4.0",
"eslint": "10.10.0",
Expand Down
35 changes: 35 additions & 0 deletions ts/packages/core/stryker.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { PartialStrykerOptions } from "@stryker-mutator/api/core";

// A real .ts file, not stryker.config.mjs with a `@type` JSDoc annotation (Stryker's own documented pattern): Stryker's own config loader is a plain `import()` under the hood (ConfigReader#importJSConfig in @stryker-mutator/core) with no opinion at all about the extension it is given, and Node's own ESM loader on this workspace's pinned version (.tool-versions: nodejs 26) strips a .ts file's type syntax natively with no flag and no loader hook -- so `stryker run stryker.config.ts` resolves straight through that native support, with no shim file, and Stryker's own option validation still runs afterward exactly as it would for a .js config.
//
// testRunner is "command", not "@stryker-mutator/vitest-runner", despite this package running on vitest: vitest-runner@10.0.0 crashes on init against vitest@5.0.0 with "TypeError: Converting circular structure to JSON" while serialising vitest's own resolved config (VitestTestRunner.init, vitest-test-runner.js), a confirmed upstream incompatibility with no fix or compatible version pairing available (see stryker-mutator/stryker-js's vitest-runner issue tracker; independently corroborated by Chris0Jeky/Taskdeck#3038 hitting the identical "0.00 tests per mutant" symptom against the same vitest major). The command runner re-runs `pnpm test` as a subprocess per mutant instead of driving vitest in-process, so it loses per-test coverage analysis (every mutant re-runs the whole suite rather than only its covering tests) but actually produces a real result. Revisit once vitest-runner ships a fix for this.
const config: PartialStrykerOptions = {
packageManager: "pnpm",
// src/generated/protocol.ts is cddl.js output, not hand-written logic -- mutating it would just generate noise against code nobody edits directly, exactly the exclusion the issue that added this config asked for.
mutate: ["src/**/*.ts", "!src/**/*.test.ts", "!src/generated/**"],
testRunner: "command",
// test/conformance.test.ts is excluded here, not mutated around: Stryker's sandbox for a command-runner mutant is confined to this package's own directory, but that test reads its vectors from a sibling package (`../../../../conformance/*.json`, outside the sandbox root) -- it fails with ENOENT for every mutant regardless of the mutation, which is a sandboxing mismatch, not a real "no coverage" signal. `_conformance-check` already runs this suite as its own separate, unmutated CI step.
commandRunner: {
command: "pnpm exec vitest run --exclude test/conformance.test.ts",
},
plugins: ["@stryker-mutator/typescript-checker"],
checkers: ["typescript"],
tsconfigFile: "tsconfig.json",
// The command runner only sees the subprocess's exit code, never which tests ran -- there's no per-test signal to analyse coverage from, so Stryker itself forces this to "off" for this runner regardless of what's configured here. "ignoreStatic" is incompatible with coverage analysis "off" (Stryker refuses to start otherwise) -- moot anyway, since the command runner re-runs the whole suite for every mutant regardless of whether it's static or per-test, so there's no separate static-mutant cost to skip here the way there would be under a coverage-aware runner.
coverageAnalysis: "off",
incremental: true,
// dist/coverage/.turbo are build/tooling output Stryker would otherwise copy into every mutant's own sandbox for nothing -- none of it is ever read by a test.
ignorePatterns: ["dist", "coverage", ".turbo"],
reporters: ["progress", "clear-text", "html"],
tempDirName: ".stryker-tmp",
cleanTempDir: true,
concurrency: 4,
timeoutMS: 30_000,
thresholds: {
high: 80,
low: 60,
// No `break` yet -- this config's own job is a first baseline report (wire-mesh#67); fixing what it finds and setting a real, measured break threshold is wire-mesh#68's own separate work. Picking a break value before a baseline exists would be exactly the arbitrary-magic-number pattern this codebase's own no-magic-numbers convention already refuses elsewhere.
},
};

export default config;
2 changes: 1 addition & 1 deletion ts/packages/core/tsconfig.node.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"compilerOptions": {
"allowImportingTsExtensions": true
},
"include": ["generate.ts", "tsdown.config.ts", "eslint.config.ts", "release.config.ts", "test/**/*.ts"]
"include": ["generate.ts", "tsdown.config.ts", "eslint.config.ts", "release.config.ts", "stryker.config.ts", "test/**/*.ts"]
}
Loading