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 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.2",
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
- "src/TestCoverageReporter.js",
51
- "src/MutationTester.js",
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
+ });