phantom-pr 0.4.19 → 0.5.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 +216 -80
- package/dist/core/analysis/astExtractor.d.ts +15 -0
- package/dist/core/analysis/astExtractor.js +354 -0
- package/dist/core/analysis/astExtractor.js.map +1 -0
- package/dist/core/analysis/index.d.ts +3 -0
- package/dist/core/analysis/index.js +3 -0
- package/dist/core/analysis/index.js.map +1 -0
- package/dist/core/analysis/types.d.ts +50 -0
- package/dist/core/analysis/types.js +16 -0
- package/dist/core/analysis/types.js.map +1 -0
- package/dist/core/context/contextSelector.d.ts +29 -0
- package/dist/core/context/contextSelector.js +293 -0
- package/dist/core/context/contextSelector.js.map +1 -0
- package/dist/core/context/index.d.ts +4 -0
- package/dist/core/context/index.js +3 -0
- package/dist/core/context/index.js.map +1 -0
- package/dist/core/generator/enhancedContext.d.ts +34 -0
- package/dist/core/generator/enhancedContext.js +144 -0
- package/dist/core/generator/enhancedContext.js.map +1 -0
- package/dist/core/generator/postValidation.d.ts +24 -0
- package/dist/core/generator/postValidation.js +57 -0
- package/dist/core/generator/postValidation.js.map +1 -0
- package/dist/core/retry/errorParser.d.ts +12 -0
- package/dist/core/retry/errorParser.js +264 -0
- package/dist/core/retry/errorParser.js.map +1 -0
- package/dist/core/retry/feedbackGenerator.d.ts +12 -0
- package/dist/core/retry/feedbackGenerator.js +164 -0
- package/dist/core/retry/feedbackGenerator.js.map +1 -0
- package/dist/core/retry/index.d.ts +3 -0
- package/dist/core/retry/index.js +3 -0
- package/dist/core/retry/index.js.map +1 -0
- package/dist/core/retry/types.d.ts +40 -0
- package/dist/core/retry/types.js +5 -0
- package/dist/core/retry/types.js.map +1 -0
- package/dist/core/testRunner/retryEnhancer.d.ts +32 -0
- package/dist/core/testRunner/retryEnhancer.js +58 -0
- package/dist/core/testRunner/retryEnhancer.js.map +1 -0
- package/dist/core/validation/coverageVerifier.d.ts +16 -0
- package/dist/core/validation/coverageVerifier.js +226 -0
- package/dist/core/validation/coverageVerifier.js.map +1 -0
- package/dist/core/validation/index.d.ts +2 -0
- package/dist/core/validation/index.js +2 -0
- package/dist/core/validation/index.js.map +1 -0
- package/dist/core/validation/types.d.ts +24 -0
- package/dist/core/validation/types.js +6 -0
- package/dist/core/validation/types.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-generation validator that verifies generated tests cover all identified behaviors.
|
|
3
|
+
* Returns structured validation result with specific rejection codes.
|
|
4
|
+
*
|
|
5
|
+
* Static analysis only - does NOT execute the test.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Extract test block names from test file content.
|
|
9
|
+
* Matches it('...'), test('...'), describe('...') patterns.
|
|
10
|
+
*/
|
|
11
|
+
function extractTestNames(testContent) {
|
|
12
|
+
const names = [];
|
|
13
|
+
// Match it('name', ...), test('name', ...), describe('name', ...)
|
|
14
|
+
const testBlockRe = /(?:it|test|describe)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
15
|
+
for (const match of testContent.matchAll(testBlockRe)) {
|
|
16
|
+
const name = match[1];
|
|
17
|
+
if (name)
|
|
18
|
+
names.push(name.toLowerCase());
|
|
19
|
+
}
|
|
20
|
+
return names;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extract jest.mock() and vi.mock() calls from test content.
|
|
24
|
+
*/
|
|
25
|
+
function extractMockedModules(testContent) {
|
|
26
|
+
const mocked = new Set();
|
|
27
|
+
// jest.mock('path') or vi.mock('path')
|
|
28
|
+
const mockRe = /(?:jest|vi)\.mock\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
29
|
+
for (const match of testContent.matchAll(mockRe)) {
|
|
30
|
+
const path = match[1];
|
|
31
|
+
if (path)
|
|
32
|
+
mocked.add(path);
|
|
33
|
+
}
|
|
34
|
+
return mocked;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Check if test content appears to test branch conditions.
|
|
38
|
+
* Looks for patterns that suggest conditional testing.
|
|
39
|
+
*/
|
|
40
|
+
function countBranchTests(testContent, branches) {
|
|
41
|
+
const testNames = extractTestNames(testContent);
|
|
42
|
+
const contentLower = testContent.toLowerCase();
|
|
43
|
+
let testedCount = 0;
|
|
44
|
+
for (const branch of branches) {
|
|
45
|
+
const conditionLower = branch.condition.toLowerCase();
|
|
46
|
+
// Check if any test name mentions the condition
|
|
47
|
+
const mentionedInTestName = testNames.some(name => name.includes(conditionLower) ||
|
|
48
|
+
conditionLower.includes(name.split(' ')[0] ?? ''));
|
|
49
|
+
// Check for common branch testing patterns
|
|
50
|
+
const hasConditionTest = contentLower.includes(`when ${conditionLower}`) ||
|
|
51
|
+
contentLower.includes(`if ${conditionLower}`) ||
|
|
52
|
+
contentLower.includes(`${conditionLower} is true`) ||
|
|
53
|
+
contentLower.includes(`${conditionLower} is false`) ||
|
|
54
|
+
contentLower.includes(`should render when ${conditionLower}`) ||
|
|
55
|
+
contentLower.includes(`should not render when`);
|
|
56
|
+
// Check for assertion patterns that might test the branch
|
|
57
|
+
const hasAssertions = contentLower.includes('tobetruthy') ||
|
|
58
|
+
contentLower.includes('tobefalsy') ||
|
|
59
|
+
contentLower.includes('tobeinthedocument') ||
|
|
60
|
+
contentLower.includes('not.tobeinthedocument');
|
|
61
|
+
if (mentionedInTestName || hasConditionTest || hasAssertions) {
|
|
62
|
+
testedCount++;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Heuristic: if there are multiple test blocks covering different scenarios,
|
|
66
|
+
// assume branches are being adequately tested (lenient to avoid false rejections)
|
|
67
|
+
if (branches.length > 0 && testNames.length >= 2) {
|
|
68
|
+
// If we have descriptive test names, count them as covering branches
|
|
69
|
+
testedCount = Math.max(testedCount, Math.min(branches.length, testNames.length));
|
|
70
|
+
}
|
|
71
|
+
return testedCount;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if test content appears to test React effects.
|
|
75
|
+
*/
|
|
76
|
+
function countEffectTests(testContent, effects) {
|
|
77
|
+
const contentLower = testContent.toLowerCase();
|
|
78
|
+
const testNames = extractTestNames(testContent);
|
|
79
|
+
// Check for effect-related patterns
|
|
80
|
+
const hasEffectTest = contentLower.includes('useeffect') ||
|
|
81
|
+
contentLower.includes('effect') ||
|
|
82
|
+
contentLower.includes('on mount') ||
|
|
83
|
+
contentLower.includes('onmount') ||
|
|
84
|
+
contentLower.includes('lifecycle') ||
|
|
85
|
+
contentLower.includes('side effect');
|
|
86
|
+
// Check for async patterns often used with effects
|
|
87
|
+
const hasAsyncPattern = contentLower.includes('await') ||
|
|
88
|
+
contentLower.includes('waitfor') ||
|
|
89
|
+
contentLower.includes('act(');
|
|
90
|
+
// Check for cleanup patterns (testing cleanup implies testing the effect)
|
|
91
|
+
const hasCleanupPattern = contentLower.includes('unmount') ||
|
|
92
|
+
contentLower.includes('cleanup') ||
|
|
93
|
+
contentLower.includes('clearinterval') ||
|
|
94
|
+
contentLower.includes('cleartimeout');
|
|
95
|
+
// Check for render patterns (basic effect tests render the component)
|
|
96
|
+
const hasRenderPattern = contentLower.includes('render(');
|
|
97
|
+
// If any effect-related pattern is found, assume effects are being tested
|
|
98
|
+
if (hasEffectTest || hasAsyncPattern || hasCleanupPattern) {
|
|
99
|
+
return effects.length;
|
|
100
|
+
}
|
|
101
|
+
// If there are multiple test cases and render is used, be lenient
|
|
102
|
+
if (testNames.length >= 2 && hasRenderPattern) {
|
|
103
|
+
return effects.length;
|
|
104
|
+
}
|
|
105
|
+
return 0;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if test content appears to test cleanup behavior.
|
|
109
|
+
*/
|
|
110
|
+
function hasCleanupTest(testContent) {
|
|
111
|
+
const contentLower = testContent.toLowerCase();
|
|
112
|
+
return (contentLower.includes('unmount') ||
|
|
113
|
+
contentLower.includes('cleanup') ||
|
|
114
|
+
contentLower.includes('clearinterval') ||
|
|
115
|
+
contentLower.includes('cleartimeout') ||
|
|
116
|
+
contentLower.includes('removelistener') ||
|
|
117
|
+
contentLower.includes('unsubscribe') ||
|
|
118
|
+
contentLower.includes('dispose'));
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Extract child component names from import path.
|
|
122
|
+
*/
|
|
123
|
+
function normalizeImportToName(importPath) {
|
|
124
|
+
// Get the last segment and strip extension
|
|
125
|
+
const segments = importPath.split('/');
|
|
126
|
+
const last = segments[segments.length - 1] ?? importPath;
|
|
127
|
+
return last.replace(/\.(tsx?|jsx?)$/, '');
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check which child components are mocked in the test.
|
|
131
|
+
*/
|
|
132
|
+
function findMockedChildren(testContent, children) {
|
|
133
|
+
const mockedModules = extractMockedModules(testContent);
|
|
134
|
+
const mocked = [];
|
|
135
|
+
for (const child of children) {
|
|
136
|
+
// Check if the child's import path is mocked
|
|
137
|
+
const isMocked = mockedModules.has(child.importPath) ||
|
|
138
|
+
[...mockedModules].some(m => m.includes(child.name) ||
|
|
139
|
+
normalizeImportToName(m).toLowerCase() === child.name.toLowerCase());
|
|
140
|
+
if (isMocked) {
|
|
141
|
+
mocked.push(child.name);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Also check for inline mocks: jest.fn() assignments that mention component names
|
|
145
|
+
for (const child of children) {
|
|
146
|
+
if (!mocked.includes(child.name)) {
|
|
147
|
+
const inlineMockRe = new RegExp(`${child.name}[\\s\\S]*?=.*?jest\\.fn|vi\\.fn`, 'i');
|
|
148
|
+
if (inlineMockRe.test(testContent)) {
|
|
149
|
+
mocked.push(child.name);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return [...new Set(mocked)].sort();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Verify that generated test adequately covers the analyzed component.
|
|
157
|
+
*
|
|
158
|
+
* @param analysis - Component analysis from AST extraction
|
|
159
|
+
* @param generatedTestContent - The generated test file content
|
|
160
|
+
* @returns ValidationResult with coverage details and any rejections
|
|
161
|
+
*/
|
|
162
|
+
export function verifyCoverage(analysis, generatedTestContent) {
|
|
163
|
+
const rejections = [];
|
|
164
|
+
const warnings = [];
|
|
165
|
+
// Count branch coverage
|
|
166
|
+
const branchesIdentified = analysis.branches.length;
|
|
167
|
+
const branchesTested = countBranchTests(generatedTestContent, analysis.branches);
|
|
168
|
+
// Count effect coverage
|
|
169
|
+
const effectsIdentified = analysis.effects.length;
|
|
170
|
+
const effectsTested = countEffectTests(generatedTestContent, analysis.effects);
|
|
171
|
+
// Check cleanup requirement
|
|
172
|
+
const cleanupRequired = analysis.effects.some(e => e.hasCleanup);
|
|
173
|
+
const cleanupTested = cleanupRequired ? hasCleanupTest(generatedTestContent) : true;
|
|
174
|
+
// Check child mocking
|
|
175
|
+
const childrenIdentified = analysis.children.map(c => c.name).sort();
|
|
176
|
+
const childrenMocked = findMockedChildren(generatedTestContent, analysis.children);
|
|
177
|
+
// Build coverage report
|
|
178
|
+
const coverage = {
|
|
179
|
+
branchesIdentified,
|
|
180
|
+
branchesTested,
|
|
181
|
+
effectsIdentified,
|
|
182
|
+
effectsTested,
|
|
183
|
+
cleanupRequired,
|
|
184
|
+
cleanupTested,
|
|
185
|
+
childrenIdentified,
|
|
186
|
+
childrenMocked,
|
|
187
|
+
};
|
|
188
|
+
// Apply rejection rules
|
|
189
|
+
// Rule: All branches should be tested
|
|
190
|
+
if (branchesIdentified > 0 && branchesTested < branchesIdentified) {
|
|
191
|
+
// Only reject if significantly under-tested
|
|
192
|
+
const coverage = branchesTested / branchesIdentified;
|
|
193
|
+
if (coverage < 0.5) {
|
|
194
|
+
rejections.push('llm_reject_incomplete_branch_coverage');
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
warnings.push(`Branch coverage: ${branchesTested}/${branchesIdentified} (${Math.round(coverage * 100)}%)`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Rule: Cleanup must be tested if required
|
|
201
|
+
if (cleanupRequired && !cleanupTested) {
|
|
202
|
+
rejections.push('llm_reject_missing_cleanup_test');
|
|
203
|
+
}
|
|
204
|
+
// Rule: All child components should be mocked
|
|
205
|
+
const unmockedChildren = childrenIdentified.filter(c => !childrenMocked.includes(c));
|
|
206
|
+
if (unmockedChildren.length > 0) {
|
|
207
|
+
// Only reject if more than half are unmocked
|
|
208
|
+
if (unmockedChildren.length > childrenIdentified.length / 2) {
|
|
209
|
+
rejections.push('llm_reject_unmocked_child');
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
warnings.push(`Unmocked children: ${unmockedChildren.join(', ')}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Rule: Effects should be tested
|
|
216
|
+
if (effectsIdentified > 0 && effectsTested === 0) {
|
|
217
|
+
rejections.push('llm_reject_missing_effect_test');
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
valid: rejections.length === 0,
|
|
221
|
+
rejections,
|
|
222
|
+
warnings,
|
|
223
|
+
coverage,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=coverageVerifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverageVerifier.js","sourceRoot":"","sources":["../../../src/core/validation/coverageVerifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/validation/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for post-generation validation.
|
|
3
|
+
* Verifies generated tests cover all identified behaviors.
|
|
4
|
+
*/
|
|
5
|
+
/** Rejection codes matching existing guardrail pattern (llm_reject_*). */
|
|
6
|
+
export type RejectionCode = 'llm_reject_incomplete_branch_coverage' | 'llm_reject_missing_cleanup_test' | 'llm_reject_unmocked_child' | 'llm_reject_missing_effect_test';
|
|
7
|
+
/** Coverage report showing what was analyzed vs tested. */
|
|
8
|
+
export type CoverageReport = {
|
|
9
|
+
branchesIdentified: number;
|
|
10
|
+
branchesTested: number;
|
|
11
|
+
effectsIdentified: number;
|
|
12
|
+
effectsTested: number;
|
|
13
|
+
cleanupRequired: boolean;
|
|
14
|
+
cleanupTested: boolean;
|
|
15
|
+
childrenIdentified: string[];
|
|
16
|
+
childrenMocked: string[];
|
|
17
|
+
};
|
|
18
|
+
/** Result of coverage verification. */
|
|
19
|
+
export type ValidationResult = {
|
|
20
|
+
valid: boolean;
|
|
21
|
+
rejections: RejectionCode[];
|
|
22
|
+
warnings: string[];
|
|
23
|
+
coverage: CoverageReport;
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/validation/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|