jest-test-lineage-reporter 2.0.2 → 2.1.1

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.
@@ -0,0 +1,169 @@
1
+ import {
2
+ badGCPressureFunction,
3
+ goodGCPressureFunction,
4
+ badStringConcatenation,
5
+ goodStringConcatenation,
6
+ badArrayOperations,
7
+ goodArrayOperations,
8
+ objectPoolExample
9
+ } from '../gc-pressure-example';
10
+
11
+ describe.skip('GC Pressure Examples', () => {
12
+ test.skip('should demonstrate BAD GC pressure with many small objects', () => {
13
+ // This test creates many small objects and should trigger 🗑️GC alerts
14
+
15
+ const result1 = badGCPressureFunction(1000); // Creates 2000+ small objects
16
+ expect(result1).toBeGreaterThan(0);
17
+ expect(typeof result1).toBe('number');
18
+
19
+ const result2 = badGCPressureFunction(500); // Creates 1000+ small objects
20
+ expect(result2).toBeGreaterThan(0);
21
+ expect(result2).toBeLessThan(result1);
22
+
23
+ // Test edge cases
24
+ expect(badGCPressureFunction(0)).toBe(0);
25
+ expect(badGCPressureFunction(1)).toBeGreaterThan(0);
26
+
27
+ // This should show:
28
+ // - 🗑️GC alerts due to many small object allocations
29
+ // - High memory churn but relatively small total memory
30
+ // - Multiple expect statements for good test quality
31
+ });
32
+
33
+ test('should demonstrate GOOD GC behavior with object reuse', () => {
34
+ // This test reuses objects and should have minimal GC pressure
35
+
36
+ const result1 = goodGCPressureFunction(1000); // Reuses same objects
37
+ expect(result1).toBeGreaterThan(0);
38
+ expect(typeof result1).toBe('number');
39
+
40
+ const result2 = goodGCPressureFunction(500);
41
+ expect(result2).toBeGreaterThan(0);
42
+ expect(result2).toBeLessThan(result1);
43
+
44
+ // Test edge cases
45
+ expect(goodGCPressureFunction(0)).toBe(0);
46
+ expect(goodGCPressureFunction(1)).toBeGreaterThan(0);
47
+
48
+ // This should show:
49
+ // - Minimal or no 🗑️GC alerts
50
+ // - Lower memory usage than the bad example
51
+ // - Better performance consistency
52
+ });
53
+
54
+ test('should demonstrate BAD string concatenation GC pressure', () => {
55
+ // String concatenation in loops creates many temporary strings
56
+
57
+ const items = Array.from({ length: 1000 }, (_, i) => `item${i}`);
58
+
59
+ const result = badStringConcatenation(items);
60
+ expect(result).toContain('item0');
61
+ expect(result).toContain('item999');
62
+ expect(result.split(', ')).toHaveLength(1001); // 1000 items + empty string at end
63
+
64
+ // Test with smaller arrays
65
+ const smallItems = ['a', 'b', 'c'];
66
+ const smallResult = badStringConcatenation(smallItems);
67
+ expect(smallResult).toBe('a, b, c, ');
68
+
69
+ // This should trigger 🗑️GC due to many temporary string objects
70
+ });
71
+
72
+ test('should demonstrate GOOD string concatenation', () => {
73
+ // Array.join() creates only one final string
74
+
75
+ const items = Array.from({ length: 1000 }, (_, i) => `item${i}`);
76
+
77
+ const result = goodStringConcatenation(items);
78
+ expect(result).toContain('item0');
79
+ expect(result).toContain('item999');
80
+ expect(result.split(', ')).toHaveLength(1000);
81
+
82
+ // Test with smaller arrays
83
+ const smallItems = ['a', 'b', 'c'];
84
+ const smallResult = goodStringConcatenation(smallItems);
85
+ expect(smallResult).toBe('a, b, c');
86
+
87
+ // This should have minimal GC pressure
88
+ });
89
+
90
+ test('should demonstrate BAD array operations with multiple allocations', () => {
91
+ // Chained array operations create many intermediate arrays
92
+
93
+ const numbers = Array.from({ length: 1000 }, (_, i) => i);
94
+
95
+ const result = badArrayOperations(numbers);
96
+ expect(Array.isArray(result)).toBe(true);
97
+ expect(result.length).toBeGreaterThan(0);
98
+ expect(result.every(x => x % 2 === 0)).toBe(true);
99
+ expect(result.every(x => x > 10)).toBe(true);
100
+
101
+ // Test edge cases
102
+ expect(badArrayOperations([])).toEqual([]);
103
+ expect(badArrayOperations([1, 2, 3])).toEqual([]);
104
+ expect(badArrayOperations([10, 20, 30])).toEqual([22, 42, 62]);
105
+
106
+ // This should trigger 🗑️GC due to multiple intermediate arrays
107
+ });
108
+
109
+ test('should demonstrate GOOD array operations with single allocation', () => {
110
+ // Single reduce operation creates only one final array
111
+
112
+ const numbers = Array.from({ length: 1000 }, (_, i) => i);
113
+
114
+ const result = goodArrayOperations(numbers);
115
+ expect(Array.isArray(result)).toBe(true);
116
+ expect(result.length).toBeGreaterThan(0);
117
+ expect(result.every(x => x % 2 === 0)).toBe(true);
118
+ expect(result.every(x => x > 10)).toBe(true);
119
+
120
+ // Test edge cases
121
+ expect(goodArrayOperations([])).toEqual([]);
122
+ expect(goodArrayOperations([1, 2, 3])).toEqual([]);
123
+ expect(goodArrayOperations([10, 20, 30])).toEqual([22, 42, 62]);
124
+
125
+ // This should have minimal GC pressure
126
+ });
127
+
128
+ test('should demonstrate object pooling for optimal GC behavior', () => {
129
+ // Object pooling reuses pre-allocated objects
130
+
131
+ const result1 = objectPoolExample(1000);
132
+ expect(result1).toBeGreaterThan(0);
133
+ expect(typeof result1).toBe('number');
134
+
135
+ const result2 = objectPoolExample(500);
136
+ expect(result2).toBeGreaterThan(0);
137
+ expect(result2).toBeLessThan(result1);
138
+
139
+ // Test edge cases
140
+ expect(objectPoolExample(0)).toBe(0);
141
+ expect(objectPoolExample(1)).toBeGreaterThan(0);
142
+
143
+ // This should have the best GC behavior - minimal allocations
144
+ });
145
+
146
+ test('should compare all GC pressure patterns', () => {
147
+ // Compare all patterns to show the difference
148
+
149
+ const testSize = 100;
150
+
151
+ const badResult = badGCPressureFunction(testSize);
152
+ const goodResult = goodGCPressureFunction(testSize);
153
+ const poolResult = objectPoolExample(testSize);
154
+
155
+ // All should produce similar numerical results
156
+ expect(badResult).toBeGreaterThan(0);
157
+ expect(goodResult).toBeGreaterThan(0);
158
+ expect(poolResult).toBeGreaterThan(0);
159
+
160
+ // But GC behavior should be very different:
161
+ // - badResult: High 🗑️GC pressure
162
+ // - goodResult: Medium 🗑️GC pressure
163
+ // - poolResult: Minimal 🗑️GC pressure
164
+
165
+ expect(typeof badResult).toBe('number');
166
+ expect(typeof goodResult).toBe('number');
167
+ expect(typeof poolResult).toBe('number');
168
+ });
169
+ });
@@ -0,0 +1,83 @@
1
+ import {
2
+ lightweightFunction,
3
+ mediumFunction,
4
+ heavyFunction,
5
+ memoryIntensiveFunction,
6
+ recursiveFunction,
7
+ nestedCallsFunction,
8
+ mixedPerformanceFunction,
9
+ performanceVariableFunction
10
+ } from '../performance-example';
11
+
12
+ describe.skip('Performance Tracking Examples', () => {
13
+ test('should track lightweight function performance', () => {
14
+ // This should show minimal CPU cycles
15
+ const result = lightweightFunction(5);
16
+ expect(result).toBe(6);
17
+ });
18
+
19
+ test('should track medium function performance', () => {
20
+ // This should show moderate CPU cycles
21
+ const result = mediumFunction(4);
22
+ expect(result).toBeGreaterThan(0);
23
+ });
24
+
25
+ test('should track heavy function performance', () => {
26
+ // This should show high CPU cycles
27
+ const result = heavyFunction(2);
28
+ expect(result).toBeGreaterThan(0);
29
+ });
30
+
31
+ test('should track memory intensive function', () => {
32
+ // This should show memory allocation patterns
33
+ const result = memoryIntensiveFunction(1000);
34
+ expect(result).toHaveLength(1000);
35
+ });
36
+
37
+ test('should track recursive function with exponential complexity', () => {
38
+ // This should show very high CPU cycles due to recursion
39
+ const result = recursiveFunction(5);
40
+ expect(result).toBeGreaterThan(0);
41
+ });
42
+
43
+ test('should track nested calls with different depths', () => {
44
+ // This should show performance at different call depths
45
+ const result = nestedCallsFunction(10);
46
+ expect(result).toBeGreaterThan(0);
47
+ });
48
+
49
+ test('should track mixed performance patterns', () => {
50
+ // This should show variable performance within one test
51
+ const result = mixedPerformanceFunction(10);
52
+ expect(result).toBeGreaterThan(0);
53
+ });
54
+
55
+ test('should track fast mode performance', () => {
56
+ // Fast execution path
57
+ const result = performanceVariableFunction('fast');
58
+ expect(result).toBe(43);
59
+ });
60
+
61
+ test('should track medium mode performance', () => {
62
+ // Medium execution path
63
+ const result = performanceVariableFunction('medium');
64
+ expect(result).toBeGreaterThan(0);
65
+ });
66
+
67
+ test('should track slow mode performance', () => {
68
+ // Slow execution path
69
+ const result = performanceVariableFunction('slow');
70
+ expect(result).toBeGreaterThan(0);
71
+ });
72
+
73
+ test('should demonstrate performance hotspot', () => {
74
+ // Call heavy function multiple times to create hotspot
75
+ let total = 0;
76
+ let i = 0;
77
+ while (i < 3) {
78
+ total += heavyFunction(i);
79
+ i++;
80
+ }
81
+ expect(total).toBeGreaterThan(0);
82
+ });
83
+ });
@@ -0,0 +1,122 @@
1
+ import {
2
+ simpleFunction,
3
+ complexFunction,
4
+ asyncFunction,
5
+ errorProneFunction,
6
+ wellTestedFunction,
7
+ Calculator
8
+ } from '../quality-example';
9
+
10
+ describe('Test Quality Examples', () => {
11
+ // High quality test - good assertions, error handling, edge cases
12
+ test('wellTestedFunction should handle all edge cases properly', async () => {
13
+ // Test normal cases
14
+ expect(wellTestedFunction(5, 3)).toBe(8);
15
+ expect(wellTestedFunction(0, 0)).toBe(0);
16
+ expect(wellTestedFunction(1.5, 2.5)).toBe(4);
17
+
18
+ // Test error cases
19
+ expect(() => wellTestedFunction(null as any, 5)).toThrow('Parameter a is required');
20
+ expect(() => wellTestedFunction(5, undefined as any)).toThrow('Parameter b is required');
21
+ expect(() => wellTestedFunction('5' as any, 3)).toThrow('Both parameters must be numbers');
22
+ expect(() => wellTestedFunction(-1, 5)).toThrow('Parameters must be non-negative');
23
+ expect(() => wellTestedFunction(5, -1)).toThrow('Parameters must be non-negative');
24
+
25
+ // Test boundary cases
26
+ expect(wellTestedFunction(Number.MAX_SAFE_INTEGER, 0)).toBe(Number.MAX_SAFE_INTEGER);
27
+ expect(wellTestedFunction(0.1, 0.2)).toBeCloseTo(0.3);
28
+ });
29
+
30
+ // Medium quality test - some assertions, basic testing
31
+ test('complexFunction should handle different data types', () => {
32
+ expect(complexFunction('hello')).toBe('HELLO');
33
+ expect(complexFunction(5)).toBe(25);
34
+ expect(complexFunction(-3)).toBe(3);
35
+ expect(complexFunction(0)).toBe(1);
36
+ expect(complexFunction([1, 2, 3])).toEqual([2, 4, 6]);
37
+ expect(complexFunction({ key: 'value' })).toBe('{"key":"value"}');
38
+
39
+ // Test error cases
40
+ expect(() => complexFunction(null)).toThrow('Data is required');
41
+ expect(() => complexFunction(undefined)).toThrow('Data is required');
42
+ });
43
+
44
+ // Low quality test - minimal assertions, no error handling
45
+ test('simpleFunction basic test', () => {
46
+ expect(simpleFunction(5)).toBe(10);
47
+ });
48
+
49
+ // Async test with proper error handling
50
+ test('asyncFunction should handle async operations correctly', async () => {
51
+ const result = await asyncFunction(10);
52
+ expect(result).toBe('Completed after 10ms');
53
+
54
+ // Test error case
55
+ await expect(asyncFunction(-1)).rejects.toThrow('Delay cannot be negative');
56
+ });
57
+
58
+ // Poor quality test - no error handling for error-prone function
59
+ test('errorProneFunction test', () => {
60
+ expect(errorProneFunction('hello')).toBe('HELLO');
61
+ expect(errorProneFunction(123)).toBe('123');
62
+ // Missing: null/undefined tests that would reveal bugs
63
+ });
64
+
65
+ // Test with mocking (affects isolation score)
66
+ test('Calculator with mocking', () => {
67
+ const calculator = new Calculator();
68
+ const spy = jest.spyOn(calculator, 'add');
69
+
70
+ calculator.add(2, 3);
71
+ expect(spy).toHaveBeenCalledWith(2, 3);
72
+ expect(calculator.getHistory()).toEqual([5]);
73
+
74
+ spy.mockRestore();
75
+ });
76
+
77
+ // Long test (test smell)
78
+ test('long test with many assertions', () => {
79
+ const calc = new Calculator();
80
+
81
+ // Too many assertions in one test
82
+ expect(calc.add(1, 1)).toBe(2);
83
+ expect(calc.add(2, 2)).toBe(4);
84
+ expect(calc.add(3, 3)).toBe(6);
85
+ expect(calc.add(4, 4)).toBe(8);
86
+ expect(calc.add(5, 5)).toBe(10);
87
+ expect(calc.add(6, 6)).toBe(12);
88
+ expect(calc.add(7, 7)).toBe(14);
89
+ expect(calc.add(8, 8)).toBe(16);
90
+ expect(calc.add(9, 9)).toBe(18);
91
+ expect(calc.add(10, 10)).toBe(20);
92
+ expect(calc.add(11, 11)).toBe(22);
93
+ expect(calc.add(12, 12)).toBe(24);
94
+
95
+ expect(calc.getHistory()).toHaveLength(12);
96
+ calc.clearHistory();
97
+ expect(calc.getHistory()).toHaveLength(0);
98
+ });
99
+
100
+ // Test with complex control flow (high complexity)
101
+ test('complex control flow test', () => {
102
+ let result = 0;
103
+
104
+ for (let i = 0; i < 10; i++) {
105
+ if (i % 2 === 0) {
106
+ if (i % 4 === 0) {
107
+ result += complexFunction(i);
108
+ } else {
109
+ result += simpleFunction(i);
110
+ }
111
+ } else {
112
+ if (i > 5) {
113
+ result -= i;
114
+ } else {
115
+ result += i;
116
+ }
117
+ }
118
+ }
119
+
120
+ expect(result).toBeGreaterThan(0);
121
+ });
122
+ });
@@ -0,0 +1,32 @@
1
+ import { demonstrateSurvivedMutations, anotherWeakFunction } from '../survived-mutations-example';
2
+
3
+ describe('Survived Mutations Example', () => {
4
+ // This test is intentionally terrible to demonstrate survived mutations
5
+
6
+ describe('demonstrateSurvivedMutations', () => {
7
+ it('should just call the function', () => {
8
+ // This test literally does NOTHING except call the function
9
+ // No assertions whatsoever!
10
+
11
+ demonstrateSurvivedMutations(42); // Covers input === 42, return 100
12
+ demonstrateSurvivedMutations(60); // Covers input > 50, return input * 2
13
+ demonstrateSurvivedMutations(5); // Covers default case, return input + 10
14
+
15
+ // NO EXPECTATIONS AT ALL!
16
+ // This means ALL mutations will survive because we don't check anything
17
+ });
18
+ });
19
+
20
+ describe('anotherWeakFunction', () => {
21
+ it('should execute the function', () => {
22
+ // This test calls the function but makes NO assertions!
23
+
24
+ anotherWeakFunction(10, 5); // Covers x > y, return true
25
+ anotherWeakFunction(3, 8); // Covers x <= y, return false
26
+
27
+ // NO EXPECTATIONS AT ALL!
28
+ // return true -> return false: SURVIVES
29
+ // return false -> return true: SURVIVES
30
+ });
31
+ });
32
+ });
@@ -0,0 +1,90 @@
1
+ import { definitelyWillSurvive, anotherSurvivor, booleanSurvivor, guaranteedSurvivor } from '../truly-weak-example';
2
+
3
+ describe('Truly Weak Example - Guaranteed Survived Mutations', () => {
4
+
5
+ describe('definitelyWillSurvive', () => {
6
+ it('should just execute', () => {
7
+ // This test literally does NOTHING except call the function
8
+ // It covers all branches but validates NOTHING
9
+
10
+ definitelyWillSurvive(5); // Covers x === 5, return 42
11
+ definitelyWillSurvive(15); // Covers x > 10, return x + 100
12
+ definitelyWillSurvive(3); // Covers default case, return x * 2
13
+
14
+ // NO ASSERTIONS WHATSOEVER!
15
+ // ALL mutations will survive:
16
+ // return 42 -> return 0: SURVIVES
17
+ // return 42 -> return 1: SURVIVES
18
+ // x + 100 -> x - 100: SURVIVES
19
+ // x + 100 -> x * 100: SURVIVES
20
+ // x * 2 -> x + 2: SURVIVES
21
+ // x * 2 -> x - 2: SURVIVES
22
+ });
23
+ });
24
+
25
+ describe('anotherSurvivor', () => {
26
+ it('should execute without any validation', () => {
27
+ // This test covers all lines but checks NOTHING
28
+
29
+ anotherSurvivor(30, 25); // Covers sum > 50, return sum - 10
30
+ anotherSurvivor(10, 5); // Covers sum <= 50, return sum / 2
31
+
32
+ // NO EXPECTATIONS!
33
+ // Mutations that will survive:
34
+ // a + b -> a - b: SURVIVES
35
+ // a + b -> a * b: SURVIVES
36
+ // sum > 50 -> sum < 50: SURVIVES
37
+ // sum - 10 -> sum + 10: SURVIVES
38
+ // sum / 2 -> sum * 2: SURVIVES
39
+ });
40
+ });
41
+
42
+ describe('booleanSurvivor', () => {
43
+ it('should call the function', () => {
44
+ // This test calls the function but ignores the result completely
45
+
46
+ booleanSurvivor(5); // Covers x > 0, return true
47
+ booleanSurvivor(-3); // Covers x <= 0, return false
48
+
49
+ // NO VALIDATION OF BOOLEAN RESULTS!
50
+ // Mutations that will survive:
51
+ // x > 0 -> x < 0: SURVIVES
52
+ // x > 0 -> x >= 0: SURVIVES
53
+ // return true -> return false: SURVIVES
54
+ // return false -> return true: SURVIVES
55
+ });
56
+ });
57
+
58
+ describe('guaranteedSurvivor', () => {
59
+ it('should execute without any validation whatsoever', () => {
60
+ // This test is designed to be completely useless
61
+ // It catches ALL exceptions and validates NOTHING
62
+
63
+ try {
64
+ guaranteedSurvivor(10); // Should return 100, but we don't check
65
+ guaranteedSurvivor(20); // Should return 200, but we don't check
66
+ guaranteedSurvivor(5); // Should return 10, but we don't check
67
+ guaranteedSurvivor(-1); // Should return 4, but we don't check
68
+ } catch (e) {
69
+ // Even if mutations cause errors, we ignore them!
70
+ // This ensures mutations that change behavior but don't crash will survive
71
+ }
72
+
73
+ // NO ASSERTIONS AT ALL!
74
+ // ALL mutations will survive because:
75
+ // 1. We don't check return values
76
+ // 2. We catch all exceptions
77
+ // 3. We have no expectations
78
+ //
79
+ // Expected survived mutations:
80
+ // input === 10 -> input !== 10: SURVIVES
81
+ // input === 10 -> input > 10: SURVIVES
82
+ // result = 100 -> result = 0: SURVIVES
83
+ // result = 100 -> result = 1: SURVIVES
84
+ // input === 20 -> input !== 20: SURVIVES
85
+ // result = 200 -> result = 0: SURVIVES
86
+ // input + 5 -> input - 5: SURVIVES
87
+ // input + 5 -> input * 5: SURVIVES
88
+ });
89
+ });
90
+ });