@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.
- package/README.md +351 -0
- package/bin/shiftleft.js +95 -0
- package/package.json +57 -0
- package/src/commands/doctor.js +208 -0
- package/src/commands/init-postman.js +298 -0
- package/src/commands/init-rules.js +78 -0
- package/src/commands/link.js +172 -0
- package/src/commands/protect.js +61 -0
- package/src/commands/run-tests.js +182 -0
- package/src/commands/setup-pipeline.js +209 -0
- package/src/commands/update.js +203 -0
- package/src/index.js +4 -0
- package/src/utils/copy-tree.js +98 -0
- package/src/utils/gitignore.js +26 -0
- package/src/utils/logger.js +9 -0
- package/src/utils/manifest.js +145 -0
- package/src/utils/stack.js +80 -0
- package/src/utils/template.js +135 -0
- package/templates/AGENTS.md +109 -0
- package/templates/CLAUDE.md +3 -0
- package/templates/jenkins/Jenkinsfile-java.groovy +432 -0
- package/templates/jenkins/Jenkinsfile-node.groovy +450 -0
- package/templates/postman/.husky/pre-commit +19 -0
- package/templates/postman/.prettierrc.json +5 -0
- package/templates/postman/README.md.ejs +147 -0
- package/templates/postman/collections/01-core.json.ejs +91 -0
- package/templates/postman/config/local.json.ejs +12 -0
- package/templates/postman/config/staging.json.ejs +26 -0
- package/templates/postman/environments/local.postman_environment.json.ejs +31 -0
- package/templates/postman/environments/staging.postman_environment.json.ejs +31 -0
- package/templates/postman/gitignore +16 -0
- package/templates/postman/npmrc +31 -0
- package/templates/postman/package.json.ejs +66 -0
- package/templates/postman/run-all-shim.sh +16 -0
- package/templates/postman/scripts/auth/generate-jwt.sh +113 -0
- package/templates/postman/scripts/auth/get-issuer-secret.sh +140 -0
- package/templates/postman/scripts/infra/start-mocks.sh +138 -0
- package/templates/postman/scripts/infra/stop-mocks.sh +43 -0
- package/templates/postman/scripts/lib/api_coverage.py +1122 -0
- package/templates/postman/scripts/lib/cleanup-reports.sh +101 -0
- package/templates/postman/scripts/lib/cleanup-stryker.sh +44 -0
- package/templates/postman/scripts/lib/report_combined.py +527 -0
- package/templates/postman/scripts/lib/report_consolidated.py +363 -0
- package/templates/postman/scripts/lib/report_generator.py +121 -0
- package/templates/postman/scripts/lib/report_migration.py +156 -0
- package/templates/postman/scripts/lib/report_mutation.py +110 -0
- package/templates/postman/scripts/lib/report_unit.py +353 -0
- package/templates/postman/scripts/lib/report_utils.py +973 -0
- package/templates/postman/scripts/report-generators/generate-consolidated-report.sh +445 -0
- package/templates/postman/scripts/report-generators/java-api-coverage-matrix.sh +257 -0
- package/templates/postman/scripts/report-generators/mutation-report.sh +672 -0
- package/templates/postman/scripts/report-generators/node-api-coverage-matrix.sh +167 -0
- package/templates/postman/scripts/report-generators/stage-report-artifacts.sh +27 -0
- package/templates/postman/scripts/run-all.sh +452 -0
- package/templates/postman/scripts/runners/run-mutation-tests.sh +113 -0
- package/templates/postman/scripts/runners/run-tests-local.sh +936 -0
- package/templates/postman/scripts/runners/run-tests-staging.sh +741 -0
- package/templates/postman-node/README.md.ejs +26 -0
- package/templates/postman-node/collections/crud/01-bootstrap.json.ejs +34 -0
- package/templates/postman-node/config/local.json.ejs +46 -0
- package/templates/postman-node/config/staging.json.ejs +31 -0
- package/templates/postman-node/local.test.env.ejs +3 -0
- package/templates/postman-node/mocks/external.js +14 -0
- package/templates/postman-node/package.json.ejs +39 -0
- package/templates/postman-node/requirements.txt +1 -0
- package/templates/postman-node/scripts/database/cleanup-mysql.sh +12 -0
- package/templates/postman-node/scripts/database/run-migrations.js +29 -0
- package/templates/postman-node/scripts/database/start-mysql.sh +34 -0
- package/templates/postman-node/scripts/database/wait-for-mysql.sh +36 -0
- package/templates/postman-node/scripts/lib/api_coverage_node.py +1137 -0
- package/templates/postman-node/scripts/lib/fetch-jwt.sh +86 -0
- package/templates/postman-node/scripts/lib/run-newman.sh +104 -0
- package/templates/postman-node/scripts/lib/setup-database.sh +55 -0
- package/templates/postman-node/scripts/lib/start-app.sh +48 -0
- package/templates/postman-node/scripts/lib/utils.sh +114 -0
- package/templates/postman-node/scripts/report-generators/stage-report-artifacts.sh +26 -0
- package/templates/postman-node/scripts/run-all.sh +303 -0
- package/templates/postman-node/scripts/runners/run-tests.sh +123 -0
- package/templates/postman-node/scripts/setup-mocks.js.ejs +29 -0
- package/templates/postman-node/stryker.config.js.ejs +51 -0
- package/templates/rules/local-test-setup.mdc +420 -0
- package/templates/rules/testing-node.mdc +66 -0
- package/templates/rules/testing.mdc +248 -0
- package/templates/skills/_shared/postman-standards.md +380 -0
- package/templates/skills/enhance-test-pipeline/SKILL-java.md +483 -0
- package/templates/skills/enhance-test-pipeline/SKILL-node.md +431 -0
- package/templates/skills/enhance-test-pipeline/SKILL.md +9 -0
- package/templates/skills/review-test-suite/SKILL-java.md +137 -0
- package/templates/skills/review-test-suite/SKILL-node.md +78 -0
- package/templates/skills/review-test-suite/SKILL.md +9 -0
- package/templates/skills/run-test-suite/SKILL-java.md +186 -0
- package/templates/skills/run-test-suite/SKILL-node.md +191 -0
- package/templates/skills/run-test-suite/SKILL.md +9 -0
- package/templates/skills/setup-api-tests/SKILL-java.md +1094 -0
- package/templates/skills/setup-api-tests/SKILL-node.md +141 -0
- package/templates/skills/setup-api-tests/SKILL.md +9 -0
- package/templates/skills/setup-mutation-tests/SKILL-java.md +303 -0
- package/templates/skills/setup-mutation-tests/SKILL-node.md +408 -0
- package/templates/skills/setup-mutation-tests/SKILL.md +9 -0
- package/templates/skills/setup-test-pipeline/SKILL-java.md +454 -0
- package/templates/skills/setup-test-pipeline/SKILL-node.md +318 -0
- package/templates/skills/setup-test-pipeline/SKILL.md +9 -0
- package/templates/skills/write-api-tests/SKILL-java.md +115 -0
- package/templates/skills/write-api-tests/SKILL-node.md +83 -0
- package/templates/skills/write-api-tests/SKILL.md +9 -0
- 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?"
|