@freshworks/shiftleft-tools 1.1.8

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.
Files changed (106) hide show
  1. package/README.md +351 -0
  2. package/bin/shiftleft.js +95 -0
  3. package/package.json +57 -0
  4. package/src/commands/doctor.js +208 -0
  5. package/src/commands/init-postman.js +298 -0
  6. package/src/commands/init-rules.js +78 -0
  7. package/src/commands/link.js +172 -0
  8. package/src/commands/protect.js +61 -0
  9. package/src/commands/run-tests.js +182 -0
  10. package/src/commands/setup-pipeline.js +209 -0
  11. package/src/commands/update.js +203 -0
  12. package/src/index.js +4 -0
  13. package/src/utils/copy-tree.js +98 -0
  14. package/src/utils/gitignore.js +26 -0
  15. package/src/utils/logger.js +9 -0
  16. package/src/utils/manifest.js +145 -0
  17. package/src/utils/stack.js +80 -0
  18. package/src/utils/template.js +135 -0
  19. package/templates/AGENTS.md +109 -0
  20. package/templates/CLAUDE.md +3 -0
  21. package/templates/jenkins/Jenkinsfile-java.groovy +432 -0
  22. package/templates/jenkins/Jenkinsfile-node.groovy +450 -0
  23. package/templates/postman/.husky/pre-commit +19 -0
  24. package/templates/postman/.prettierrc.json +5 -0
  25. package/templates/postman/README.md.ejs +147 -0
  26. package/templates/postman/collections/01-core.json.ejs +91 -0
  27. package/templates/postman/config/local.json.ejs +12 -0
  28. package/templates/postman/config/staging.json.ejs +26 -0
  29. package/templates/postman/environments/local.postman_environment.json.ejs +31 -0
  30. package/templates/postman/environments/staging.postman_environment.json.ejs +31 -0
  31. package/templates/postman/gitignore +16 -0
  32. package/templates/postman/npmrc +31 -0
  33. package/templates/postman/package.json.ejs +66 -0
  34. package/templates/postman/run-all-shim.sh +16 -0
  35. package/templates/postman/scripts/auth/generate-jwt.sh +113 -0
  36. package/templates/postman/scripts/auth/get-issuer-secret.sh +140 -0
  37. package/templates/postman/scripts/infra/start-mocks.sh +138 -0
  38. package/templates/postman/scripts/infra/stop-mocks.sh +43 -0
  39. package/templates/postman/scripts/lib/api_coverage.py +1122 -0
  40. package/templates/postman/scripts/lib/cleanup-reports.sh +101 -0
  41. package/templates/postman/scripts/lib/cleanup-stryker.sh +44 -0
  42. package/templates/postman/scripts/lib/report_combined.py +527 -0
  43. package/templates/postman/scripts/lib/report_consolidated.py +363 -0
  44. package/templates/postman/scripts/lib/report_generator.py +121 -0
  45. package/templates/postman/scripts/lib/report_migration.py +156 -0
  46. package/templates/postman/scripts/lib/report_mutation.py +110 -0
  47. package/templates/postman/scripts/lib/report_unit.py +353 -0
  48. package/templates/postman/scripts/lib/report_utils.py +973 -0
  49. package/templates/postman/scripts/report-generators/generate-consolidated-report.sh +445 -0
  50. package/templates/postman/scripts/report-generators/java-api-coverage-matrix.sh +257 -0
  51. package/templates/postman/scripts/report-generators/mutation-report.sh +672 -0
  52. package/templates/postman/scripts/report-generators/node-api-coverage-matrix.sh +167 -0
  53. package/templates/postman/scripts/report-generators/stage-report-artifacts.sh +27 -0
  54. package/templates/postman/scripts/run-all.sh +452 -0
  55. package/templates/postman/scripts/runners/run-mutation-tests.sh +113 -0
  56. package/templates/postman/scripts/runners/run-tests-local.sh +936 -0
  57. package/templates/postman/scripts/runners/run-tests-staging.sh +741 -0
  58. package/templates/postman-node/README.md.ejs +26 -0
  59. package/templates/postman-node/collections/crud/01-bootstrap.json.ejs +34 -0
  60. package/templates/postman-node/config/local.json.ejs +46 -0
  61. package/templates/postman-node/config/staging.json.ejs +31 -0
  62. package/templates/postman-node/local.test.env.ejs +3 -0
  63. package/templates/postman-node/mocks/external.js +14 -0
  64. package/templates/postman-node/package.json.ejs +39 -0
  65. package/templates/postman-node/requirements.txt +1 -0
  66. package/templates/postman-node/scripts/database/cleanup-mysql.sh +12 -0
  67. package/templates/postman-node/scripts/database/run-migrations.js +29 -0
  68. package/templates/postman-node/scripts/database/start-mysql.sh +34 -0
  69. package/templates/postman-node/scripts/database/wait-for-mysql.sh +36 -0
  70. package/templates/postman-node/scripts/lib/api_coverage_node.py +1137 -0
  71. package/templates/postman-node/scripts/lib/fetch-jwt.sh +86 -0
  72. package/templates/postman-node/scripts/lib/run-newman.sh +104 -0
  73. package/templates/postman-node/scripts/lib/setup-database.sh +55 -0
  74. package/templates/postman-node/scripts/lib/start-app.sh +48 -0
  75. package/templates/postman-node/scripts/lib/utils.sh +114 -0
  76. package/templates/postman-node/scripts/report-generators/stage-report-artifacts.sh +26 -0
  77. package/templates/postman-node/scripts/run-all.sh +303 -0
  78. package/templates/postman-node/scripts/runners/run-tests.sh +123 -0
  79. package/templates/postman-node/scripts/setup-mocks.js.ejs +29 -0
  80. package/templates/postman-node/stryker.config.js.ejs +51 -0
  81. package/templates/rules/local-test-setup.mdc +420 -0
  82. package/templates/rules/testing-node.mdc +66 -0
  83. package/templates/rules/testing.mdc +248 -0
  84. package/templates/skills/_shared/postman-standards.md +380 -0
  85. package/templates/skills/enhance-test-pipeline/SKILL-java.md +483 -0
  86. package/templates/skills/enhance-test-pipeline/SKILL-node.md +431 -0
  87. package/templates/skills/enhance-test-pipeline/SKILL.md +9 -0
  88. package/templates/skills/review-test-suite/SKILL-java.md +137 -0
  89. package/templates/skills/review-test-suite/SKILL-node.md +78 -0
  90. package/templates/skills/review-test-suite/SKILL.md +9 -0
  91. package/templates/skills/run-test-suite/SKILL-java.md +186 -0
  92. package/templates/skills/run-test-suite/SKILL-node.md +191 -0
  93. package/templates/skills/run-test-suite/SKILL.md +9 -0
  94. package/templates/skills/setup-api-tests/SKILL-java.md +1094 -0
  95. package/templates/skills/setup-api-tests/SKILL-node.md +141 -0
  96. package/templates/skills/setup-api-tests/SKILL.md +9 -0
  97. package/templates/skills/setup-mutation-tests/SKILL-java.md +303 -0
  98. package/templates/skills/setup-mutation-tests/SKILL-node.md +408 -0
  99. package/templates/skills/setup-mutation-tests/SKILL.md +9 -0
  100. package/templates/skills/setup-test-pipeline/SKILL-java.md +454 -0
  101. package/templates/skills/setup-test-pipeline/SKILL-node.md +318 -0
  102. package/templates/skills/setup-test-pipeline/SKILL.md +9 -0
  103. package/templates/skills/write-api-tests/SKILL-java.md +115 -0
  104. package/templates/skills/write-api-tests/SKILL-node.md +83 -0
  105. package/templates/skills/write-api-tests/SKILL.md +9 -0
  106. package/templates/stryker.config.js +50 -0
@@ -0,0 +1,408 @@
1
+ # Setup Mutation Tests — Node.js / Express
2
+
3
+ Add Stryker mutation testing to a Node.js project using an **inspect-first, minimal-scope** approach.
4
+
5
+ ## CRITICAL: Mutate only meaningful files
6
+
7
+ Stryker is **orders of magnitude slower** than unit tests. A broad `mutate: ['src/**/*.js']` on a medium service can take **30–60+ minutes** and produce noise from files that have no real logic to test.
8
+
9
+ **You MUST:**
10
+
11
+ 1. **Never** use `src/**` or `src/**/*.js` as the mutate scope
12
+ 2. **Include only** files with branching business logic (conditions, loops, transformations, validation)
13
+ 3. **Exclude** thin wrappers, entry points, config, models, and route wiring
14
+ 4. **Audit every folder** under `src/` before writing `stryker.config.js` — do not copy-paste from another repo
15
+ 5. **Confirm file count** with the user before saving config (see Phase 2)
16
+
17
+ **Two speed levers (use both):**
18
+
19
+ | Lever | What | Effect |
20
+ |-------|------|--------|
21
+ | **Narrow `mutate` scope** | Only actions, services, serializers, middlewares (+ selective helpers) | Full scan: minutes not hours |
22
+ | **`since` mode** | `yarn mutation-tests` — only files changed vs `origin/master` | Local runs: often under 1 min |
23
+
24
+ Reserve `yarn mutation-tests:full` for Jenkins / pre-merge only.
25
+
26
+ ## When to Use
27
+
28
+ Invoke when the user says:
29
+ - "setup mutation tests", "add mutation testing", "add Stryker"
30
+ - "measure test quality", "check unit test quality"
31
+ - "my unit tests pass but I want to know if they're strong"
32
+
33
+ ---
34
+
35
+ ## What is Mutation Testing?
36
+
37
+ Stryker makes small automated changes (mutations) to your source code — flipping `>` to `>=`, removing return values, negating conditions — then runs your Mocha/Jest tests against each mutation.
38
+
39
+ - **Mutant killed** — your tests caught the change (good)
40
+ - **Mutant survived** — your tests didn't catch it (weak assertion)
41
+
42
+ Target: 80% high threshold, 60% low threshold. `break: 0` means CI never hard-fails on score alone — only on test failures.
43
+
44
+ ---
45
+
46
+ ## Why `since` mode matters
47
+
48
+ Stryker on a large Node codebase can take 10-20 minutes. Running it on every local change makes it unusable. The solution:
49
+
50
+ - **Local / `yarn mutation-tests`** — `since` mode: only mutates files changed vs `origin/master`. Takes 30 seconds if you changed 2 files. If no scoped files changed, exits immediately.
51
+ - **Jenkins / `yarn mutation-tests:full`** — full mode: all scoped files, `--force` flag. Runs the complete scan. Slow but complete.
52
+
53
+ This is the critical difference from Java PIT — Stryker needs this two-mode approach to be practical.
54
+
55
+ ---
56
+
57
+ ## Phase 1: Inspect
58
+
59
+ ### 1.1 Check if Stryker already exists
60
+
61
+ ```bash
62
+ cat package.json | grep -i stryker
63
+ ls stryker.config.js stryker.config.ts 2>/dev/null
64
+ ```
65
+
66
+ - Found → check the existing configuration, skip to Phase 4 (Verify)
67
+ - Not found → continue
68
+
69
+ ### 1.2 Discover the test runner
70
+
71
+ ```bash
72
+ cat package.json | grep -E '"test"|"mocha"|"jest"'
73
+ ```
74
+
75
+ This determines which Stryker runner plugin to install (`@stryker-mutator/mocha-runner` vs `@stryker-mutator/jest-runner`).
76
+
77
+ ### 1.3 Discover the source directory structure
78
+
79
+ ```bash
80
+ ls src/
81
+ find src -maxdepth 1 -type d | sort
82
+ ```
83
+
84
+ Map what you find to these categories:
85
+
86
+ | Folder | Include? | Reason |
87
+ |--------|----------|--------|
88
+ | `src/actions/` | **YES** | Core business logic |
89
+ | `src/services/` | **YES** | Core business logic |
90
+ | `src/serializers/` | **YES** if transforms data | Skip if pass-through only |
91
+ | `src/middlewares/` | **YES** if validates/auth logic | Skip if one-line `next()` |
92
+ | `src/validators/` | **YES** | Validation rules |
93
+ | `src/helpers/` | **FILE BY FILE** | Often mostly external SDK wrappers — see 1.4 |
94
+ | `src/controllers/` | **NO** | HTTP wiring — covered by Postman |
95
+ | `src/routes/` | **NO** | Route registration only |
96
+ | `src/models/` | **NO** | Sequelize/ORM definitions — no logic to kill |
97
+ | `src/config/` | **NO** | Static config |
98
+ | `src/constants/` | **NO** | Constants |
99
+ | `src/migrations/` | **NO** | DB migrations |
100
+ | `src/seeders/` | **NO** | Seed data |
101
+ | `src/clients/` | **NO** | HTTP client wrappers |
102
+ | `src/index.js`, `src/app.js` | **NO** | Bootstrap |
103
+
104
+ ### 1.3b Count files before proceeding
105
+
106
+ After deciding folders, **count how many files** will be mutated:
107
+
108
+ ```bash
109
+ # Example — adjust globs to match your planned mutate array
110
+ find src/actions src/services src/middlewares -name '*.js' 2>/dev/null | wc -l
111
+ ```
112
+
113
+ | Files in scope | Action |
114
+ |----------------|--------|
115
+ | **under 40** | Good — proceed |
116
+ | **40–80** | Review exclusions — drop pass-through serializers/helpers |
117
+ | **over 80** | **Stop** — scope is too wide; exclude more helpers/models or split by package |
118
+
119
+ Show the count to the user in Phase 3. If over 80, ask which folders to drop before continuing.
120
+
121
+ ### 1.4 Inspect helpers (if `src/helpers/` exists)
122
+
123
+ ```bash
124
+ ls src/helpers/
125
+ ```
126
+
127
+ For each helper file, check if it only wraps an external service with no branching:
128
+
129
+ ```bash
130
+ # Read the file — look for: does it only call an external SDK/API with no if/else?
131
+ cat src/helpers/aws.js # Wraps AWS SDK → EXCLUDE
132
+ cat src/helpers/freshid.js # Wraps FreshID API → EXCLUDE
133
+ cat src/helpers/utils.js # Has if/else logic → INCLUDE
134
+ ```
135
+
136
+ Files to typically EXCLUDE from helpers (they only wrap external services):
137
+ - `aws.js`, `chargebee.js`, `freshid.js`, `launchdarkly.js`
138
+ - `emailNotifications.js`, `analytics.js`, `observability.js`
139
+ - `mcp-gateway.js`, `mcp-gateway-util.js`
140
+ - `mp-listings.js`, `mp-apps.js`
141
+ - `constants.js`, `config.js`
142
+ - `helpers/validator/schema/**` (JSON schema files, not logic)
143
+
144
+ Files to typically INCLUDE: anything with **branching or computation** (`if`, `switch`, `for`, `?.`, `??`, `Math.`, string transforms).
145
+
146
+ **Per-file inclusion test** — run for each candidate helper:
147
+
148
+ ```bash
149
+ # Files with few branches are usually not worth mutating
150
+ for f in src/helpers/*.js; do
151
+ branches=$(grep -cE '\b(if|else|switch|for|while|\?\?|\?\.)\b' "$f" 2>/dev/null || echo 0)
152
+ lines=$(wc -l < "$f" | tr -d ' ')
153
+ echo "$f branches=$branches lines=$lines"
154
+ done
155
+ ```
156
+
157
+ | Signal | Decision |
158
+ |--------|----------|
159
+ | Only calls external SDK, no `if`/`switch` | **EXCLUDE** |
160
+ | `branches=0` and file is under 30 lines | **EXCLUDE** |
161
+ | `branches >= 1` or non-trivial transform | **INCLUDE** |
162
+
163
+ Read the file if unsure — **never include by folder glob alone** when `src/helpers/` is mixed.
164
+
165
+ ### 1.5 Find unit test location
166
+
167
+ ```bash
168
+ ls test/unit/ test/ 2>/dev/null | head -20
169
+ cat package.json | grep -A3 '"test"'
170
+ ```
171
+
172
+ Note the test file pattern (e.g., `test/unit/**/*.test.js`) and any setup files (e.g., `test/unit/setup.js`).
173
+
174
+ ---
175
+
176
+ ## Phase 2: Reason
177
+
178
+ Build the **smallest** `mutate` array that still covers real business logic.
179
+
180
+ **Rules:**
181
+
182
+ - One glob **per included folder** — only folders that exist in this repo
183
+ - Add `!` exclusions for every external-wrapper file under included folders (especially `helpers/`)
184
+ - **Do not** add `src/helpers/**/*.js` unless you listed specific included files — prefer listing individual helpers or a tight subfolder
185
+ - **Never** add `src/controllers/**`, `src/routes/**`, `src/models/**`, `src/config/**`
186
+
187
+ **mutate array example (freshapps-style layout):**
188
+
189
+ ```javascript
190
+ mutate: [
191
+ 'src/actions/**/*.js',
192
+ 'src/serializers/**/*.js',
193
+ 'src/middlewares/**/*.js',
194
+ 'src/helpers/workflow.js', // only if it has branching logic
195
+ '!src/helpers/aws.js',
196
+ '!src/helpers/freshid.js',
197
+ // ... every external wrapper explicitly excluded
198
+ ],
199
+ ```
200
+
201
+ **Anti-patterns (reject if user or template suggests these):**
202
+
203
+ ```javascript
204
+ // WRONG — too broad, will run forever
205
+ mutate: ['src/**/*.js']
206
+
207
+ // WRONG — helpers folder is mixed
208
+ mutate: ['src/helpers/**/*.js']
209
+
210
+ // WRONG — controllers have no unit-testable logic
211
+ mutate: ['src/controllers/**/*.js']
212
+ ```
213
+
214
+ **Stryker runner** — `mocha` or `jest` based on 1.2.
215
+
216
+ **Two scripts to add to package.json**:
217
+ - `"mutation-tests"` — `since` mode (fast, local dev): `./postman/scripts/runners/run-mutation-tests.sh`
218
+ - `"mutation-tests:full"` — full mode (Jenkins CI): `./postman/scripts/runners/run-mutation-tests.sh --full`
219
+
220
+ ---
221
+
222
+ ## Phase 3: Confirm
223
+
224
+ Show the user a summary before writing anything:
225
+
226
+ ```
227
+ Mutation scope audit:
228
+ INCLUDED (32 files):
229
+ src/actions/ 12 files
230
+ src/serializers/ 8 files
231
+ src/middlewares/ 5 files
232
+ src/helpers/ 7 files (workflow.js, billing.js, …)
233
+ EXCLUDED (not meaningful to mutate):
234
+ src/controllers/ 14 files — HTTP wiring
235
+ src/helpers/ 11 files — aws.js, freshid.js, … (SDK wrappers)
236
+ src/models/ 9 files — ORM definitions
237
+
238
+ Estimated full-scan time: ~5–8 min (32 files) — NOT hours
239
+
240
+ Stryker config:
241
+ mutate: [listed paths only — no src/**]
242
+ coverageAnalysis: perTest
243
+ incremental: true
244
+ Local: yarn mutation-tests (since mode — changed files only)
245
+ CI: yarn mutation-tests:full (full scope above)
246
+
247
+ Proceed? [Y/n]
248
+ ```
249
+
250
+ If estimated file count is over 80, **do not proceed** until scope is reduced.
251
+
252
+ Wait for confirmation before writing any files.
253
+
254
+ ---
255
+
256
+ ## Phase 4: Execute
257
+
258
+ ### 4.1 Install dependencies
259
+
260
+ ```bash
261
+ yarn add --dev @stryker-mutator/core @stryker-mutator/mocha-runner
262
+ # or for Jest:
263
+ yarn add --dev @stryker-mutator/core @stryker-mutator/jest-runner
264
+ ```
265
+
266
+ ### 4.2 Create stryker.config.js
267
+
268
+ ```javascript
269
+ 'use strict';
270
+
271
+ /** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */
272
+ module.exports = {
273
+ packageManager: 'yarn',
274
+ testRunner: 'mocha', // or 'jest'
275
+ reporters: ['html', 'json', 'clear-text', 'progress'],
276
+ htmlReporter: {
277
+ fileName: 'coverage/mutation/index.html'
278
+ },
279
+ jsonReporter: {
280
+ fileName: 'coverage/mutation/mutation-report.json'
281
+ },
282
+ mutate: [
283
+ // ONLY folders/files from Phase 1 audit — never src/**
284
+ 'src/actions/**/*.js',
285
+ 'src/serializers/**/*.js',
286
+ 'src/middlewares/**/*.js',
287
+ // Add individual helpers OR exclude the whole folder — avoid helpers/**
288
+ // 'src/helpers/workflow.js',
289
+ '!src/controllers/**',
290
+ '!src/routes/**',
291
+ '!src/models/**',
292
+ '!src/config/**',
293
+ '!src/helpers/validator/schema/**/*.js',
294
+ '!src/helpers/aws.js',
295
+ '!src/helpers/chargebee.js',
296
+ '!src/helpers/freshid.js',
297
+ '!src/helpers/launchdarkly.js',
298
+ '!src/helpers/emailNotifications.js',
299
+ '!src/helpers/analytics.js',
300
+ '!src/helpers/observability.js',
301
+ '!src/helpers/constants.js',
302
+ '!src/helpers/config.js'
303
+ ],
304
+ coverageAnalysis: 'perTest', // Fastest analysis mode
305
+ concurrency: 4,
306
+ incremental: true, // Reuse previous results — speeds up repeated runs
307
+ incrementalFile: 'coverage/mutation/stryker-incremental.json',
308
+ ignorePatterns: ['postman/**', 'coverage/**'],
309
+ mochaOpts: {
310
+ // REPLACE with actual test file pattern from Phase 1
311
+ files: 'test/unit/**/*.test.js',
312
+ require: ['test/unit/setup.js'], // Remove if no setup file
313
+ timeout: 10000
314
+ },
315
+ thresholds: {
316
+ high: 80,
317
+ low: 60,
318
+ break: 0 // Never hard-fail CI on score alone — only on test failures
319
+ },
320
+ tempDirName: 'coverage/mutation/.stryker-tmp'
321
+ };
322
+ ```
323
+
324
+ ### 4.3 Add scripts to package.json
325
+
326
+ ```json
327
+ {
328
+ "scripts": {
329
+ "mutation-tests": "./postman/scripts/runners/run-mutation-tests.sh",
330
+ "mutation-tests:full": "./postman/scripts/runners/run-mutation-tests.sh --full"
331
+ }
332
+ }
333
+ ```
334
+
335
+ ### 4.4 Stage run-mutation-tests.sh from the shiftleft-tools package
336
+
337
+ `runners/run-mutation-tests.sh` and `lib/cleanup-stryker.sh` are library scripts —
338
+ they're staged from the installed package, not copied by hand. Run:
339
+
340
+ ```bash
341
+ shiftleft stage-scripts
342
+ ```
343
+
344
+ This pulls the current versions into `postman/scripts/` (gitignored, made
345
+ executable) and is re-run automatically by `shiftleft test`. The `package.json`
346
+ `mutation-tests` scripts above invoke `./postman/scripts/runners/run-mutation-tests.sh`,
347
+ which will be present after staging.
348
+
349
+ ### 4.5 Add .gitignore entries
350
+
351
+ Add to `.gitignore`:
352
+ ```
353
+ coverage/mutation/.stryker-tmp/
354
+ .stryker-incremental.json
355
+ stryker.log
356
+ ```
357
+
358
+ ---
359
+
360
+ ## Phase 5: Verify
361
+
362
+ Run in `since` mode first (only changed files — fast):
363
+
364
+ ```bash
365
+ yarn mutation-tests
366
+ ```
367
+
368
+ Expected output:
369
+ - If no scoped files changed vs origin/master: "No scoped source files changed vs origin/master; skipping Stryker." (exit 0, this is correct)
370
+ - If files changed: shows mutation score for changed files
371
+
372
+ Run full mode to verify the full scope works:
373
+
374
+ ```bash
375
+ yarn mutation-tests:full
376
+ ```
377
+
378
+ Report is generated at `coverage/mutation/index.html`.
379
+
380
+ ### Report results to the user
381
+
382
+ After the run completes:
383
+ 1. Report the mutation score — e.g. "74% of mutants killed (high: 80%, low: 60%)"
384
+ 2. Identify surviving mutants — list which classes have weak coverage
385
+ 3. Suggest fixes for top surviving mutants:
386
+
387
+ | Surviving Mutant Type | Likely Cause | Fix |
388
+ |---|---|---|
389
+ | Negated condition | Test doesn't check the false branch | Add test for falsy case |
390
+ | Removed method call | Side effect not asserted | Use `sinon.spy` and assert `.calledWith()` |
391
+ | String literal changed | Hardcoded string not asserted | Assert on the actual return value |
392
+ | Removed block | Error branch not tested | Add test that triggers the error path |
393
+
394
+ ---
395
+
396
+ ## Verification Checklist
397
+
398
+ - [ ] `@stryker-mutator/core` installed in devDependencies
399
+ - [ ] `stryker.config.js` `mutate` array has **no** `src/**` or `src/helpers/**` blanket globs
400
+ - [ ] Mutate scope is **under 80 files** (count with `find` before saving)
401
+ - [ ] Controllers, routes, models, config, migrations **excluded**
402
+ - [ ] External-service wrapper files excluded from `mutate`
403
+ - [ ] `coverageAnalysis: 'perTest'` and `incremental: true` set
404
+ - [ ] `mutation-tests` and `mutation-tests:full` scripts added to package.json
405
+ - [ ] `run-mutation-tests.sh` copied and executable
406
+ - [ ] `yarn mutation-tests` works (since mode)
407
+ - [ ] `yarn mutation-tests:full` works (full mode)
408
+ - [ ] Score reported to user
@@ -0,0 +1,9 @@
1
+ # Setup Mutation Tests Skill
2
+
3
+ ## Detect Project Type First
4
+
5
+ Before doing anything, detect the stack:
6
+
7
+ 1. `pom.xml` in project root → **Java Spring Boot** → read `SKILL-java.md` in this folder and follow it completely
8
+ 2. `package.json` (no `pom.xml`) → **Node.js** → read `SKILL-node.md` in this folder and follow it completely (mutate **only meaningful business-logic files** — never `src/**`)
9
+ 3. If unsure → ask the user: "Is this a Java or Node.js project?"