@vibe-validate/extractors 0.12.1 → 0.12.2
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 +68 -9
- package/dist/ava-extractor.d.ts +24 -0
- package/dist/ava-extractor.d.ts.map +1 -0
- package/dist/ava-extractor.js +367 -0
- package/dist/ava-extractor.js.map +1 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/jasmine-extractor.d.ts +23 -0
- package/dist/jasmine-extractor.d.ts.map +1 -0
- package/dist/jasmine-extractor.js +254 -0
- package/dist/jasmine-extractor.js.map +1 -0
- package/dist/jest-extractor.d.ts +29 -0
- package/dist/jest-extractor.d.ts.map +1 -0
- package/dist/jest-extractor.js +115 -0
- package/dist/jest-extractor.js.map +1 -0
- package/dist/junit-extractor.d.ts +24 -0
- package/dist/junit-extractor.d.ts.map +1 -0
- package/dist/junit-extractor.js +264 -0
- package/dist/junit-extractor.js.map +1 -0
- package/dist/mocha-extractor.d.ts +23 -0
- package/dist/mocha-extractor.d.ts.map +1 -0
- package/dist/mocha-extractor.js +263 -0
- package/dist/mocha-extractor.js.map +1 -0
- package/dist/playwright-extractor.d.ts +38 -0
- package/dist/playwright-extractor.d.ts.map +1 -0
- package/dist/playwright-extractor.js +230 -0
- package/dist/playwright-extractor.js.map +1 -0
- package/dist/smart-extractor.d.ts +14 -1
- package/dist/smart-extractor.d.ts.map +1 -1
- package/dist/smart-extractor.js +50 -1
- package/dist/smart-extractor.js.map +1 -1
- package/dist/tap-extractor.d.ts +24 -0
- package/dist/tap-extractor.d.ts.map +1 -0
- package/dist/tap-extractor.js +227 -0
- package/dist/tap-extractor.js.map +1 -0
- package/dist/types.d.ts +21 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vitest-extractor.d.ts +9 -1
- package/dist/vitest-extractor.d.ts.map +1 -1
- package/dist/vitest-extractor.js +112 -16
- package/dist/vitest-extractor.js.map +1 -1
- package/package.json +3 -5
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JUnit XML Error Extractor
|
|
3
|
+
*
|
|
4
|
+
* Parses JUnit XML test reports and formats failures for LLM consumption.
|
|
5
|
+
* Supports Vitest, Jest, and other test frameworks that output JUnit XML.
|
|
6
|
+
*
|
|
7
|
+
* @package @vibe-validate/extractors
|
|
8
|
+
*/
|
|
9
|
+
import { stripAnsiCodes } from './utils.js';
|
|
10
|
+
/**
|
|
11
|
+
* Extract errors from JUnit XML test output
|
|
12
|
+
*
|
|
13
|
+
* @param output - JUnit XML string
|
|
14
|
+
* @returns Structured error information
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const junitXml = fs.readFileSync('junit.xml', 'utf-8');
|
|
19
|
+
* const result = extractJUnitErrors(junitXml);
|
|
20
|
+
* console.log(result.summary); // "5 test(s) failed"
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function extractJUnitErrors(output) {
|
|
24
|
+
const cleanOutput = stripAnsiCodes(output);
|
|
25
|
+
// Try to parse XML
|
|
26
|
+
let isValidXml = false;
|
|
27
|
+
try {
|
|
28
|
+
// Simple XML parsing - look for <testsuite> and <testcase> elements
|
|
29
|
+
isValidXml = parseSimpleXML(cleanOutput);
|
|
30
|
+
}
|
|
31
|
+
catch (_error) {
|
|
32
|
+
return {
|
|
33
|
+
summary: 'Unable to parse JUnit XML - invalid format',
|
|
34
|
+
errors: [],
|
|
35
|
+
totalCount: 0,
|
|
36
|
+
cleanOutput: cleanOutput.trim(),
|
|
37
|
+
guidance: 'Ensure the input is valid JUnit XML format',
|
|
38
|
+
metadata: {
|
|
39
|
+
confidence: 0,
|
|
40
|
+
completeness: 0,
|
|
41
|
+
issues: ['Failed to parse XML']
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (!isValidXml) {
|
|
46
|
+
return {
|
|
47
|
+
summary: '0 test(s) failed',
|
|
48
|
+
errors: [],
|
|
49
|
+
totalCount: 0,
|
|
50
|
+
cleanOutput: '',
|
|
51
|
+
guidance: '',
|
|
52
|
+
metadata: {
|
|
53
|
+
confidence: 100,
|
|
54
|
+
completeness: 100,
|
|
55
|
+
issues: []
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Extract all failure elements
|
|
60
|
+
const failures = extractFailures(cleanOutput);
|
|
61
|
+
const errors = [];
|
|
62
|
+
let completeCount = 0;
|
|
63
|
+
for (const failure of failures) {
|
|
64
|
+
const file = failure.file || 'unknown';
|
|
65
|
+
const location = failure.location || `${file}:0`;
|
|
66
|
+
const message = failure.message || 'Test failed';
|
|
67
|
+
const context = failure.testName || '';
|
|
68
|
+
const isComplete = file !== 'unknown' && failure.location && message;
|
|
69
|
+
if (isComplete) {
|
|
70
|
+
completeCount++;
|
|
71
|
+
}
|
|
72
|
+
// Parse location to get line/column (only if location exists)
|
|
73
|
+
let line;
|
|
74
|
+
if (location) {
|
|
75
|
+
const locationParts = location.split(':');
|
|
76
|
+
line = locationParts[1] ? parseInt(locationParts[1], 10) : undefined;
|
|
77
|
+
}
|
|
78
|
+
errors.push({
|
|
79
|
+
file,
|
|
80
|
+
line,
|
|
81
|
+
message: decodeHtmlEntities(message),
|
|
82
|
+
context: decodeHtmlEntities(context)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
// Generate summary
|
|
86
|
+
const failureCount = failures.length;
|
|
87
|
+
const summary = `${failureCount} test(s) failed`;
|
|
88
|
+
// Generate guidance based on error types
|
|
89
|
+
const guidance = generateGuidance(failures);
|
|
90
|
+
// Calculate quality metadata
|
|
91
|
+
const completeness = failures.length > 0 ? (completeCount / failures.length) * 100 : 100;
|
|
92
|
+
const confidence = failures.length > 0 ? 95 : 100; // High confidence for JUnit XML
|
|
93
|
+
const metadata = {
|
|
94
|
+
confidence,
|
|
95
|
+
completeness,
|
|
96
|
+
issues: []
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
summary,
|
|
100
|
+
errors,
|
|
101
|
+
totalCount: failures.length,
|
|
102
|
+
cleanOutput: formatCleanOutput(errors),
|
|
103
|
+
guidance,
|
|
104
|
+
metadata
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Simple XML parser for JUnit format
|
|
109
|
+
* (We avoid full XML parsers to minimize dependencies)
|
|
110
|
+
*/
|
|
111
|
+
function parseSimpleXML(xml) {
|
|
112
|
+
// Check if it contains testsuite elements
|
|
113
|
+
if (!xml.includes('<testsuite') && !xml.includes('<testsuites')) {
|
|
114
|
+
throw new Error('Not JUnit XML format');
|
|
115
|
+
}
|
|
116
|
+
// Validate basic XML structure
|
|
117
|
+
if (!xml.includes('<?xml') && !xml.includes('<testsuite')) {
|
|
118
|
+
throw new Error('Invalid XML structure');
|
|
119
|
+
}
|
|
120
|
+
// Return that XML is valid
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
function extractFailures(xml) {
|
|
124
|
+
const failures = [];
|
|
125
|
+
// Match all <testcase> elements with <failure> children
|
|
126
|
+
const testcasePattern = /<testcase[^>]*>([\s\S]*?)<\/testcase>/g;
|
|
127
|
+
let testcaseMatch;
|
|
128
|
+
while ((testcaseMatch = testcasePattern.exec(xml)) !== null) {
|
|
129
|
+
const testcaseContent = testcaseMatch[0];
|
|
130
|
+
const testcaseInner = testcaseMatch[1];
|
|
131
|
+
// Check if this testcase has a failure
|
|
132
|
+
if (!testcaseInner.includes('<failure')) {
|
|
133
|
+
continue; // Skip passing tests
|
|
134
|
+
}
|
|
135
|
+
// Extract attributes from testcase opening tag using more reliable string extraction
|
|
136
|
+
const testcaseTagMatch = testcaseContent.match(/<testcase([^>]*)>/);
|
|
137
|
+
const testcaseTag = testcaseTagMatch ? testcaseTagMatch[1] : '';
|
|
138
|
+
// Extract classname using indexOf/substring (more reliable than regex for attributes with special chars)
|
|
139
|
+
let file;
|
|
140
|
+
const classnameIdx = testcaseTag.indexOf('classname="');
|
|
141
|
+
if (classnameIdx !== -1) {
|
|
142
|
+
const start = classnameIdx + 'classname="'.length;
|
|
143
|
+
const end = testcaseTag.indexOf('"', start);
|
|
144
|
+
file = testcaseTag.substring(start, end);
|
|
145
|
+
}
|
|
146
|
+
// Extract name (test hierarchy) similarly
|
|
147
|
+
let testName;
|
|
148
|
+
const nameIdx = testcaseTag.indexOf('name="');
|
|
149
|
+
if (nameIdx !== -1) {
|
|
150
|
+
const start = nameIdx + 'name="'.length;
|
|
151
|
+
const end = testcaseTag.indexOf('"', start);
|
|
152
|
+
testName = testcaseTag.substring(start, end);
|
|
153
|
+
}
|
|
154
|
+
// Extract failure element
|
|
155
|
+
const failurePattern = /<failure[^>]*>([\s\S]*?)<\/failure>/;
|
|
156
|
+
const failureMatch = testcaseInner.match(failurePattern);
|
|
157
|
+
if (!failureMatch) {
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const failureContent = failureMatch[0];
|
|
161
|
+
const failureText = failureMatch[1];
|
|
162
|
+
// Extract message attribute
|
|
163
|
+
const messageMatch = failureContent.match(/message="([^"]+)"/);
|
|
164
|
+
const message = messageMatch ? messageMatch[1] : undefined;
|
|
165
|
+
// Extract error type
|
|
166
|
+
const typeMatch = failureContent.match(/type="([^"]+)"/);
|
|
167
|
+
const errorType = typeMatch ? typeMatch[1] : undefined;
|
|
168
|
+
// Extract location from failure text (❯ file:line:column)
|
|
169
|
+
// Note: We strip column number to keep format consistent (file:line)
|
|
170
|
+
// Pattern allows word chars, forward slashes, dots, hyphens, and underscores in paths
|
|
171
|
+
const locationPattern = /❯\s+([\w/._-]+):(\d+)(?::\d+)?/;
|
|
172
|
+
const locationMatch = failureText.match(locationPattern);
|
|
173
|
+
let location;
|
|
174
|
+
let extractedFile;
|
|
175
|
+
if (locationMatch) {
|
|
176
|
+
extractedFile = locationMatch[1];
|
|
177
|
+
const line = locationMatch[2];
|
|
178
|
+
location = `${extractedFile}:${line}`;
|
|
179
|
+
}
|
|
180
|
+
// No fallback - if no location found in failure text, leave location undefined
|
|
181
|
+
failures.push({
|
|
182
|
+
file: extractedFile || file,
|
|
183
|
+
location,
|
|
184
|
+
message,
|
|
185
|
+
testName,
|
|
186
|
+
errorType
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return failures;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Decode HTML entities in XML content
|
|
193
|
+
*/
|
|
194
|
+
function decodeHtmlEntities(text) {
|
|
195
|
+
return text
|
|
196
|
+
.replace(/>/g, '>')
|
|
197
|
+
.replace(/</g, '<')
|
|
198
|
+
.replace(/"/g, '"')
|
|
199
|
+
.replace(/'/g, "'")
|
|
200
|
+
.replace(/&/g, '&'); // Must be last to avoid double-decoding
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Generate guidance based on failure types
|
|
204
|
+
*/
|
|
205
|
+
function generateGuidance(failures) {
|
|
206
|
+
const guidances = [];
|
|
207
|
+
const seen = new Set();
|
|
208
|
+
for (const failure of failures) {
|
|
209
|
+
const message = failure.message || '';
|
|
210
|
+
const errorType = failure.errorType;
|
|
211
|
+
// Assertion errors
|
|
212
|
+
if (errorType === 'AssertionError' || message.includes('expected')) {
|
|
213
|
+
if (!seen.has('assertion')) {
|
|
214
|
+
guidances.push('Review test assertions and expected values');
|
|
215
|
+
seen.add('assertion');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Timeout errors
|
|
219
|
+
if (message.includes('timed out') || message.includes('timeout')) {
|
|
220
|
+
if (!seen.has('timeout')) {
|
|
221
|
+
guidances.push('Increase test timeout or optimize async operations');
|
|
222
|
+
seen.add('timeout');
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Type errors
|
|
226
|
+
if (errorType === 'TypeError') {
|
|
227
|
+
if (!seen.has('type')) {
|
|
228
|
+
guidances.push('Check for null/undefined values and type mismatches');
|
|
229
|
+
seen.add('type');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
// File errors
|
|
233
|
+
if (message.includes('ENOENT') || message.includes('no such file')) {
|
|
234
|
+
if (!seen.has('file')) {
|
|
235
|
+
guidances.push('Verify file paths and ensure test fixtures exist');
|
|
236
|
+
seen.add('file');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Module errors
|
|
240
|
+
if (message.includes('Cannot find package') || message.includes('Cannot find module')) {
|
|
241
|
+
if (!seen.has('module')) {
|
|
242
|
+
guidances.push('Install missing dependencies or check import paths');
|
|
243
|
+
seen.add('module');
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return guidances.join('\n');
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Format clean output for LLM consumption
|
|
251
|
+
*/
|
|
252
|
+
function formatCleanOutput(errors) {
|
|
253
|
+
if (errors.length === 0) {
|
|
254
|
+
return '';
|
|
255
|
+
}
|
|
256
|
+
return errors
|
|
257
|
+
.map((error) => {
|
|
258
|
+
const location = error.line ? `${error.file}:${error.line}` : error.file;
|
|
259
|
+
const contextStr = error.context ? ` (${error.context})` : '';
|
|
260
|
+
return `${location}: ${error.message}${contextStr}`;
|
|
261
|
+
})
|
|
262
|
+
.join('\n');
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=junit-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"junit-extractor.js","sourceRoot":"","sources":["../src/junit-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mocha Error Extractor
|
|
3
|
+
*
|
|
4
|
+
* Parses Mocha test output and formats failures for LLM consumption.
|
|
5
|
+
*
|
|
6
|
+
* @package @vibe-validate/extractors
|
|
7
|
+
*/
|
|
8
|
+
import type { ErrorExtractorResult } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Extract errors from Mocha test output
|
|
11
|
+
*
|
|
12
|
+
* @param output - Mocha text output
|
|
13
|
+
* @returns Structured error information
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const mochaOutput = execSync('mocha tests/**\/*.test.js', { encoding: 'utf-8' });
|
|
18
|
+
* const result = extractMochaErrors(mochaOutput);
|
|
19
|
+
* console.log(result.summary); // "5 test(s) failed"
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractMochaErrors(output: string): ErrorExtractorResult;
|
|
23
|
+
//# sourceMappingURL=mocha-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mocha-extractor.d.ts","sourceRoot":"","sources":["../src/mocha-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAsC,MAAM,YAAY,CAAC;AAG3F;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CAsFvE"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mocha Error Extractor
|
|
3
|
+
*
|
|
4
|
+
* Parses Mocha test output and formats failures for LLM consumption.
|
|
5
|
+
*
|
|
6
|
+
* @package @vibe-validate/extractors
|
|
7
|
+
*/
|
|
8
|
+
import { stripAnsiCodes } from './utils.js';
|
|
9
|
+
/**
|
|
10
|
+
* Extract errors from Mocha test output
|
|
11
|
+
*
|
|
12
|
+
* @param output - Mocha text output
|
|
13
|
+
* @returns Structured error information
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const mochaOutput = execSync('mocha tests/**\/*.test.js', { encoding: 'utf-8' });
|
|
18
|
+
* const result = extractMochaErrors(mochaOutput);
|
|
19
|
+
* console.log(result.summary); // "5 test(s) failed"
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export function extractMochaErrors(output) {
|
|
23
|
+
const cleanOutput = stripAnsiCodes(output);
|
|
24
|
+
// Check if this looks like Mocha output
|
|
25
|
+
if (!cleanOutput.includes('failing') && !cleanOutput.includes('passing')) {
|
|
26
|
+
return {
|
|
27
|
+
summary: 'Unable to parse Mocha output - invalid format',
|
|
28
|
+
errors: [],
|
|
29
|
+
totalCount: 0,
|
|
30
|
+
cleanOutput: cleanOutput.trim(),
|
|
31
|
+
guidance: 'Ensure the input is valid Mocha test output',
|
|
32
|
+
metadata: {
|
|
33
|
+
confidence: 0,
|
|
34
|
+
completeness: 0,
|
|
35
|
+
issues: ['Not Mocha output format']
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// Extract failure count
|
|
40
|
+
const failingMatch = cleanOutput.match(/(\d+) failing/);
|
|
41
|
+
const failureCount = failingMatch ? parseInt(failingMatch[1], 10) : 0;
|
|
42
|
+
if (failureCount === 0) {
|
|
43
|
+
return {
|
|
44
|
+
summary: '0 test(s) failed',
|
|
45
|
+
errors: [],
|
|
46
|
+
totalCount: 0,
|
|
47
|
+
cleanOutput: '',
|
|
48
|
+
guidance: '',
|
|
49
|
+
metadata: {
|
|
50
|
+
confidence: 100,
|
|
51
|
+
completeness: 100,
|
|
52
|
+
issues: []
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Extract all failures
|
|
57
|
+
const failures = extractFailures(cleanOutput);
|
|
58
|
+
const errors = [];
|
|
59
|
+
let completeCount = 0;
|
|
60
|
+
for (const failure of failures) {
|
|
61
|
+
const file = failure.file || 'unknown';
|
|
62
|
+
const message = failure.message || 'Test failed';
|
|
63
|
+
const context = failure.testName || '';
|
|
64
|
+
const isComplete = file !== 'unknown' && failure.line && message;
|
|
65
|
+
if (isComplete) {
|
|
66
|
+
completeCount++;
|
|
67
|
+
}
|
|
68
|
+
errors.push({
|
|
69
|
+
file,
|
|
70
|
+
line: failure.line,
|
|
71
|
+
message,
|
|
72
|
+
context
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
// Generate summary
|
|
76
|
+
const summary = `${failures.length} test(s) failed`;
|
|
77
|
+
// Generate guidance
|
|
78
|
+
const guidance = generateGuidance(failures);
|
|
79
|
+
// Calculate quality metadata
|
|
80
|
+
const completeness = failures.length > 0 ? (completeCount / failures.length) * 100 : 100;
|
|
81
|
+
const confidence = failures.length > 0 ? 95 : 100; // High confidence for Mocha
|
|
82
|
+
const metadata = {
|
|
83
|
+
confidence,
|
|
84
|
+
completeness,
|
|
85
|
+
issues: []
|
|
86
|
+
};
|
|
87
|
+
return {
|
|
88
|
+
summary,
|
|
89
|
+
errors,
|
|
90
|
+
totalCount: failures.length,
|
|
91
|
+
cleanOutput: formatCleanOutput(errors),
|
|
92
|
+
guidance,
|
|
93
|
+
metadata
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Extract failure information from Mocha output
|
|
98
|
+
*/
|
|
99
|
+
function extractFailures(output) {
|
|
100
|
+
const failures = [];
|
|
101
|
+
const lines = output.split('\n');
|
|
102
|
+
let i = 0;
|
|
103
|
+
while (i < lines.length) {
|
|
104
|
+
const line = lines[i];
|
|
105
|
+
// Look for numbered failure markers (e.g., " 1) ")
|
|
106
|
+
// Only match detailed format (2 spaces), not summary format (6+ spaces)
|
|
107
|
+
const failureMatch = line.match(/^ {2}(\d+)\)\s+(.*)$/);
|
|
108
|
+
if (failureMatch) {
|
|
109
|
+
const _failureNumber = failureMatch[1]; // Extracted but not used (test name is more important)
|
|
110
|
+
const firstPart = failureMatch[2].trim();
|
|
111
|
+
// Collect test hierarchy lines
|
|
112
|
+
const testNameParts = [];
|
|
113
|
+
// Check if first part ends with colon (simple format: "1) Test:")
|
|
114
|
+
const isSimpleFormat = firstPart.endsWith(':');
|
|
115
|
+
if (firstPart) {
|
|
116
|
+
testNameParts.push(firstPart.replace(/:$/, '')); // Remove trailing colon
|
|
117
|
+
}
|
|
118
|
+
let j = i + 1;
|
|
119
|
+
// If simple format, don't try to collect more hierarchy
|
|
120
|
+
if (!isSimpleFormat) {
|
|
121
|
+
// Continue collecting hierarchy lines until we hit blank line or error
|
|
122
|
+
while (j < lines.length) {
|
|
123
|
+
const nextLine = lines[j];
|
|
124
|
+
// Blank line marks end of hierarchy
|
|
125
|
+
if (nextLine.trim() === '') {
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
// Error line marks end of hierarchy
|
|
129
|
+
if (nextLine.match(/^\s+(Error|AssertionError|TypeError)/)) {
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
// Indented lines are part of hierarchy (at least 5 spaces for Mocha)
|
|
133
|
+
if (nextLine.match(/^\s{5,}\S/)) {
|
|
134
|
+
const part = nextLine.trim().replace(/:$/, ''); // Remove trailing colon
|
|
135
|
+
testNameParts.push(part);
|
|
136
|
+
}
|
|
137
|
+
j++;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const testName = testNameParts.join(' > ');
|
|
141
|
+
// Now scan for error message and stack trace
|
|
142
|
+
let message;
|
|
143
|
+
let errorType;
|
|
144
|
+
let file;
|
|
145
|
+
let lineNumber;
|
|
146
|
+
// Continue from where we left off
|
|
147
|
+
while (j < lines.length && j < i + 40) {
|
|
148
|
+
const nextLine = lines[j];
|
|
149
|
+
// Stop if we hit the next failure
|
|
150
|
+
if (nextLine.match(/^\s+\d+\)\s+/)) {
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
// Extract error type and message
|
|
154
|
+
// Pattern 1: " AssertionError [ERR_ASSERTION]: Expected..."
|
|
155
|
+
// Pattern 2: " Error: ENOENT: no such file..."
|
|
156
|
+
// Pattern 3: " TypeError: Cannot read..."
|
|
157
|
+
if (!message) {
|
|
158
|
+
// Match plain "Error" or prefixed errors like "TypeError", "AssertionError"
|
|
159
|
+
const errorMatch = nextLine.match(/^\s+([A-Za-z]*Error)(?:\s\[[\w_]+\])?\s*:\s*(.+)/);
|
|
160
|
+
if (errorMatch) {
|
|
161
|
+
errorType = errorMatch[1];
|
|
162
|
+
message = errorMatch[2].trim();
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Extract file location from stack trace
|
|
166
|
+
if (!file && nextLine.includes('at Context.<anonymous>')) {
|
|
167
|
+
// Match various path formats:
|
|
168
|
+
// - file:///path/to/file.js:10:20
|
|
169
|
+
// - /absolute/path/file.js:10:20
|
|
170
|
+
// - relative/path/file.js:10:20
|
|
171
|
+
const locationMatch = nextLine.match(/at Context\.<anonymous> \((?:file:\/\/)?([^:)]+):(\d+)(?::(\d+))?\)/);
|
|
172
|
+
if (locationMatch) {
|
|
173
|
+
file = locationMatch[1];
|
|
174
|
+
lineNumber = parseInt(locationMatch[2], 10);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Extract file from timeout error messages: "Error: Timeout... (/path/to/file.js)"
|
|
178
|
+
if (!file && message && message.includes('Timeout')) {
|
|
179
|
+
const timeoutFileMatch = message.match(/\(([^)]+\.(?:js|ts|mjs|cjs))\)/);
|
|
180
|
+
if (timeoutFileMatch) {
|
|
181
|
+
file = timeoutFileMatch[1];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
j++;
|
|
185
|
+
}
|
|
186
|
+
failures.push({
|
|
187
|
+
testName,
|
|
188
|
+
message,
|
|
189
|
+
errorType,
|
|
190
|
+
file,
|
|
191
|
+
line: lineNumber
|
|
192
|
+
});
|
|
193
|
+
i = j; // Skip to after this failure
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
i++;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return failures;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Generate guidance based on failure types
|
|
203
|
+
*/
|
|
204
|
+
function generateGuidance(failures) {
|
|
205
|
+
const guidances = [];
|
|
206
|
+
const seen = new Set();
|
|
207
|
+
for (const failure of failures) {
|
|
208
|
+
const message = failure.message || '';
|
|
209
|
+
const errorType = failure.errorType;
|
|
210
|
+
// Assertion errors
|
|
211
|
+
if (errorType === 'AssertionError' || message.includes('expected') || message.includes('Expected')) {
|
|
212
|
+
if (!seen.has('assertion')) {
|
|
213
|
+
guidances.push('Review test assertions and expected values');
|
|
214
|
+
seen.add('assertion');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
// Timeout errors
|
|
218
|
+
if (message.includes('Timeout') || message.includes('timeout') || message.includes('exceeded')) {
|
|
219
|
+
if (!seen.has('timeout')) {
|
|
220
|
+
guidances.push('Increase test timeout or optimize async operations');
|
|
221
|
+
seen.add('timeout');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Type errors
|
|
225
|
+
if (errorType === 'TypeError') {
|
|
226
|
+
if (!seen.has('type')) {
|
|
227
|
+
guidances.push('Check for null/undefined values and type mismatches');
|
|
228
|
+
seen.add('type');
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// File errors
|
|
232
|
+
if (message.includes('ENOENT') || message.includes('no such file')) {
|
|
233
|
+
if (!seen.has('file')) {
|
|
234
|
+
guidances.push('Verify file paths and ensure test fixtures exist');
|
|
235
|
+
seen.add('file');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// Module errors
|
|
239
|
+
if (message.includes('Cannot find package') || message.includes('Cannot find module')) {
|
|
240
|
+
if (!seen.has('module')) {
|
|
241
|
+
guidances.push('Install missing dependencies or check import paths');
|
|
242
|
+
seen.add('module');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return guidances.join('\n');
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Format clean output for LLM consumption
|
|
250
|
+
*/
|
|
251
|
+
function formatCleanOutput(errors) {
|
|
252
|
+
if (errors.length === 0) {
|
|
253
|
+
return '';
|
|
254
|
+
}
|
|
255
|
+
return errors
|
|
256
|
+
.map((error) => {
|
|
257
|
+
const location = error.line ? `${error.file}:${error.line}` : error.file;
|
|
258
|
+
const contextStr = error.context ? ` (${error.context})` : '';
|
|
259
|
+
return `${location}: ${error.message}${contextStr}`;
|
|
260
|
+
})
|
|
261
|
+
.join('\n');
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=mocha-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mocha-extractor.js","sourceRoot":"","sources":["../src/mocha-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IAE3C,wCAAwC;IACxC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzE,OAAO;YACL,OAAO,EAAE,+CAA+C;YACxD,MAAM,EAAE,EAAE;YACV,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,WAAW,CAAC,IAAI,EAAE;YAC/B,QAAQ,EAAE,6CAA6C;YACvD,QAAQ,EAAE;gBACR,UAAU,EAAE,CAAC;gBACb,YAAY,EAAE,CAAC;gBACf,MAAM,EAAE,CAAC,yBAAyB,CAAC;aACpC;SACF,CAAC;IACJ,CAAC;IAED,wBAAwB;IACxB,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEtE,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,OAAO,EAAE,kBAAkB;YAC3B,MAAM,EAAE,EAAE;YACV,UAAU,EAAE,CAAC;YACb,WAAW,EAAE,EAAE;YACf,QAAQ,EAAE,EAAE;YACZ,QAAQ,EAAE;gBACR,UAAU,EAAE,GAAG;gBACf,YAAY,EAAE,GAAG;gBACjB,MAAM,EAAE,EAAE;aACX;SACF,CAAC;IACJ,CAAC;IAED,uBAAuB;IACvB,MAAM,QAAQ,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAqB,EAAE,CAAC;IAEpC,IAAI,aAAa,GAAG,CAAC,CAAC;IAEtB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,SAAS,CAAC;QACvC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,aAAa,CAAC;QACjD,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;QAEvC,MAAM,UAAU,GAAG,IAAI,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC;QACjE,IAAI,UAAU,EAAE,CAAC;YACf,aAAa,EAAE,CAAC;QAClB,CAAC;QAED,MAAM,CAAC,IAAI,CAAC;YACV,IAAI;YACJ,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,OAAO;YACP,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,mBAAmB;IACnB,MAAM,OAAO,GAAG,GAAG,QAAQ,CAAC,MAAM,iBAAiB,CAAC;IAEpD,oBAAoB;IACpB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAE5C,6BAA6B;IAC7B,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACzF,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,4BAA4B;IAE/E,MAAM,QAAQ,GAAuB;QACnC,UAAU;QACV,YAAY;QACZ,MAAM,EAAE,EAAE;KACX,CAAC;IAEF,OAAO;QACL,OAAO;QACP,MAAM;QACN,UAAU,EAAE,QAAQ,CAAC,MAAM;QAC3B,WAAW,EAAE,iBAAiB,CAAC,MAAM,CAAC;QACtC,QAAQ;QACR,QAAQ;KACT,CAAC;AACJ,CAAC;AAaD;;GAEG;AACH,SAAS,eAAe,CAAC,MAAc;IACrC,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAEtB,oDAAoD;QACpD,wEAAwE;QACxE,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAExD,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,cAAc,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,uDAAuD;YAC/F,MAAM,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAEzC,+BAA+B;YAC/B,MAAM,aAAa,GAAa,EAAE,CAAC;YAEnC,kEAAkE;YAClE,MAAM,cAAc,GAAG,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAE/C,IAAI,SAAS,EAAE,CAAC;gBACd,aAAa,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,wBAAwB;YAC3E,CAAC;YAED,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEd,wDAAwD;YACxD,IAAI,CAAC,cAAc,EAAE,CAAC;gBACpB,uEAAuE;gBACvE,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;oBACxB,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;oBAE1B,oCAAoC;oBACpC,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;wBAC3B,MAAM;oBACR,CAAC;oBAED,oCAAoC;oBACpC,IAAI,QAAQ,CAAC,KAAK,CAAC,sCAAsC,CAAC,EAAE,CAAC;wBAC3D,MAAM;oBACR,CAAC;oBAED,qEAAqE;oBACrE,IAAI,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC;wBAChC,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,wBAAwB;wBACxE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC3B,CAAC;oBAED,CAAC,EAAE,CAAC;gBACN,CAAC;YACH,CAAC;YAED,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAE3C,6CAA6C;YAC7C,IAAI,OAA2B,CAAC;YAChC,IAAI,SAA6B,CAAC;YAClC,IAAI,IAAwB,CAAC;YAC7B,IAAI,UAA8B,CAAC;YAEnC,kCAAkC;YAClC,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAE1B,kCAAkC;gBAClC,IAAI,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC;oBACnC,MAAM;gBACR,CAAC;gBAED,iCAAiC;gBACjC,gEAAgE;gBAChE,mDAAmD;gBACnD,8CAA8C;gBAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,4EAA4E;oBAC5E,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;oBACtF,IAAI,UAAU,EAAE,CAAC;wBACf,SAAS,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;wBAC1B,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBACjC,CAAC;gBACH,CAAC;gBAED,yCAAyC;gBACzC,IAAI,CAAC,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,CAAC;oBACzD,8BAA8B;oBAC9B,kCAAkC;oBAClC,iCAAiC;oBACjC,gCAAgC;oBAChC,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,qEAAqE,CAAC,CAAC;oBAC5G,IAAI,aAAa,EAAE,CAAC;wBAClB,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;wBACxB,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC9C,CAAC;gBACH,CAAC;gBAED,mFAAmF;gBACnF,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;oBACpD,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;oBACzE,IAAI,gBAAgB,EAAE,CAAC;wBACrB,IAAI,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;oBAC7B,CAAC;gBACH,CAAC;gBAED,CAAC,EAAE,CAAC;YACN,CAAC;YAED,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ;gBACR,OAAO;gBACP,SAAS;gBACT,IAAI;gBACJ,IAAI,EAAE,UAAU;aACjB,CAAC,CAAC;YAEH,CAAC,GAAG,CAAC,CAAC,CAAC,6BAA6B;QACtC,CAAC;aAAM,CAAC;YACN,CAAC,EAAE,CAAC;QACN,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,QAAuB;IAC/C,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QAEpC,mBAAmB;QACnB,IAAI,SAAS,KAAK,gBAAgB,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACnG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC3B,SAAS,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;gBAC7D,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;QAED,iBAAiB;QACjB,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAC/F,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;gBACzB,SAAS,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;gBACrE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAED,cAAc;QACd,IAAI,SAAS,KAAK,WAAW,EAAE,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,SAAS,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;gBACtE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,cAAc;QACd,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YACnE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBACtB,SAAS,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;gBACnE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,gBAAgB;QAChB,IAAI,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,CAAC;YACtF,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACxB,SAAS,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;gBACrE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED;;GAEG;AACH,SAAS,iBAAiB,CAAC,MAAwB;IACjD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,MAAM;SACV,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;QACzE,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,OAAO,GAAG,QAAQ,KAAK,KAAK,CAAC,OAAO,GAAG,UAAU,EAAE,CAAC;IACtD,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Playwright Test Error Extractor
|
|
3
|
+
*
|
|
4
|
+
* Extracts error information from Playwright test output.
|
|
5
|
+
*
|
|
6
|
+
* Output format:
|
|
7
|
+
* ```
|
|
8
|
+
* Running N tests using M workers
|
|
9
|
+
*
|
|
10
|
+
* ✘ 1 test.spec.ts:10:5 › Describe › test name (100ms)
|
|
11
|
+
* ✓ 2 test.spec.ts:20:5 › passing test (50ms)
|
|
12
|
+
*
|
|
13
|
+
* 1) test.spec.ts:10:5 › Describe › test name
|
|
14
|
+
*
|
|
15
|
+
* Error: expect(received).toBe(expected)
|
|
16
|
+
*
|
|
17
|
+
* Expected: "foo"
|
|
18
|
+
* Received: "bar"
|
|
19
|
+
*
|
|
20
|
+
* 10 | test('test name', async () => {
|
|
21
|
+
* 11 | const value = 'bar';
|
|
22
|
+
* > 12 | expect(value).toBe('foo');
|
|
23
|
+
* | ^
|
|
24
|
+
* 13 | });
|
|
25
|
+
*
|
|
26
|
+
* at test.spec.ts:12:21
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import type { ErrorExtractorResult } from './types.js';
|
|
30
|
+
/**
|
|
31
|
+
* Extract errors from Playwright test output
|
|
32
|
+
*/
|
|
33
|
+
export declare function extractPlaywrightErrors(output: string): ErrorExtractorResult;
|
|
34
|
+
/**
|
|
35
|
+
* Check if output is from Playwright
|
|
36
|
+
*/
|
|
37
|
+
export declare function isPlaywrightOutput(output: string): boolean;
|
|
38
|
+
//# sourceMappingURL=playwright-extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-extractor.d.ts","sourceRoot":"","sources":["../src/playwright-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAkB,oBAAoB,EAAsB,MAAM,YAAY,CAAC;AAG3F;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CA8H5E;AAoGD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAW1D"}
|