jest-test-lineage-reporter 2.0.2 → 2.1.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/README.md +252 -0
- package/bin/jest-lineage.js +20 -0
- package/package.json +14 -7
- package/src/__tests__/assertion-test.test.ts +59 -0
- package/src/__tests__/calculator.test.ts +30 -0
- package/src/__tests__/depth-example.test.ts +237 -0
- package/src/__tests__/gc-pressure-example.test.ts +169 -0
- package/src/__tests__/performance-example.test.ts +83 -0
- package/src/__tests__/quality-example.test.ts +122 -0
- package/src/__tests__/survived-mutations-example.test.ts +32 -0
- package/src/__tests__/truly-weak-example.test.ts +90 -0
- package/src/__tests__/weak-test-example.test.ts +222 -0
- package/src/calculator.ts +12 -0
- package/src/cli/commands/analyze.js +91 -0
- package/src/cli/commands/mutate.js +89 -0
- package/src/cli/commands/query.js +107 -0
- package/src/cli/commands/report.js +65 -0
- package/src/cli/commands/test.js +56 -0
- package/src/cli/index.js +89 -0
- package/src/cli/utils/config-loader.js +114 -0
- package/src/cli/utils/data-loader.js +118 -0
- package/src/cli/utils/jest-runner.js +105 -0
- package/src/cli/utils/output-formatter.js +126 -0
- package/src/depth-example.ts +66 -0
- package/src/gc-pressure-example.ts +158 -0
- package/src/global.d.ts +7 -0
- package/src/mcp/server.js +469 -0
- package/src/performance-example.ts +82 -0
- package/src/quality-example.ts +79 -0
- package/src/survived-mutations-example.ts +19 -0
- package/src/truly-weak-example.ts +37 -0
- package/src/weak-test-example.ts +91 -0
package/README.md
CHANGED
|
@@ -16,6 +16,258 @@ A comprehensive test analytics platform that provides line-by-line test coverage
|
|
|
16
16
|
- **Easy integration**: Simple Jest reporter that works alongside existing reporters
|
|
17
17
|
- **TypeScript support**: Built with TypeScript support out of the box
|
|
18
18
|
- **Statistics and insights**: File-level and overall statistics about test coverage patterns
|
|
19
|
+
- **🆕 CLI Tool**: Powerful command-line interface for standalone operations
|
|
20
|
+
|
|
21
|
+
## 🚀 CLI Usage (New!)
|
|
22
|
+
|
|
23
|
+
Jest Test Lineage Reporter now includes a powerful CLI tool!
|
|
24
|
+
|
|
25
|
+
### Quick Start with CLI
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Run tests with lineage tracking
|
|
29
|
+
jest-lineage test
|
|
30
|
+
|
|
31
|
+
# Run mutation testing on existing data
|
|
32
|
+
jest-lineage mutate --threshold 85
|
|
33
|
+
|
|
34
|
+
# Generate HTML report
|
|
35
|
+
jest-lineage report --open
|
|
36
|
+
|
|
37
|
+
# Query which tests cover a specific line
|
|
38
|
+
jest-lineage query src/calculator.ts 42
|
|
39
|
+
|
|
40
|
+
# Full analysis workflow (test + mutate + report)
|
|
41
|
+
jest-lineage analyze --open
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### CLI Commands
|
|
45
|
+
|
|
46
|
+
#### `jest-lineage test [jest-args...]`
|
|
47
|
+
Run Jest tests with lineage tracking enabled.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Basic usage
|
|
51
|
+
jest-lineage test
|
|
52
|
+
|
|
53
|
+
# Pass Jest arguments
|
|
54
|
+
jest-lineage test --watch --testPathPattern=calculator
|
|
55
|
+
|
|
56
|
+
# Disable specific features
|
|
57
|
+
jest-lineage test --no-performance --no-quality
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### `jest-lineage mutate`
|
|
61
|
+
Run mutation testing standalone (on existing lineage data).
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Basic mutation testing
|
|
65
|
+
jest-lineage mutate
|
|
66
|
+
|
|
67
|
+
# With custom threshold
|
|
68
|
+
jest-lineage mutate --threshold 90
|
|
69
|
+
|
|
70
|
+
# Debug mode (create mutation files without running tests)
|
|
71
|
+
jest-lineage mutate --debug --debug-dir ./mutations
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### `jest-lineage report`
|
|
75
|
+
Generate HTML report from existing lineage data.
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Generate and open report
|
|
79
|
+
jest-lineage report --open
|
|
80
|
+
|
|
81
|
+
# Custom output path
|
|
82
|
+
jest-lineage report --output coverage-report.html
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
#### `jest-lineage query <file> [line]`
|
|
86
|
+
Query which tests cover specific files or lines.
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Query entire file
|
|
90
|
+
jest-lineage query src/calculator.ts
|
|
91
|
+
|
|
92
|
+
# Query specific line
|
|
93
|
+
jest-lineage query src/calculator.ts 42
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### `jest-lineage analyze`
|
|
97
|
+
Full workflow: run tests, mutation testing, and generate report.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Complete analysis
|
|
101
|
+
jest-lineage analyze --open
|
|
102
|
+
|
|
103
|
+
# Skip mutation testing
|
|
104
|
+
jest-lineage analyze --skip-mutation --open
|
|
105
|
+
|
|
106
|
+
# Use existing test data
|
|
107
|
+
jest-lineage analyze --skip-tests --open
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### CLI Options
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
Global Options:
|
|
114
|
+
-v, --version Show version number
|
|
115
|
+
-h, --help Show help
|
|
116
|
+
|
|
117
|
+
Test Command:
|
|
118
|
+
--config <path> Path to Jest config file
|
|
119
|
+
--no-lineage Disable lineage tracking
|
|
120
|
+
--no-performance Disable performance tracking
|
|
121
|
+
--no-quality Disable quality analysis
|
|
122
|
+
--quiet, -q Suppress console output
|
|
123
|
+
|
|
124
|
+
Mutate Command:
|
|
125
|
+
--data <path> Path to lineage data file (default: .jest-lineage-data.json)
|
|
126
|
+
--threshold <number> Mutation score threshold (default: 80)
|
|
127
|
+
--timeout <ms> Timeout per mutation (default: 5000)
|
|
128
|
+
--debug Create debug mutation files
|
|
129
|
+
--debug-dir <path> Directory for debug files (default: ./mutations-debug)
|
|
130
|
+
--verbose Enable debug logging
|
|
131
|
+
|
|
132
|
+
Report Command:
|
|
133
|
+
--data <path> Path to lineage data file
|
|
134
|
+
--output <path> Output HTML file path (default: test-lineage-report.html)
|
|
135
|
+
--open Open report in browser
|
|
136
|
+
--format <type> Report format (default: html)
|
|
137
|
+
|
|
138
|
+
Query Command:
|
|
139
|
+
--data <path> Path to lineage data file
|
|
140
|
+
--json Output as JSON
|
|
141
|
+
--format <type> Output format: table, list, json (default: table)
|
|
142
|
+
|
|
143
|
+
Analyze Command:
|
|
144
|
+
--config <path> Path to Jest config file
|
|
145
|
+
--threshold <number> Mutation score threshold (default: 80)
|
|
146
|
+
--output <path> Output HTML file path
|
|
147
|
+
--open Open report in browser
|
|
148
|
+
--skip-tests Skip running tests (use existing data)
|
|
149
|
+
--skip-mutation Skip mutation testing
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Configuration Priority
|
|
153
|
+
|
|
154
|
+
The CLI respects configuration from multiple sources with this priority:
|
|
155
|
+
|
|
156
|
+
1. **CLI Arguments** (highest priority)
|
|
157
|
+
2. **Environment Variables** (`JEST_LINEAGE_*`)
|
|
158
|
+
3. **Config File** (jest.config.js)
|
|
159
|
+
4. **package.json** (`"jest-lineage"` field)
|
|
160
|
+
5. **Defaults** (lowest priority)
|
|
161
|
+
|
|
162
|
+
Example package.json configuration:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"jest-lineage": {
|
|
167
|
+
"mutationThreshold": 85,
|
|
168
|
+
"outputFile": "test-analytics.html",
|
|
169
|
+
"enableMutationTesting": true
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## 🤖 MCP Server (New!)
|
|
175
|
+
|
|
176
|
+
Jest Test Lineage Reporter now includes a Model Context Protocol (MCP) server for programmatic access via AI assistants like Claude.
|
|
177
|
+
|
|
178
|
+
### What is MCP?
|
|
179
|
+
|
|
180
|
+
The Model Context Protocol allows AI assistants to interact with your test infrastructure programmatically. With the MCP server, you can ask Claude to run tests, analyze mutation scores, generate reports, and query coverage data directly.
|
|
181
|
+
|
|
182
|
+
### Setting Up the MCP Server
|
|
183
|
+
|
|
184
|
+
Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"mcpServers": {
|
|
189
|
+
"jest-test-lineage-reporter": {
|
|
190
|
+
"command": "node",
|
|
191
|
+
"args": [
|
|
192
|
+
"/path/to/your/project/node_modules/jest-test-lineage-reporter/src/mcp/server.js"
|
|
193
|
+
]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Or if installed globally:
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"mcpServers": {
|
|
204
|
+
"jest-test-lineage-reporter": {
|
|
205
|
+
"command": "node",
|
|
206
|
+
"args": [
|
|
207
|
+
"$(npm root -g)/jest-test-lineage-reporter/src/mcp/server.js"
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Available MCP Tools
|
|
215
|
+
|
|
216
|
+
The MCP server exposes these tools:
|
|
217
|
+
|
|
218
|
+
#### `run_tests`
|
|
219
|
+
Run Jest tests with lineage tracking and generate coverage data.
|
|
220
|
+
|
|
221
|
+
**Parameters:**
|
|
222
|
+
- `args` (array): Jest command-line arguments
|
|
223
|
+
- `enableLineage` (boolean): Enable lineage tracking (default: true)
|
|
224
|
+
- `enablePerformance` (boolean): Enable performance tracking (default: true)
|
|
225
|
+
- `enableQuality` (boolean): Enable quality analysis (default: true)
|
|
226
|
+
|
|
227
|
+
#### `run_mutation_testing`
|
|
228
|
+
Run mutation testing on existing lineage data to assess test effectiveness.
|
|
229
|
+
|
|
230
|
+
**Parameters:**
|
|
231
|
+
- `dataPath` (string): Path to lineage data file (default: `.jest-lineage-data.json`)
|
|
232
|
+
- `threshold` (number): Minimum mutation score threshold 0-100 (default: 80)
|
|
233
|
+
- `timeout` (number): Timeout per mutation in milliseconds (default: 5000)
|
|
234
|
+
- `debug` (boolean): Create debug mutation files instead of running tests (default: false)
|
|
235
|
+
|
|
236
|
+
#### `generate_report`
|
|
237
|
+
Generate HTML report from existing lineage data.
|
|
238
|
+
|
|
239
|
+
**Parameters:**
|
|
240
|
+
- `dataPath` (string): Path to lineage data file (default: `.jest-lineage-data.json`)
|
|
241
|
+
- `outputPath` (string): Output HTML file path (default: `test-lineage-report.html`)
|
|
242
|
+
|
|
243
|
+
#### `query_coverage`
|
|
244
|
+
Query which tests cover specific files or lines.
|
|
245
|
+
|
|
246
|
+
**Parameters:**
|
|
247
|
+
- `file` (string, required): File path to query (e.g., "src/calculator.ts")
|
|
248
|
+
- `line` (number, optional): Line number to query
|
|
249
|
+
- `dataPath` (string): Path to lineage data file (default: `.jest-lineage-data.json`)
|
|
250
|
+
|
|
251
|
+
#### `analyze_full`
|
|
252
|
+
Run full workflow: tests, mutation testing, and generate report.
|
|
253
|
+
|
|
254
|
+
**Parameters:**
|
|
255
|
+
- `skipTests` (boolean): Skip running tests (use existing data) (default: false)
|
|
256
|
+
- `skipMutation` (boolean): Skip mutation testing (default: false)
|
|
257
|
+
- `threshold` (number): Mutation score threshold (default: 80)
|
|
258
|
+
- `outputPath` (string): Output HTML file path (default: `test-lineage-report.html`)
|
|
259
|
+
|
|
260
|
+
### Example MCP Usage with Claude
|
|
261
|
+
|
|
262
|
+
Once configured, you can ask Claude:
|
|
263
|
+
|
|
264
|
+
- "Run the tests with lineage tracking"
|
|
265
|
+
- "Run mutation testing with an 85% threshold"
|
|
266
|
+
- "Generate an HTML report from the latest test data"
|
|
267
|
+
- "Which tests cover line 42 of src/calculator.ts?"
|
|
268
|
+
- "Run a full analysis and generate the report"
|
|
269
|
+
|
|
270
|
+
Claude will use the MCP server to execute these operations in your project.
|
|
19
271
|
|
|
20
272
|
## 📦 Installation
|
|
21
273
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Jest Test Lineage Reporter CLI
|
|
5
|
+
* Main entry point for command-line interface
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const cli = require('../src/cli');
|
|
9
|
+
|
|
10
|
+
// Run CLI with error handling
|
|
11
|
+
cli.run(process.argv).catch((error) => {
|
|
12
|
+
console.error('\n❌ Error:', error.message);
|
|
13
|
+
|
|
14
|
+
if (process.env.JEST_LINEAGE_DEBUG === 'true') {
|
|
15
|
+
console.error('\nStack trace:');
|
|
16
|
+
console.error(error.stack);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jest-test-lineage-reporter",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"main": "src/TestCoverageReporter.js",
|
|
5
|
+
"bin": {
|
|
6
|
+
"jest-lineage": "./bin/jest-lineage.js"
|
|
7
|
+
},
|
|
5
8
|
"scripts": {
|
|
6
9
|
"test": "jest",
|
|
7
10
|
"test:watch": "jest --watch",
|
|
@@ -47,16 +50,20 @@
|
|
|
47
50
|
"npm": ">=6.0.0"
|
|
48
51
|
},
|
|
49
52
|
"files": [
|
|
50
|
-
"
|
|
51
|
-
"src/
|
|
52
|
-
"src/testSetup.js",
|
|
53
|
-
"src/babel-plugin-lineage-tracker.js",
|
|
54
|
-
"src/babel-plugin-mutation-tester.js",
|
|
55
|
-
"src/config.js",
|
|
53
|
+
"bin/",
|
|
54
|
+
"src/",
|
|
56
55
|
"babel.config.js",
|
|
57
56
|
"README.md",
|
|
58
57
|
"LICENSE"
|
|
59
58
|
],
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@modelcontextprotocol/sdk": "^0.5.0",
|
|
61
|
+
"chalk": "^4.1.2",
|
|
62
|
+
"cli-table3": "^0.6.3",
|
|
63
|
+
"commander": "^11.0.0",
|
|
64
|
+
"open": "^8.4.0",
|
|
65
|
+
"ora": "^5.4.1"
|
|
66
|
+
},
|
|
60
67
|
"devDependencies": {
|
|
61
68
|
"@babel/core": "^7.23.0",
|
|
62
69
|
"@babel/plugin-transform-modules-commonjs": "^7.27.1",
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { directFunction } from '../depth-example';
|
|
2
|
+
|
|
3
|
+
describe('Assertion Counting Test', () => {
|
|
4
|
+
test('should count multiple expect statements correctly', () => {
|
|
5
|
+
// This test has many expect statements to test assertion counting
|
|
6
|
+
|
|
7
|
+
const result1 = directFunction(5);
|
|
8
|
+
expect(result1).toBe(10);
|
|
9
|
+
expect(result1).toBeGreaterThan(5);
|
|
10
|
+
expect(result1).toBeLessThan(20);
|
|
11
|
+
|
|
12
|
+
const result2 = directFunction(0);
|
|
13
|
+
expect(result2).toBe(0);
|
|
14
|
+
expect(result2).toEqual(0);
|
|
15
|
+
expect(result2).not.toBe(1);
|
|
16
|
+
|
|
17
|
+
const result3 = directFunction(-5);
|
|
18
|
+
expect(result3).toBe(-10);
|
|
19
|
+
expect(result3).toBeLessThan(0);
|
|
20
|
+
expect(result3).toBeGreaterThan(-20);
|
|
21
|
+
|
|
22
|
+
// Test arrays and objects
|
|
23
|
+
const results = [result1, result2, result3];
|
|
24
|
+
expect(results).toHaveLength(3);
|
|
25
|
+
expect(results).toContain(10);
|
|
26
|
+
expect(results).toContain(0);
|
|
27
|
+
expect(results).toContain(-10);
|
|
28
|
+
|
|
29
|
+
// Test properties
|
|
30
|
+
const obj = { value: result1 };
|
|
31
|
+
expect(obj).toHaveProperty('value');
|
|
32
|
+
expect(obj).toHaveProperty('value', 10);
|
|
33
|
+
|
|
34
|
+
// Test null/undefined
|
|
35
|
+
expect(result1).toBeDefined();
|
|
36
|
+
expect(result1).not.toBeNull();
|
|
37
|
+
expect(result1).not.toBeUndefined();
|
|
38
|
+
|
|
39
|
+
// Test truthiness
|
|
40
|
+
expect(result1).toBeTruthy();
|
|
41
|
+
expect(result2).toBeFalsy();
|
|
42
|
+
|
|
43
|
+
// Test error handling
|
|
44
|
+
expect(() => {
|
|
45
|
+
if (result1 < 0) {
|
|
46
|
+
throw new Error('Should not be negative');
|
|
47
|
+
}
|
|
48
|
+
}).not.toThrow();
|
|
49
|
+
|
|
50
|
+
// This test should show:
|
|
51
|
+
// - 22+ expect statements (high assertion count)
|
|
52
|
+
// - Error handling with expect().not.toThrow()
|
|
53
|
+
// - Property testing with toHaveProperty()
|
|
54
|
+
// - Array testing with toContain() and toHaveLength()
|
|
55
|
+
// - Boundary testing with toBeGreaterThan/toBeLessThan
|
|
56
|
+
// - Null/undefined testing
|
|
57
|
+
// - Truthiness testing
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { add, subtract, multiply } from '../calculator';
|
|
2
|
+
|
|
3
|
+
describe('Calculator', () => {
|
|
4
|
+
it('should correctly add two numbers', () => {
|
|
5
|
+
expect(add(1, 2)).toBe(3);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('should subtract a smaller number from a larger one', () => {
|
|
9
|
+
expect(subtract(5, 2)).toBe(3); // This will hit line 9
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('should subtract a larger number from a smaller one and return a positive result', () => {
|
|
13
|
+
expect(subtract(2, 5)).toBe(3); // This will hit line 7
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// This test covers the same line as the first subtraction test, which our report will show.
|
|
17
|
+
it('should handle zero correctly in subtraction', () => {
|
|
18
|
+
expect(subtract(10, 0)).toBe(10); // This will also hit line 9
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// This test ONLY calls multiply, so it will show different coverage
|
|
22
|
+
it('should multiply two numbers correctly', () => {
|
|
23
|
+
expect(multiply(3, 4)).toBe(12); // This will ONLY hit line 13 (multiply function)
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// This test ONLY calls add, so it will show different coverage
|
|
27
|
+
it('should add negative numbers', () => {
|
|
28
|
+
expect(add(-5, -3)).toBe(-8); // This will ONLY hit lines 2-3 (add function)
|
|
29
|
+
});
|
|
30
|
+
});
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import {
|
|
2
|
+
directFunction,
|
|
3
|
+
oneLevel,
|
|
4
|
+
twoLevels,
|
|
5
|
+
threeLevels,
|
|
6
|
+
complexFunction,
|
|
7
|
+
recursiveFunction,
|
|
8
|
+
memoryLeakFunction,
|
|
9
|
+
clearMemoryLeaks,
|
|
10
|
+
getMemoryLeakCount
|
|
11
|
+
} from '../depth-example';
|
|
12
|
+
|
|
13
|
+
describe('Call Depth Tracking Examples', () => {
|
|
14
|
+
test('should call directFunction directly (depth 1)', () => {
|
|
15
|
+
const result = directFunction(5);
|
|
16
|
+
expect(result).toBe(10);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('should call directFunction through oneLevel (depth 2)', () => {
|
|
20
|
+
const result = oneLevel(5);
|
|
21
|
+
expect(result).toBe(11);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('should call directFunction through twoLevels (depth 3)', () => {
|
|
25
|
+
const result = twoLevels(5);
|
|
26
|
+
expect(result).toBe(12);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('should call directFunction through threeLevels (depth 4)', () => {
|
|
30
|
+
const result = threeLevels(5);
|
|
31
|
+
expect(result).toBe(13);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should call directFunction at multiple depths in complexFunction', () => {
|
|
35
|
+
const result = complexFunction(5);
|
|
36
|
+
expect(result).toBe(33); // 10 + 11 + 12 = 33
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('should call directFunction through recursive calls (very deep)', () => {
|
|
40
|
+
const result = recursiveFunction(5);
|
|
41
|
+
expect(result).toBe(13); // 10 + 1 + 1 + 1 = 13
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('should demonstrate memory leak detection with large allocations', () => {
|
|
45
|
+
// This test intentionally creates memory leaks to demonstrate tracking
|
|
46
|
+
const largeArrays = [];
|
|
47
|
+
|
|
48
|
+
// Create multiple large arrays (each >1MB) to trigger memory leak detection
|
|
49
|
+
for (let i = 0; i < 3; i++) {
|
|
50
|
+
// Allocate ~2MB array (will trigger 🚨LEAK alert)
|
|
51
|
+
const largeArray = new Array(500000).fill(0).map((_, index) => ({
|
|
52
|
+
id: index,
|
|
53
|
+
data: `Large data string for item ${index} with extra padding to increase memory usage`,
|
|
54
|
+
timestamp: Date.now(),
|
|
55
|
+
metadata: {
|
|
56
|
+
created: new Date(),
|
|
57
|
+
processed: false,
|
|
58
|
+
tags: ['memory', 'test', 'large', 'allocation']
|
|
59
|
+
}
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
largeArrays.push(largeArray);
|
|
63
|
+
|
|
64
|
+
// Call our function to track memory usage at different call depths
|
|
65
|
+
const result = directFunction(i);
|
|
66
|
+
expect(result).toBe(i * 2);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Verify we created the expected number of arrays
|
|
70
|
+
expect(largeArrays).toHaveLength(3);
|
|
71
|
+
expect(largeArrays[0]).toHaveLength(500000);
|
|
72
|
+
|
|
73
|
+
// Test edge cases with memory allocation
|
|
74
|
+
expect(largeArrays[0][0]).toHaveProperty('id', 0);
|
|
75
|
+
expect(largeArrays[0][0]).toHaveProperty('data');
|
|
76
|
+
expect(largeArrays[0][0].metadata).toHaveProperty('tags');
|
|
77
|
+
expect(largeArrays[0][0].metadata.tags).toContain('memory');
|
|
78
|
+
|
|
79
|
+
// Test error conditions
|
|
80
|
+
expect(() => {
|
|
81
|
+
if (largeArrays.length === 0) {
|
|
82
|
+
throw new Error('No arrays created');
|
|
83
|
+
}
|
|
84
|
+
}).not.toThrow();
|
|
85
|
+
|
|
86
|
+
// Test boundary conditions
|
|
87
|
+
expect(largeArrays[2][499999]).toHaveProperty('id', 499999);
|
|
88
|
+
|
|
89
|
+
// This should show high memory usage, multiple assertions, and good error handling
|
|
90
|
+
// Expected quality metrics:
|
|
91
|
+
// - High assertion count (8+ expect statements)
|
|
92
|
+
// - Error handling (try/catch equivalent with expect().not.toThrow())
|
|
93
|
+
// - Edge case testing (boundary values, null checks)
|
|
94
|
+
// - Memory leak detection (large allocations)
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('should demonstrate GC pressure with many small allocations', () => {
|
|
98
|
+
const smallObjects = [];
|
|
99
|
+
|
|
100
|
+
// Create many small objects to trigger GC pressure detection
|
|
101
|
+
for (let i = 0; i < 1000; i++) {
|
|
102
|
+
// Small allocations (<1KB each) to trigger 🗑️GC alert
|
|
103
|
+
const smallObj = {
|
|
104
|
+
id: i,
|
|
105
|
+
value: Math.random(),
|
|
106
|
+
processed: false
|
|
107
|
+
};
|
|
108
|
+
smallObjects.push(smallObj);
|
|
109
|
+
|
|
110
|
+
// Call function at different depths to test performance impact
|
|
111
|
+
if (i % 100 === 0) {
|
|
112
|
+
const result = oneLevel(i);
|
|
113
|
+
expect(result).toBeGreaterThan(i);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
expect(smallObjects).toHaveLength(1000);
|
|
118
|
+
expect(smallObjects[999]).toHaveProperty('id', 999);
|
|
119
|
+
|
|
120
|
+
// This should show GC pressure but smaller memory footprint
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('should demonstrate slow execution patterns', () => {
|
|
124
|
+
const results = [];
|
|
125
|
+
|
|
126
|
+
// Create intentionally variable performance to trigger slow execution detection
|
|
127
|
+
for (let i = 0; i < 5; i++) {
|
|
128
|
+
const startTime = Date.now();
|
|
129
|
+
|
|
130
|
+
// Sometimes do heavy work, sometimes light work (creates performance variance)
|
|
131
|
+
if (i % 2 === 0) {
|
|
132
|
+
// Heavy work - should be slower
|
|
133
|
+
let heavyResult = 0;
|
|
134
|
+
for (let j = 0; j < 10000; j++) {
|
|
135
|
+
heavyResult += Math.sin(j) * Math.cos(j);
|
|
136
|
+
}
|
|
137
|
+
results.push(heavyResult);
|
|
138
|
+
} else {
|
|
139
|
+
// Light work - should be faster
|
|
140
|
+
results.push(i * 2);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const result = directFunction(i);
|
|
144
|
+
expect(result).toBe(i * 2);
|
|
145
|
+
|
|
146
|
+
const endTime = Date.now();
|
|
147
|
+
expect(endTime).toBeGreaterThanOrEqual(startTime);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
expect(results).toHaveLength(5);
|
|
151
|
+
|
|
152
|
+
// This should show performance variance and trigger 🐌SLOW alert
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test('should create actual memory leaks with large objects', () => {
|
|
156
|
+
// Clear any existing leaks first
|
|
157
|
+
const initialCount = getMemoryLeakCount();
|
|
158
|
+
expect(initialCount).toBeGreaterThanOrEqual(0);
|
|
159
|
+
|
|
160
|
+
// Create multiple memory leaks with large objects
|
|
161
|
+
for (let i = 0; i < 3; i++) {
|
|
162
|
+
// Each call creates ~1MB of leaked memory (1000 items * 1KB each)
|
|
163
|
+
const result = memoryLeakFunction(1000);
|
|
164
|
+
expect(result).toBe(1000 * 2); // directFunction returns x * 2
|
|
165
|
+
|
|
166
|
+
// Verify memory leak count is increasing
|
|
167
|
+
const currentCount = getMemoryLeakCount();
|
|
168
|
+
expect(currentCount).toBe(initialCount + i + 1);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Verify we have created 3 memory leaks
|
|
172
|
+
const finalCount = getMemoryLeakCount();
|
|
173
|
+
expect(finalCount).toBe(initialCount + 3);
|
|
174
|
+
|
|
175
|
+
// This test should show:
|
|
176
|
+
// - High memory usage (3MB+ leaked)
|
|
177
|
+
// - 🚨LEAK alerts in console
|
|
178
|
+
// - Multiple expect() statements (good assertion count)
|
|
179
|
+
// - Error handling with expect().toBe() validations
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('should create massive memory leak for testing', () => {
|
|
183
|
+
// Create a very large memory leak to ensure detection
|
|
184
|
+
const initialMemoryCount = getMemoryLeakCount();
|
|
185
|
+
|
|
186
|
+
// Create 5 large objects (each ~2MB)
|
|
187
|
+
for (let i = 0; i < 5; i++) {
|
|
188
|
+
const result = memoryLeakFunction(2000); // 2000 items * ~1KB each = ~2MB
|
|
189
|
+
expect(result).toBe(2000 * 2);
|
|
190
|
+
|
|
191
|
+
// Verify the leak is growing
|
|
192
|
+
expect(getMemoryLeakCount()).toBeGreaterThan(initialMemoryCount + i);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Verify total memory leaks
|
|
196
|
+
const totalLeaks = getMemoryLeakCount();
|
|
197
|
+
expect(totalLeaks).toBeGreaterThanOrEqual(initialMemoryCount + 5);
|
|
198
|
+
|
|
199
|
+
// Test edge cases
|
|
200
|
+
expect(() => memoryLeakFunction(0)).not.toThrow();
|
|
201
|
+
expect(memoryLeakFunction(0)).toBe(0);
|
|
202
|
+
|
|
203
|
+
// Test error conditions
|
|
204
|
+
expect(() => {
|
|
205
|
+
if (totalLeaks < 0) {
|
|
206
|
+
throw new Error('Invalid leak count');
|
|
207
|
+
}
|
|
208
|
+
}).not.toThrow();
|
|
209
|
+
|
|
210
|
+
// This should create ~10MB of leaked memory and trigger multiple 🚨LEAK alerts
|
|
211
|
+
// Quality metrics should show:
|
|
212
|
+
// - High assertion count (8+ expect statements)
|
|
213
|
+
// - Good error handling (expect().not.toThrow())
|
|
214
|
+
// - Edge case testing (zero values, negative checks)
|
|
215
|
+
// - Boundary testing (memory thresholds)
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test('should demonstrate memory cleanup', () => {
|
|
219
|
+
// Create some leaks first
|
|
220
|
+
const result1 = memoryLeakFunction(500);
|
|
221
|
+
const result2 = memoryLeakFunction(500);
|
|
222
|
+
|
|
223
|
+
expect(result1).toBe(1000);
|
|
224
|
+
expect(result2).toBe(1000);
|
|
225
|
+
expect(getMemoryLeakCount()).toBeGreaterThanOrEqual(2);
|
|
226
|
+
|
|
227
|
+
// Clear all memory leaks
|
|
228
|
+
const clearedCount = clearMemoryLeaks();
|
|
229
|
+
expect(clearedCount).toBeGreaterThanOrEqual(2);
|
|
230
|
+
expect(getMemoryLeakCount()).toBe(0);
|
|
231
|
+
|
|
232
|
+
// Verify cleanup worked
|
|
233
|
+
expect(getMemoryLeakCount()).toBe(0);
|
|
234
|
+
|
|
235
|
+
// This test shows proper cleanup and should have fewer memory issues
|
|
236
|
+
});
|
|
237
|
+
});
|