@vibe-validate/extractors 0.17.0-rc2 → 0.17.0-rc4
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/dist/extractor-registry.d.ts +72 -0
- package/dist/extractor-registry.d.ts.map +1 -0
- package/dist/extractor-registry.js +243 -0
- package/dist/extractor-registry.js.map +1 -0
- package/dist/extractors/ava/index.d.ts +23 -0
- package/dist/extractors/ava/index.d.ts.map +1 -0
- package/dist/extractors/ava/index.js +507 -0
- package/dist/extractors/ava/index.js.map +1 -0
- package/dist/extractors/ava/index.test.d.ts +7 -0
- package/dist/extractors/ava/index.test.d.ts.map +1 -0
- package/dist/extractors/ava/index.test.js +408 -0
- package/dist/extractors/ava/index.test.js.map +1 -0
- package/dist/extractors/eslint/index.d.ts +18 -0
- package/dist/extractors/eslint/index.d.ts.map +1 -0
- package/dist/extractors/eslint/index.js +206 -0
- package/dist/extractors/eslint/index.js.map +1 -0
- package/dist/extractors/eslint/index.test.d.ts +9 -0
- package/dist/extractors/eslint/index.test.d.ts.map +1 -0
- package/dist/extractors/eslint/index.test.js +191 -0
- package/dist/extractors/eslint/index.test.js.map +1 -0
- package/dist/extractors/generic/index.d.ts +30 -0
- package/dist/extractors/generic/index.d.ts.map +1 -0
- package/dist/extractors/generic/index.js +140 -0
- package/dist/extractors/generic/index.js.map +1 -0
- package/dist/extractors/generic/index.test.d.ts +7 -0
- package/dist/extractors/generic/index.test.d.ts.map +1 -0
- package/dist/extractors/generic/index.test.js +61 -0
- package/dist/extractors/generic/index.test.js.map +1 -0
- package/dist/extractors/jasmine/index.d.ts +17 -0
- package/dist/extractors/jasmine/index.d.ts.map +1 -0
- package/dist/extractors/jasmine/index.js +242 -0
- package/dist/extractors/jasmine/index.js.map +1 -0
- package/dist/extractors/jasmine/index.test.d.ts +7 -0
- package/dist/extractors/jasmine/index.test.d.ts.map +1 -0
- package/dist/extractors/jasmine/index.test.js +318 -0
- package/dist/extractors/jasmine/index.test.js.map +1 -0
- package/dist/extractors/jest/index.d.ts +17 -0
- package/dist/extractors/jest/index.d.ts.map +1 -0
- package/dist/extractors/jest/index.js +273 -0
- package/dist/extractors/jest/index.js.map +1 -0
- package/dist/extractors/jest/index.test.d.ts +9 -0
- package/dist/extractors/jest/index.test.d.ts.map +1 -0
- package/dist/extractors/jest/index.test.js +338 -0
- package/dist/extractors/jest/index.test.js.map +1 -0
- package/dist/extractors/junit/index.d.ts +18 -0
- package/dist/extractors/junit/index.d.ts.map +1 -0
- package/dist/extractors/junit/index.js +259 -0
- package/dist/extractors/junit/index.js.map +1 -0
- package/dist/extractors/junit/index.test.d.ts +7 -0
- package/dist/extractors/junit/index.test.d.ts.map +1 -0
- package/dist/extractors/junit/index.test.js +341 -0
- package/dist/extractors/junit/index.test.js.map +1 -0
- package/dist/extractors/maven-checkstyle/index.d.ts +23 -0
- package/dist/extractors/maven-checkstyle/index.d.ts.map +1 -0
- package/dist/extractors/maven-checkstyle/index.js +263 -0
- package/dist/extractors/maven-checkstyle/index.js.map +1 -0
- package/dist/extractors/maven-checkstyle/index.test.d.ts +2 -0
- package/dist/extractors/maven-checkstyle/index.test.d.ts.map +1 -0
- package/dist/extractors/maven-checkstyle/index.test.js +197 -0
- package/dist/extractors/maven-checkstyle/index.test.js.map +1 -0
- package/dist/extractors/maven-compiler/index.d.ts +23 -0
- package/dist/extractors/maven-compiler/index.d.ts.map +1 -0
- package/dist/extractors/maven-compiler/index.js +271 -0
- package/dist/extractors/maven-compiler/index.js.map +1 -0
- package/dist/extractors/maven-compiler/index.test.d.ts +2 -0
- package/dist/extractors/maven-compiler/index.test.d.ts.map +1 -0
- package/dist/extractors/maven-compiler/index.test.js +189 -0
- package/dist/extractors/maven-compiler/index.test.js.map +1 -0
- package/dist/extractors/maven-surefire/index.d.ts +23 -0
- package/dist/extractors/maven-surefire/index.d.ts.map +1 -0
- package/dist/extractors/maven-surefire/index.js +292 -0
- package/dist/extractors/maven-surefire/index.js.map +1 -0
- package/dist/extractors/maven-surefire/index.test.d.ts +2 -0
- package/dist/extractors/maven-surefire/index.test.d.ts.map +1 -0
- package/dist/extractors/maven-surefire/index.test.js +163 -0
- package/dist/extractors/maven-surefire/index.test.js.map +1 -0
- package/dist/extractors/mocha/index.d.ts +17 -0
- package/dist/extractors/mocha/index.d.ts.map +1 -0
- package/dist/extractors/mocha/index.js +241 -0
- package/dist/extractors/mocha/index.js.map +1 -0
- package/dist/extractors/mocha/index.test.d.ts +7 -0
- package/dist/extractors/mocha/index.test.d.ts.map +1 -0
- package/dist/extractors/mocha/index.test.js +300 -0
- package/dist/extractors/mocha/index.test.js.map +1 -0
- package/dist/extractors/playwright/index.d.ts +17 -0
- package/dist/extractors/playwright/index.d.ts.map +1 -0
- package/dist/extractors/playwright/index.js +320 -0
- package/dist/extractors/playwright/index.js.map +1 -0
- package/dist/extractors/playwright/index.test.d.ts +7 -0
- package/dist/extractors/playwright/index.test.d.ts.map +1 -0
- package/dist/extractors/playwright/index.test.js +274 -0
- package/dist/extractors/playwright/index.test.js.map +1 -0
- package/dist/extractors/tap/index.d.ts +23 -0
- package/dist/extractors/tap/index.d.ts.map +1 -0
- package/dist/extractors/tap/index.js +352 -0
- package/dist/extractors/tap/index.js.map +1 -0
- package/dist/extractors/tap/index.test.d.ts +7 -0
- package/dist/extractors/tap/index.test.d.ts.map +1 -0
- package/dist/extractors/tap/index.test.js +100 -0
- package/dist/extractors/tap/index.test.js.map +1 -0
- package/dist/extractors/typescript/index.d.ts +17 -0
- package/dist/extractors/typescript/index.d.ts.map +1 -0
- package/dist/extractors/typescript/index.js +150 -0
- package/dist/extractors/typescript/index.js.map +1 -0
- package/dist/extractors/typescript/index.test.d.ts +9 -0
- package/dist/extractors/typescript/index.test.d.ts.map +1 -0
- package/dist/extractors/typescript/index.test.js +177 -0
- package/dist/extractors/typescript/index.test.js.map +1 -0
- package/dist/extractors/vitest/index.d.ts +17 -0
- package/dist/extractors/vitest/index.d.ts.map +1 -0
- package/dist/extractors/vitest/index.js +564 -0
- package/dist/extractors/vitest/index.js.map +1 -0
- package/dist/extractors/vitest/index.test.d.ts +9 -0
- package/dist/extractors/vitest/index.test.d.ts.map +1 -0
- package/dist/extractors/vitest/index.test.js +373 -0
- package/dist/extractors/vitest/index.test.js.map +1 -0
- package/dist/index.d.ts +27 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -13
- package/dist/index.js.map +1 -1
- package/dist/maven-checkstyle-extractor.d.ts.map +1 -1
- package/dist/maven-checkstyle-extractor.js +2 -17
- package/dist/maven-checkstyle-extractor.js.map +1 -1
- package/dist/maven-compiler-extractor.d.ts +20 -0
- package/dist/maven-compiler-extractor.d.ts.map +1 -0
- package/dist/maven-compiler-extractor.js +218 -0
- package/dist/maven-compiler-extractor.js.map +1 -0
- package/dist/maven-utils.d.ts +24 -0
- package/dist/maven-utils.d.ts.map +1 -0
- package/dist/maven-utils.js +36 -0
- package/dist/maven-utils.js.map +1 -0
- package/dist/plugin-loader.d.ts +82 -0
- package/dist/plugin-loader.d.ts.map +1 -0
- package/dist/plugin-loader.js +200 -0
- package/dist/plugin-loader.js.map +1 -0
- package/dist/sandbox.d.ts +161 -0
- package/dist/sandbox.d.ts.map +1 -0
- package/dist/sandbox.js +254 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/sandbox.test.d.ts +8 -0
- package/dist/sandbox.test.d.ts.map +1 -0
- package/dist/sandbox.test.js +395 -0
- package/dist/sandbox.test.js.map +1 -0
- package/dist/sandboxed-extractor.d.ts +51 -0
- package/dist/sandboxed-extractor.d.ts.map +1 -0
- package/dist/sandboxed-extractor.js +172 -0
- package/dist/sandboxed-extractor.js.map +1 -0
- package/dist/sandboxed-extractor.test.d.ts +5 -0
- package/dist/sandboxed-extractor.test.d.ts.map +1 -0
- package/dist/sandboxed-extractor.test.js +346 -0
- package/dist/sandboxed-extractor.test.js.map +1 -0
- package/dist/smart-extractor.d.ts +22 -10
- package/dist/smart-extractor.d.ts.map +1 -1
- package/dist/smart-extractor.js +116 -186
- package/dist/smart-extractor.js.map +1 -1
- package/dist/types.d.ts +94 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JUnit XML Error Extractor Plugin
|
|
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 type { ExtractorPlugin } from '../../types.js';
|
|
10
|
+
/**
|
|
11
|
+
* JUnit XML Error Extractor Plugin
|
|
12
|
+
*
|
|
13
|
+
* Extracts test failures from JUnit XML reports with high confidence (90%).
|
|
14
|
+
* Supports Vitest, Jest, and other test frameworks using JUnit XML output.
|
|
15
|
+
*/
|
|
16
|
+
declare const junitPlugin: ExtractorPlugin;
|
|
17
|
+
export default junitPlugin;
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extractors/junit/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,eAAe,EAKhB,MAAM,gBAAgB,CAAC;AA8QxB;;;;;GAKG;AACH,QAAA,MAAM,WAAW,EAAE,eAiBlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JUnit XML Error Extractor Plugin
|
|
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 { MAX_ERRORS_IN_ARRAY } from '../../result-schema.js';
|
|
10
|
+
/**
|
|
11
|
+
* Extract attribute value from XML tag
|
|
12
|
+
*/
|
|
13
|
+
function extractXmlAttribute(tag, attrName) {
|
|
14
|
+
const idx = tag.indexOf(`${attrName}="`);
|
|
15
|
+
if (idx === -1)
|
|
16
|
+
return undefined;
|
|
17
|
+
const start = idx + `${attrName}="`.length;
|
|
18
|
+
const end = tag.indexOf('"', start);
|
|
19
|
+
return tag.substring(start, end);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Extract failure information from JUnit XML
|
|
23
|
+
*/
|
|
24
|
+
function extractFailures(xml) {
|
|
25
|
+
const failures = [];
|
|
26
|
+
const testcasePattern = /<testcase[^>]*>([\s\S]*?)<\/testcase>/g;
|
|
27
|
+
let testcaseMatch;
|
|
28
|
+
while ((testcaseMatch = testcasePattern.exec(xml)) !== null) {
|
|
29
|
+
const testcaseContent = testcaseMatch[0];
|
|
30
|
+
const testcaseInner = testcaseMatch[1];
|
|
31
|
+
// Skip passing tests
|
|
32
|
+
if (!testcaseInner.includes('<failure')) {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
// Extract testcase tag attributes
|
|
36
|
+
const testcaseTagMatch = /<testcase([^>]*)>/.exec(testcaseContent);
|
|
37
|
+
const testcaseTag = testcaseTagMatch ? testcaseTagMatch[1] : '';
|
|
38
|
+
const file = extractXmlAttribute(testcaseTag, 'classname');
|
|
39
|
+
const testName = extractXmlAttribute(testcaseTag, 'name');
|
|
40
|
+
// Extract failure element
|
|
41
|
+
const failurePattern = /<failure[^>]*>([\s\S]*?)<\/failure>/;
|
|
42
|
+
const failureMatch = failurePattern.exec(testcaseInner);
|
|
43
|
+
if (!failureMatch) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const failureContent = failureMatch[0];
|
|
47
|
+
const failureText = failureMatch[1];
|
|
48
|
+
// Extract failure attributes
|
|
49
|
+
const message = extractXmlAttribute(failureContent, 'message');
|
|
50
|
+
const errorType = extractXmlAttribute(failureContent, 'type');
|
|
51
|
+
// Extract location from failure text (❯ file:line:column)
|
|
52
|
+
const locationPattern = /❯\s+([\w/.-]+):(\d+)(?::\d+)?/;
|
|
53
|
+
const locationMatch = locationPattern.exec(failureText);
|
|
54
|
+
let location;
|
|
55
|
+
let extractedFile;
|
|
56
|
+
if (locationMatch) {
|
|
57
|
+
extractedFile = locationMatch[1];
|
|
58
|
+
location = `${extractedFile}:${locationMatch[2]}`;
|
|
59
|
+
}
|
|
60
|
+
failures.push({
|
|
61
|
+
file: extractedFile ?? file,
|
|
62
|
+
location,
|
|
63
|
+
message,
|
|
64
|
+
testName,
|
|
65
|
+
errorType,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return failures;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Decode HTML entities in XML content
|
|
72
|
+
*/
|
|
73
|
+
function decodeHtmlEntities(text) {
|
|
74
|
+
return text
|
|
75
|
+
.replace(/>/g, '>')
|
|
76
|
+
.replace(/</g, '<')
|
|
77
|
+
.replace(/"/g, '"')
|
|
78
|
+
.replace(/'/g, "'")
|
|
79
|
+
.replace(/&/g, '&'); // Must be last to avoid double-decoding
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Generate JUnit-specific guidance based on error patterns
|
|
83
|
+
*/
|
|
84
|
+
function getJUnitGuidance(failures) {
|
|
85
|
+
const guidance = [];
|
|
86
|
+
const errorTypes = new Set(failures.map((f) => f.errorType));
|
|
87
|
+
const messages = failures.map((f) => f.message?.toLowerCase() ?? '');
|
|
88
|
+
// Check for assertion errors
|
|
89
|
+
if (errorTypes.has('AssertionError') || messages.some((m) => m.includes('expected'))) {
|
|
90
|
+
guidance.push('Review test assertions - expected values may not match actual results');
|
|
91
|
+
}
|
|
92
|
+
// Check for type errors
|
|
93
|
+
if (errorTypes.has('TypeError') || messages.some((m) => m.includes('cannot read properties'))) {
|
|
94
|
+
guidance.push('Check for null/undefined values before property access');
|
|
95
|
+
}
|
|
96
|
+
// Check for file system errors
|
|
97
|
+
if (messages.some((m) => m.includes('enoent') || m.includes('no such file'))) {
|
|
98
|
+
guidance.push('Verify file paths and ensure required files exist');
|
|
99
|
+
}
|
|
100
|
+
// Check for timeout errors
|
|
101
|
+
if (messages.some((m) => m.includes('timed out') || m.includes('timeout'))) {
|
|
102
|
+
guidance.push('Consider increasing test timeout or optimizing slow operations');
|
|
103
|
+
}
|
|
104
|
+
if (guidance.length === 0) {
|
|
105
|
+
return 'Review failing tests and fix assertion errors';
|
|
106
|
+
}
|
|
107
|
+
return guidance.join('. ');
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Extract JUnit XML errors from test output
|
|
111
|
+
*/
|
|
112
|
+
function extract(output) {
|
|
113
|
+
// Validate XML structure
|
|
114
|
+
if (!output.includes('<testsuite') && !output.includes('<testsuites')) {
|
|
115
|
+
return {
|
|
116
|
+
summary: 'Unable to parse JUnit XML - invalid format',
|
|
117
|
+
errors: [],
|
|
118
|
+
totalErrors: 0,
|
|
119
|
+
errorSummary: output.trim(),
|
|
120
|
+
guidance: 'Ensure the input is valid JUnit XML format',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// Extract all failure elements
|
|
124
|
+
const failures = extractFailures(output);
|
|
125
|
+
const errors = [];
|
|
126
|
+
for (const failure of failures) {
|
|
127
|
+
const file = failure.file ?? 'unknown';
|
|
128
|
+
const location = failure.location ?? `${file}:0`;
|
|
129
|
+
const message = failure.message ?? 'Test failed';
|
|
130
|
+
const context = failure.testName ?? '';
|
|
131
|
+
// Parse location to get line/column
|
|
132
|
+
let line;
|
|
133
|
+
if (location) {
|
|
134
|
+
const locationParts = location.split(':');
|
|
135
|
+
line = locationParts[1] ? Number.parseInt(locationParts[1], 10) : undefined;
|
|
136
|
+
}
|
|
137
|
+
errors.push({
|
|
138
|
+
file,
|
|
139
|
+
line,
|
|
140
|
+
message: decodeHtmlEntities(message),
|
|
141
|
+
context: decodeHtmlEntities(context),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
// Limit errors for token efficiency
|
|
145
|
+
const limitedErrors = errors.slice(0, MAX_ERRORS_IN_ARRAY);
|
|
146
|
+
// Generate summary
|
|
147
|
+
const failureCount = failures.length;
|
|
148
|
+
const summary = `${failureCount} test(s) failed`;
|
|
149
|
+
// Generate guidance based on error types
|
|
150
|
+
const guidance = getJUnitGuidance(failures);
|
|
151
|
+
// Build error summary
|
|
152
|
+
const errorSummary = limitedErrors
|
|
153
|
+
.map((e) => `${e.file}:${e.line ?? 0} - ${e.message}`)
|
|
154
|
+
.join('\n');
|
|
155
|
+
return {
|
|
156
|
+
summary,
|
|
157
|
+
errors: limitedErrors,
|
|
158
|
+
totalErrors: failures.length,
|
|
159
|
+
errorSummary,
|
|
160
|
+
guidance,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Detect if output is JUnit XML format
|
|
165
|
+
*/
|
|
166
|
+
function detect(output) {
|
|
167
|
+
// Check for JUnit XML structure
|
|
168
|
+
if (output.includes('<testsuite') || output.includes('<testsuites')) {
|
|
169
|
+
// Check for failure elements
|
|
170
|
+
if (output.includes('<failure')) {
|
|
171
|
+
return {
|
|
172
|
+
confidence: 90,
|
|
173
|
+
patterns: ['<testsuite>', '<failure>'],
|
|
174
|
+
reason: 'JUnit XML format with test failures detected',
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
confidence: 85,
|
|
179
|
+
patterns: ['<testsuite>'],
|
|
180
|
+
reason: 'JUnit XML format detected (no failures)',
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
return { confidence: 0, patterns: [], reason: '' };
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Sample test cases for JUnit extractor
|
|
187
|
+
*/
|
|
188
|
+
const samples = [
|
|
189
|
+
{
|
|
190
|
+
name: 'single-test-failure',
|
|
191
|
+
description: 'Single test failure with location',
|
|
192
|
+
input: `<?xml version="1.0" encoding="UTF-8" ?>
|
|
193
|
+
<testsuites name="vitest tests" tests="1" failures="1" errors="0" time="0.002">
|
|
194
|
+
<testsuite name="test/calculator.test.ts" tests="1" failures="1" errors="0" skipped="0" time="0.002">
|
|
195
|
+
<testcase classname="test/calculator.test.ts" name="Calculator > should add numbers" time="0.001">
|
|
196
|
+
<failure message="expected 4 to be 5 // Object.is equality" type="AssertionError">
|
|
197
|
+
AssertionError: expected 4 to be 5 // Object.is equality
|
|
198
|
+
❯ test/calculator.test.ts:10:21
|
|
199
|
+
</failure>
|
|
200
|
+
</testcase>
|
|
201
|
+
</testsuite>
|
|
202
|
+
</testsuites>`,
|
|
203
|
+
expected: {
|
|
204
|
+
totalErrors: 1,
|
|
205
|
+
summary: '1 test(s) failed',
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
name: 'multiple-test-failures',
|
|
210
|
+
description: 'Multiple test failures from different test cases',
|
|
211
|
+
input: `<?xml version="1.0" encoding="UTF-8" ?>
|
|
212
|
+
<testsuites name="vitest tests" tests="3" failures="2" errors="0" time="0.006">
|
|
213
|
+
<testsuite name="test/math.test.ts" tests="3" failures="2" errors="0" skipped="0" time="0.006">
|
|
214
|
+
<testcase classname="test/math.test.ts" name="Math > should multiply" time="0.002">
|
|
215
|
+
<failure message="expected 6 to be 8 // Object.is equality" type="AssertionError">
|
|
216
|
+
AssertionError: expected 6 to be 8 // Object.is equality
|
|
217
|
+
❯ test/math.test.ts:15:20
|
|
218
|
+
</failure>
|
|
219
|
+
</testcase>
|
|
220
|
+
<testcase classname="test/math.test.ts" name="Math > should subtract" time="0.003">
|
|
221
|
+
<failure message="expected -1 to be 0 // Object.is equality" type="AssertionError">
|
|
222
|
+
AssertionError: expected -1 to be 0 // Object.is equality
|
|
223
|
+
❯ test/math.test.ts:25:22
|
|
224
|
+
</failure>
|
|
225
|
+
</testcase>
|
|
226
|
+
</testsuite>
|
|
227
|
+
</testsuites>`,
|
|
228
|
+
expected: {
|
|
229
|
+
totalErrors: 2,
|
|
230
|
+
summary: '2 test(s) failed',
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
/**
|
|
235
|
+
* JUnit XML Error Extractor Plugin
|
|
236
|
+
*
|
|
237
|
+
* Extracts test failures from JUnit XML reports with high confidence (90%).
|
|
238
|
+
* Supports Vitest, Jest, and other test frameworks using JUnit XML output.
|
|
239
|
+
*/
|
|
240
|
+
const junitPlugin = {
|
|
241
|
+
metadata: {
|
|
242
|
+
name: 'junit',
|
|
243
|
+
version: '1.0.0',
|
|
244
|
+
author: 'vibe-validate',
|
|
245
|
+
description: 'Extracts test failures from JUnit XML reports',
|
|
246
|
+
repository: 'https://github.com/jdutton/vibe-validate',
|
|
247
|
+
tags: ['junit', 'xml', 'testing', 'vitest', 'jest'],
|
|
248
|
+
},
|
|
249
|
+
hints: {
|
|
250
|
+
required: ['<testsuite'],
|
|
251
|
+
anyOf: [],
|
|
252
|
+
},
|
|
253
|
+
priority: 90,
|
|
254
|
+
detect,
|
|
255
|
+
extract,
|
|
256
|
+
samples,
|
|
257
|
+
};
|
|
258
|
+
export default junitPlugin;
|
|
259
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extractors/junit/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../src/extractors/junit/index.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JUnit XML Error Extractor Plugin Tests
|
|
3
|
+
*
|
|
4
|
+
* @package @vibe-validate/extractors
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from 'vitest';
|
|
7
|
+
import junitPlugin from './index.js';
|
|
8
|
+
const { detect, extract } = junitPlugin;
|
|
9
|
+
describe('JUnit Plugin', () => {
|
|
10
|
+
describe('Detection', () => {
|
|
11
|
+
it('should detect JUnit XML with failures (high confidence)', () => {
|
|
12
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
13
|
+
<testsuites>
|
|
14
|
+
<testsuite name="test.ts">
|
|
15
|
+
<testcase name="test">
|
|
16
|
+
<failure message="error" type="Error">
|
|
17
|
+
❯ test.ts:10:20
|
|
18
|
+
</failure>
|
|
19
|
+
</testcase>
|
|
20
|
+
</testsuite>
|
|
21
|
+
</testsuites>`;
|
|
22
|
+
const result = detect(input);
|
|
23
|
+
expect(result.confidence).toBe(90);
|
|
24
|
+
expect(result.patterns).toContain('<testsuite>');
|
|
25
|
+
expect(result.patterns).toContain('<failure>');
|
|
26
|
+
expect(result.reason).toContain('JUnit XML format with test failures detected');
|
|
27
|
+
});
|
|
28
|
+
it('should detect JUnit XML without failures (lower confidence)', () => {
|
|
29
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
30
|
+
<testsuites tests="5" failures="0">
|
|
31
|
+
<testsuite name="test.ts" tests="5" failures="0">
|
|
32
|
+
<testcase name="test 1" time="0.001"></testcase>
|
|
33
|
+
</testsuite>
|
|
34
|
+
</testsuites>`;
|
|
35
|
+
const result = detect(input);
|
|
36
|
+
expect(result.confidence).toBe(85);
|
|
37
|
+
expect(result.patterns).toContain('<testsuite>');
|
|
38
|
+
});
|
|
39
|
+
it('should not detect non-JUnit output', () => {
|
|
40
|
+
const input = 'Regular test output without XML';
|
|
41
|
+
const result = detect(input);
|
|
42
|
+
expect(result.confidence).toBe(0);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
describe('Basic Extraction', () => {
|
|
46
|
+
it('should extract single test failure from JUnit XML', () => {
|
|
47
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
48
|
+
<testsuites name="vitest tests" tests="1" failures="1" errors="0" time="0.002">
|
|
49
|
+
<testsuite name="test/calculator.test.ts" tests="1" failures="1" errors="0" skipped="0" time="0.002">
|
|
50
|
+
<testcase classname="test/calculator.test.ts" name="Calculator > should add numbers" time="0.001">
|
|
51
|
+
<failure message="expected 4 to be 5 // Object.is equality" type="AssertionError">
|
|
52
|
+
AssertionError: expected 4 to be 5 // Object.is equality
|
|
53
|
+
|
|
54
|
+
- Expected
|
|
55
|
+
+ Received
|
|
56
|
+
|
|
57
|
+
- 5
|
|
58
|
+
+ 4
|
|
59
|
+
|
|
60
|
+
❯ test/calculator.test.ts:10:21
|
|
61
|
+
</failure>
|
|
62
|
+
</testcase>
|
|
63
|
+
</testsuite>
|
|
64
|
+
</testsuites>`;
|
|
65
|
+
const result = extract(input);
|
|
66
|
+
expect(result.summary).toBe('1 test(s) failed');
|
|
67
|
+
expect(result.errors).toHaveLength(1);
|
|
68
|
+
expect(result.errors[0]).toMatchObject({
|
|
69
|
+
file: 'test/calculator.test.ts',
|
|
70
|
+
line: 10,
|
|
71
|
+
message: 'expected 4 to be 5 // Object.is equality',
|
|
72
|
+
});
|
|
73
|
+
// Context should contain test hierarchy
|
|
74
|
+
expect(result.errors[0].context).toBeTruthy();
|
|
75
|
+
});
|
|
76
|
+
it('should extract multiple test failures', () => {
|
|
77
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
78
|
+
<testsuites name="vitest tests" tests="3" failures="2" errors="0" time="0.006">
|
|
79
|
+
<testsuite name="test/math.test.ts" tests="3" failures="2" errors="0" skipped="0" time="0.006">
|
|
80
|
+
<testcase classname="test/math.test.ts" name="Math > should multiply" time="0.002">
|
|
81
|
+
<failure message="expected 6 to be 8 // Object.is equality" type="AssertionError">
|
|
82
|
+
AssertionError: expected 6 to be 8 // Object.is equality
|
|
83
|
+
❯ test/math.test.ts:15:20
|
|
84
|
+
</failure>
|
|
85
|
+
</testcase>
|
|
86
|
+
<testcase classname="test/math.test.ts" name="Math > should divide" time="0.001">
|
|
87
|
+
</testcase>
|
|
88
|
+
<testcase classname="test/math.test.ts" name="Math > should subtract" time="0.003">
|
|
89
|
+
<failure message="expected -1 to be 0 // Object.is equality" type="AssertionError">
|
|
90
|
+
AssertionError: expected -1 to be 0 // Object.is equality
|
|
91
|
+
❯ test/math.test.ts:25:22
|
|
92
|
+
</failure>
|
|
93
|
+
</testcase>
|
|
94
|
+
</testsuite>
|
|
95
|
+
</testsuites>`;
|
|
96
|
+
const result = extract(input);
|
|
97
|
+
expect(result.summary).toBe('2 test(s) failed');
|
|
98
|
+
expect(result.errors).toHaveLength(2);
|
|
99
|
+
expect(result.errors[0].file).toBe('test/math.test.ts');
|
|
100
|
+
expect(result.errors[1].file).toBe('test/math.test.ts');
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('Error Type Detection', () => {
|
|
104
|
+
it('should detect AssertionError', () => {
|
|
105
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
106
|
+
<testsuites>
|
|
107
|
+
<testsuite name="test.ts">
|
|
108
|
+
<testcase name="test">
|
|
109
|
+
<failure message="assertion failed" type="AssertionError">
|
|
110
|
+
❯ test.ts:10:20
|
|
111
|
+
</failure>
|
|
112
|
+
</testcase>
|
|
113
|
+
</testsuite>
|
|
114
|
+
</testsuites>`;
|
|
115
|
+
const result = extract(input);
|
|
116
|
+
expect(result.errors[0].message).toContain('assertion failed');
|
|
117
|
+
expect(result.guidance).toContain('assertion');
|
|
118
|
+
});
|
|
119
|
+
it('should detect TypeError', () => {
|
|
120
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
121
|
+
<testsuites>
|
|
122
|
+
<testsuite name="test.ts">
|
|
123
|
+
<testcase name="test">
|
|
124
|
+
<failure message="Cannot read properties of null" type="TypeError">
|
|
125
|
+
TypeError: Cannot read properties of null (reading 'foo')
|
|
126
|
+
❯ test.ts:38:18
|
|
127
|
+
</failure>
|
|
128
|
+
</testcase>
|
|
129
|
+
</testsuite>
|
|
130
|
+
</testsuites>`;
|
|
131
|
+
const result = extract(input);
|
|
132
|
+
expect(result.errors[0].message).toContain('Cannot read properties of null');
|
|
133
|
+
expect(result.guidance).toContain('null/undefined');
|
|
134
|
+
});
|
|
135
|
+
it('should detect ENOENT errors', () => {
|
|
136
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
137
|
+
<testsuites>
|
|
138
|
+
<testsuite name="test.ts">
|
|
139
|
+
<testcase name="test">
|
|
140
|
+
<failure message="ENOENT: no such file or directory" type="Error">
|
|
141
|
+
Error: ENOENT: no such file or directory, open '/nonexistent/file.txt'
|
|
142
|
+
❯ test.ts:30:7
|
|
143
|
+
</failure>
|
|
144
|
+
</testcase>
|
|
145
|
+
</testsuite>
|
|
146
|
+
</testsuites>`;
|
|
147
|
+
const result = extract(input);
|
|
148
|
+
expect(result.errors[0].message).toContain('ENOENT');
|
|
149
|
+
expect(result.guidance).toContain('file paths');
|
|
150
|
+
});
|
|
151
|
+
it('should detect timeout errors', () => {
|
|
152
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
153
|
+
<testsuites>
|
|
154
|
+
<testsuite name="test.ts">
|
|
155
|
+
<testcase name="test">
|
|
156
|
+
<failure message="Test timed out in 100ms." type="Error">
|
|
157
|
+
Error: Test timed out in 100ms.
|
|
158
|
+
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
|
|
159
|
+
❯ test.ts:43:5
|
|
160
|
+
</failure>
|
|
161
|
+
</testcase>
|
|
162
|
+
</testsuite>
|
|
163
|
+
</testsuites>`;
|
|
164
|
+
const result = extract(input);
|
|
165
|
+
expect(result.errors[0].message).toContain('Test timed out');
|
|
166
|
+
expect(result.guidance).toContain('timeout');
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe('Location Extraction', () => {
|
|
170
|
+
it('should extract file:line format', () => {
|
|
171
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
172
|
+
<testsuites>
|
|
173
|
+
<testsuite name="src/utils.test.ts">
|
|
174
|
+
<testcase classname="src/utils.test.ts" name="test">
|
|
175
|
+
<failure message="error" type="Error">
|
|
176
|
+
❯ src/utils.test.ts:42:15
|
|
177
|
+
</failure>
|
|
178
|
+
</testcase>
|
|
179
|
+
</testsuite>
|
|
180
|
+
</testsuites>`;
|
|
181
|
+
const result = extract(input);
|
|
182
|
+
expect(result.errors[0].file).toBe('src/utils.test.ts');
|
|
183
|
+
expect(result.errors[0].line).toBe(42);
|
|
184
|
+
});
|
|
185
|
+
it('should handle file:line:column format', () => {
|
|
186
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
187
|
+
<testsuites>
|
|
188
|
+
<testsuite name="test.ts">
|
|
189
|
+
<testcase classname="test.ts" name="test">
|
|
190
|
+
<failure message="error" type="Error">
|
|
191
|
+
❯ packages/core/test/runner.test.ts:128:30
|
|
192
|
+
</failure>
|
|
193
|
+
</testcase>
|
|
194
|
+
</testsuite>
|
|
195
|
+
</testsuites>`;
|
|
196
|
+
const result = extract(input);
|
|
197
|
+
expect(result.errors[0].file).toBe('packages/core/test/runner.test.ts');
|
|
198
|
+
expect(result.errors[0].line).toBe(128);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe('Test Hierarchy', () => {
|
|
202
|
+
it('should preserve test hierarchy in context', () => {
|
|
203
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
204
|
+
<testsuites>
|
|
205
|
+
<testsuite name="test.ts">
|
|
206
|
+
<testcase name="Suite > Nested > Deep > test name">
|
|
207
|
+
<failure message="error" type="Error">
|
|
208
|
+
❯ test.ts:10:20
|
|
209
|
+
</failure>
|
|
210
|
+
</testcase>
|
|
211
|
+
</testsuite>
|
|
212
|
+
</testsuites>`;
|
|
213
|
+
const result = extract(input);
|
|
214
|
+
expect(result.errors[0].context).toContain('Suite > Nested > Deep > test name');
|
|
215
|
+
});
|
|
216
|
+
it('should decode HTML entities in test names', () => {
|
|
217
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
218
|
+
<testsuites>
|
|
219
|
+
<testsuite name="test.ts">
|
|
220
|
+
<testcase name="Test with "quotes" & symbols > nested">
|
|
221
|
+
<failure message="error" type="Error">
|
|
222
|
+
❯ test.ts:10:20
|
|
223
|
+
</failure>
|
|
224
|
+
</testcase>
|
|
225
|
+
</testsuite>
|
|
226
|
+
</testsuites>`;
|
|
227
|
+
const result = extract(input);
|
|
228
|
+
expect(result.errors[0].context).toContain('"quotes"');
|
|
229
|
+
expect(result.errors[0].context).toContain('& symbols >');
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
describe('Edge Cases', () => {
|
|
233
|
+
it('should handle empty JUnit XML', () => {
|
|
234
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
235
|
+
<testsuites></testsuites>`;
|
|
236
|
+
const result = extract(input);
|
|
237
|
+
expect(result.summary).toBe('0 test(s) failed');
|
|
238
|
+
expect(result.errors).toHaveLength(0);
|
|
239
|
+
});
|
|
240
|
+
it('should handle all passing tests', () => {
|
|
241
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
242
|
+
<testsuites tests="5" failures="0">
|
|
243
|
+
<testsuite name="test.ts" tests="5" failures="0">
|
|
244
|
+
<testcase name="test 1" time="0.001"></testcase>
|
|
245
|
+
<testcase name="test 2" time="0.001"></testcase>
|
|
246
|
+
</testsuite>
|
|
247
|
+
</testsuites>`;
|
|
248
|
+
const result = extract(input);
|
|
249
|
+
expect(result.summary).toBe('0 test(s) failed');
|
|
250
|
+
expect(result.errors).toHaveLength(0);
|
|
251
|
+
});
|
|
252
|
+
it('should handle invalid XML gracefully', () => {
|
|
253
|
+
const input = 'Not valid XML';
|
|
254
|
+
const result = extract(input);
|
|
255
|
+
expect(result.summary).toContain('Unable to parse JUnit XML');
|
|
256
|
+
expect(result.errors).toHaveLength(0);
|
|
257
|
+
});
|
|
258
|
+
it('should handle missing location in failure', () => {
|
|
259
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
260
|
+
<testsuites>
|
|
261
|
+
<testsuite name="test.ts">
|
|
262
|
+
<testcase classname="test.ts" name="test">
|
|
263
|
+
<failure message="error without location" type="Error">
|
|
264
|
+
Error: Something went wrong
|
|
265
|
+
</failure>
|
|
266
|
+
</testcase>
|
|
267
|
+
</testsuite>
|
|
268
|
+
</testsuites>`;
|
|
269
|
+
const result = extract(input);
|
|
270
|
+
expect(result.errors[0].file).toBe('test.ts');
|
|
271
|
+
expect(result.errors[0].message).toContain('error without location');
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
describe('Guidance Generation', () => {
|
|
275
|
+
it('should provide assertion error guidance', () => {
|
|
276
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
277
|
+
<testsuites>
|
|
278
|
+
<testsuite name="test.ts">
|
|
279
|
+
<testcase name="test">
|
|
280
|
+
<failure message="expected 4 to be 5" type="AssertionError">
|
|
281
|
+
❯ test.ts:10:20
|
|
282
|
+
</failure>
|
|
283
|
+
</testcase>
|
|
284
|
+
</testsuite>
|
|
285
|
+
</testsuites>`;
|
|
286
|
+
const result = extract(input);
|
|
287
|
+
expect(result.guidance).toContain('assertion');
|
|
288
|
+
});
|
|
289
|
+
it('should provide timeout guidance', () => {
|
|
290
|
+
const input = `<?xml version="1.0" encoding="UTF-8" ?>
|
|
291
|
+
<testsuites>
|
|
292
|
+
<testsuite name="test.ts">
|
|
293
|
+
<testcase name="test">
|
|
294
|
+
<failure message="Test timed out" type="Error">
|
|
295
|
+
❯ test.ts:10:20
|
|
296
|
+
</failure>
|
|
297
|
+
</testcase>
|
|
298
|
+
</testsuite>
|
|
299
|
+
</testsuites>`;
|
|
300
|
+
const result = extract(input);
|
|
301
|
+
expect(result.guidance).toContain('timeout');
|
|
302
|
+
});
|
|
303
|
+
});
|
|
304
|
+
describe('Sample Test Cases', () => {
|
|
305
|
+
it('should include samples that validate the plugin', () => {
|
|
306
|
+
expect(junitPlugin.samples).toBeDefined();
|
|
307
|
+
expect(junitPlugin.samples).toHaveLength(2);
|
|
308
|
+
// Validate single failure sample
|
|
309
|
+
const singleFailureSample = junitPlugin.samples[0];
|
|
310
|
+
if (!singleFailureSample.input) {
|
|
311
|
+
throw new Error('Sample input is required');
|
|
312
|
+
}
|
|
313
|
+
const singleResult = extract(singleFailureSample.input);
|
|
314
|
+
expect(singleResult.totalErrors).toBe(singleFailureSample.expected.totalErrors);
|
|
315
|
+
// Validate multiple failures sample
|
|
316
|
+
const multipleFailureSample = junitPlugin.samples[1];
|
|
317
|
+
if (!multipleFailureSample.input) {
|
|
318
|
+
throw new Error('Sample input is required');
|
|
319
|
+
}
|
|
320
|
+
const multipleResult = extract(multipleFailureSample.input);
|
|
321
|
+
expect(multipleResult.totalErrors).toBe(multipleFailureSample.expected.totalErrors);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
describe('Plugin Metadata', () => {
|
|
325
|
+
it('should have correct metadata', () => {
|
|
326
|
+
expect(junitPlugin.metadata.name).toBe('junit');
|
|
327
|
+
expect(junitPlugin.metadata.version).toBe('1.0.0');
|
|
328
|
+
expect(junitPlugin.metadata.tags).toBeDefined();
|
|
329
|
+
expect(junitPlugin.metadata.tags).toContain('junit');
|
|
330
|
+
expect(junitPlugin.metadata.tags).toContain('vitest');
|
|
331
|
+
});
|
|
332
|
+
it('should have correct priority', () => {
|
|
333
|
+
expect(junitPlugin.priority).toBe(90);
|
|
334
|
+
});
|
|
335
|
+
it('should have correct hints', () => {
|
|
336
|
+
expect(junitPlugin.hints).toBeDefined();
|
|
337
|
+
expect(junitPlugin.hints?.required).toContain('<testsuite');
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
//# sourceMappingURL=index.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../src/extractors/junit/index.test.ts"],"names":[],"mappings":"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"}
|