@testomatio/reporter 2.3.8 → 2.3.9-beta-bin-fix
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 +1 -2
- package/lib/bin/cli.js +4 -14
- package/lib/bin/reportXml.js +2 -5
- package/lib/client.d.ts +1 -1
- package/lib/client.js +22 -31
- package/lib/junit-adapter/csharp.d.ts +1 -0
- package/lib/junit-adapter/csharp.js +7 -40
- package/lib/pipe/testomatio.d.ts +1 -2
- package/lib/pipe/testomatio.js +1 -2
- package/lib/reporter.d.ts +9 -19
- package/lib/reporter.js +5 -40
- package/lib/uploader.js +0 -4
- package/lib/utils/utils.js +24 -189
- package/lib/xmlReader.d.ts +26 -32
- package/lib/xmlReader.js +52 -111
- package/package.json +5 -9
- package/src/bin/cli.js +4 -16
- package/src/bin/reportXml.js +2 -5
- package/src/client.js +28 -56
- package/src/junit-adapter/csharp.js +6 -45
- package/src/pipe/testomatio.js +1 -2
- package/src/reporter.js +4 -7
- package/src/uploader.js +0 -5
- package/src/utils/utils.js +22 -202
- package/src/xmlReader.js +46 -134
- package/lib/junit-adapter/nunit-parser.d.ts +0 -82
- package/lib/junit-adapter/nunit-parser.js +0 -431
- package/src/junit-adapter/nunit-parser.js +0 -472
- package/types/types.d.ts +0 -364
- package/types/vitest.types.d.ts +0 -93
package/src/xmlReader.js
CHANGED
|
@@ -6,7 +6,6 @@ import { XMLParser } from 'fast-xml-parser';
|
|
|
6
6
|
import { APP_PREFIX, STATUS } from './constants.js';
|
|
7
7
|
import { randomUUID } from 'crypto';
|
|
8
8
|
import { fileURLToPath } from 'url';
|
|
9
|
-
import { NUnitXmlParser } from './junit-adapter/nunit-parser.js';
|
|
10
9
|
import {
|
|
11
10
|
fetchFilesFromStackTrace,
|
|
12
11
|
fetchIdFromOutput,
|
|
@@ -15,7 +14,6 @@ import {
|
|
|
15
14
|
fetchIdFromCode,
|
|
16
15
|
humanize,
|
|
17
16
|
TEST_ID_REGEX,
|
|
18
|
-
transformEnvVarToBoolean,
|
|
19
17
|
} from './utils/utils.js';
|
|
20
18
|
import { pipesFactory } from './pipe/index.js';
|
|
21
19
|
import adapterFactory from './junit-adapter/index.js';
|
|
@@ -37,7 +35,6 @@ const {
|
|
|
37
35
|
TESTOMATIO_ENV,
|
|
38
36
|
TESTOMATIO_RUN,
|
|
39
37
|
TESTOMATIO_MARK_DETACHED,
|
|
40
|
-
TESTOMATIO_LEGACY_NUNIT,
|
|
41
38
|
} = process.env;
|
|
42
39
|
|
|
43
40
|
const options = {
|
|
@@ -78,11 +75,6 @@ class XmlReader {
|
|
|
78
75
|
this.stats.language = opts.lang?.toLowerCase();
|
|
79
76
|
this.uploader = new S3Uploader();
|
|
80
77
|
|
|
81
|
-
// Enhanced NUnit parsing - enabled by default for NUnit XML
|
|
82
|
-
// Can be disabled via opts.enhancedNunit = false or TESTOMATIO_LEGACY_NUNIT=1
|
|
83
|
-
this.enhancedNunit = !transformEnvVarToBoolean(TESTOMATIO_LEGACY_NUNIT);
|
|
84
|
-
this.groupParameterized = opts.groupParameterized !== false; // Default true, can be disabled
|
|
85
|
-
|
|
86
78
|
// @ts-ignore
|
|
87
79
|
const packageJsonPath = path.resolve(__dirname, '..', 'package.json');
|
|
88
80
|
this.version = JSON.parse(fs.readFileSync(packageJsonPath).toString()).version;
|
|
@@ -134,8 +126,7 @@ class XmlReader {
|
|
|
134
126
|
}
|
|
135
127
|
|
|
136
128
|
processJUnit(jsonSuite) {
|
|
137
|
-
const { testsuite, name, failures, errors } = jsonSuite;
|
|
138
|
-
const tests = testsuite?.tests || jsonSuite.tests;
|
|
129
|
+
const { testsuite, name, tests, failures, errors } = jsonSuite;
|
|
139
130
|
|
|
140
131
|
reduceOptions.preferClassname = this.stats.language === 'python';
|
|
141
132
|
const resultTests = processTestSuite(testsuite);
|
|
@@ -166,14 +157,6 @@ class XmlReader {
|
|
|
166
157
|
}
|
|
167
158
|
|
|
168
159
|
processNUnit(jsonSuite) {
|
|
169
|
-
// Use enhanced NUnit parser if enabled and this is actually NUnit XML
|
|
170
|
-
if (this.enhancedNunit && this.isNUnitXml(jsonSuite)) {
|
|
171
|
-
debug('Using enhanced NUnit parser');
|
|
172
|
-
return this.processNUnitEnhanced(jsonSuite);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Fallback to legacy parser for backward compatibility
|
|
176
|
-
debug('Using legacy NUnit parser');
|
|
177
160
|
const { result, total, passed, failed, inconclusive, skipped } = jsonSuite;
|
|
178
161
|
|
|
179
162
|
reduceOptions.preferClassname = this.stats.language === 'python';
|
|
@@ -192,71 +175,63 @@ class XmlReader {
|
|
|
192
175
|
};
|
|
193
176
|
}
|
|
194
177
|
|
|
195
|
-
/**
|
|
196
|
-
* Check if the XML is actually NUnit format (has test-suite hierarchy)
|
|
197
|
-
* @param {Object} jsonSuite - Parsed XML suite object
|
|
198
|
-
* @returns {boolean} - True if this is NUnit XML format
|
|
199
|
-
*/
|
|
200
|
-
isNUnitXml(jsonSuite) {
|
|
201
|
-
// NUnit XML has test-suite elements with type attributes
|
|
202
|
-
if (jsonSuite['test-suite']) {
|
|
203
|
-
const testSuite = Array.isArray(jsonSuite['test-suite']) ? jsonSuite['test-suite'][0] : jsonSuite['test-suite'];
|
|
204
|
-
|
|
205
|
-
// Check for NUnit-specific test-suite types
|
|
206
|
-
return (
|
|
207
|
-
testSuite &&
|
|
208
|
-
testSuite.type &&
|
|
209
|
-
['Assembly', 'TestSuite', 'TestFixture', 'ParameterizedMethod'].includes(testSuite.type)
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
processNUnitEnhanced(jsonSuite) {
|
|
216
|
-
debug('Processing NUnit XML with enhanced parser');
|
|
217
|
-
|
|
218
|
-
try {
|
|
219
|
-
const nunitParser = new NUnitXmlParser({
|
|
220
|
-
groupParameterized: this.groupParameterized,
|
|
221
|
-
...this.opts,
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
const result = nunitParser.parseTestRun(jsonSuite);
|
|
225
|
-
|
|
226
|
-
// Add parsed tests to our collection
|
|
227
|
-
this.tests = this.tests.concat(result.tests);
|
|
228
|
-
|
|
229
|
-
debug(`Enhanced NUnit parser processed ${result.tests.length} tests`);
|
|
230
|
-
|
|
231
|
-
return result;
|
|
232
|
-
} catch (error) {
|
|
233
|
-
debug('Enhanced NUnit parser failed, falling back to legacy parser:', error.message);
|
|
234
|
-
console.warn(`${APP_PREFIX} Enhanced NUnit parsing failed, using legacy parser: ${error.message}`);
|
|
235
|
-
|
|
236
|
-
// Fallback to legacy parser
|
|
237
|
-
this.enhancedNunit = false;
|
|
238
|
-
return this.processNUnit(jsonSuite);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
178
|
processTRX(jsonSuite) {
|
|
243
179
|
let defs = jsonSuite?.TestRun?.TestDefinitions?.UnitTest;
|
|
244
180
|
if (!Array.isArray(defs)) defs = [defs].filter(d => !!d);
|
|
245
181
|
|
|
246
|
-
|
|
247
|
-
|
|
182
|
+
const tests =
|
|
183
|
+
defs.map(td => {
|
|
184
|
+
const title = td.name.replace(/\(.*?\)/, '').trim();
|
|
185
|
+
let example = td.name.match(/\((.*?)\)/);
|
|
186
|
+
if (example) example = { ...example[1].split(',') };
|
|
187
|
+
const suite = td.TestMethod.className.split(', ')[0].split('.');
|
|
188
|
+
const suite_title = suite.pop();
|
|
189
|
+
return {
|
|
190
|
+
title,
|
|
191
|
+
example,
|
|
192
|
+
file: suite.join('/'),
|
|
193
|
+
description: td.Description,
|
|
194
|
+
suite_title,
|
|
195
|
+
id: td.Execution.id,
|
|
196
|
+
};
|
|
197
|
+
}) || [];
|
|
248
198
|
|
|
249
|
-
// Parse test results
|
|
250
199
|
let result = jsonSuite?.TestRun?.Results?.UnitTestResult;
|
|
251
200
|
if (!Array.isArray(result)) result = [result].filter(d => !!d);
|
|
252
201
|
|
|
253
|
-
const results = result.map(td =>
|
|
202
|
+
const results = result.map(td => ({
|
|
203
|
+
id: td.executionId,
|
|
204
|
+
// seconds are used in junit reports, but ms are used by testomatio
|
|
205
|
+
run_time: parseFloat(td.duration) * 1000,
|
|
206
|
+
status: td.outcome,
|
|
207
|
+
stack: td.Output.StdOut,
|
|
208
|
+
files: td?.ResultFiles?.ResultFile?.map(rf => rf.path),
|
|
209
|
+
}));
|
|
210
|
+
|
|
211
|
+
results.forEach(r => {
|
|
212
|
+
const test = tests.find(t => t.id === r.id) || {};
|
|
213
|
+
r.suite_title = test.suite_title;
|
|
214
|
+
r.title = test.title?.trim();
|
|
215
|
+
if (test.code) r.code = test.code;
|
|
216
|
+
if (test.description) r.description = test.description;
|
|
217
|
+
if (test.example) r.example = test.example;
|
|
218
|
+
if (test.file) r.file = test.file;
|
|
219
|
+
r.create = true;
|
|
220
|
+
r.overwrite = true;
|
|
221
|
+
if (r.status === 'Passed') r.status = STATUS.PASSED;
|
|
222
|
+
if (r.status === 'Failed') r.status = STATUS.FAILED;
|
|
223
|
+
if (r.status === 'Skipped') r.status = STATUS.SKIPPED;
|
|
224
|
+
delete r.id;
|
|
225
|
+
});
|
|
254
226
|
|
|
255
227
|
debug(results);
|
|
256
228
|
|
|
257
229
|
const counters = jsonSuite?.TestRun?.ResultSummary?.Counters || {};
|
|
230
|
+
|
|
258
231
|
const failed_count = parseInt(counters.failed, 10) + parseInt(counters.error, 10);
|
|
259
|
-
|
|
232
|
+
|
|
233
|
+
let status = STATUS.PASSED.toString();
|
|
234
|
+
if (failed_count > 0) status = STATUS.FAILED;
|
|
260
235
|
|
|
261
236
|
this.tests = results.filter(t => !!t.title);
|
|
262
237
|
|
|
@@ -271,69 +246,6 @@ class XmlReader {
|
|
|
271
246
|
};
|
|
272
247
|
}
|
|
273
248
|
|
|
274
|
-
_parseTRXTestDefinition(td) {
|
|
275
|
-
const title = td.name.replace(/\(.*?\)/, '').trim();
|
|
276
|
-
const exampleMatch = td.name.match(/\((.*?)\)/);
|
|
277
|
-
const example = exampleMatch ? {
|
|
278
|
-
...exampleMatch[1].split(',').map(p => p.trim()).filter(p => p !== '')
|
|
279
|
-
} : null;
|
|
280
|
-
|
|
281
|
-
const suite = td.TestMethod.className.split(', ')[0].split('.');
|
|
282
|
-
const suite_title = suite.pop();
|
|
283
|
-
|
|
284
|
-
// Convert namespace to file path for C#
|
|
285
|
-
const file = `${suite.join('/')}.cs`;
|
|
286
|
-
|
|
287
|
-
return {
|
|
288
|
-
title, // Base name without parameters for test import
|
|
289
|
-
example, // Parameters object for parameterized tests
|
|
290
|
-
file, // File path with .cs extension
|
|
291
|
-
description: td.Description,
|
|
292
|
-
suite_title,
|
|
293
|
-
id: td.Execution.id,
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
_parseTRXTestResult(td, tests) {
|
|
298
|
-
const test = tests.find(t => t.id === td.executionId) || {};
|
|
299
|
-
|
|
300
|
-
const result = {
|
|
301
|
-
suite_title: test.suite_title,
|
|
302
|
-
title: test.title?.trim(),
|
|
303
|
-
file: test.file,
|
|
304
|
-
description: test.description,
|
|
305
|
-
code: test.code,
|
|
306
|
-
run_time: parseFloat(td.duration) * 1000,
|
|
307
|
-
stack: td.Output?.StdOut || '',
|
|
308
|
-
files: td?.ResultFiles?.ResultFile?.map(rf => rf.path),
|
|
309
|
-
create: true,
|
|
310
|
-
overwrite: true,
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
// Add example for parameterized tests
|
|
314
|
-
if (test.example) {
|
|
315
|
-
result.example = test.example;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Map TRX status to Testomat.io status
|
|
319
|
-
result.status = this._mapTRXStatus(td.outcome);
|
|
320
|
-
|
|
321
|
-
return result;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
_mapTRXStatus(outcome) {
|
|
325
|
-
switch (outcome) {
|
|
326
|
-
case 'Passed':
|
|
327
|
-
return STATUS.PASSED;
|
|
328
|
-
case 'Failed':
|
|
329
|
-
return STATUS.FAILED;
|
|
330
|
-
case 'Skipped':
|
|
331
|
-
return STATUS.SKIPPED;
|
|
332
|
-
default:
|
|
333
|
-
return STATUS.PASSED;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
249
|
processXUnit(assemblies) {
|
|
338
250
|
const tests = [];
|
|
339
251
|
|
|
@@ -600,7 +512,7 @@ function reduceTestCases(prev, item) {
|
|
|
600
512
|
|
|
601
513
|
const exampleMatches = testCaseItem.name?.match(/\S\((.*?)\)/);
|
|
602
514
|
if (exampleMatches) {
|
|
603
|
-
example = { ...exampleMatches[1].split(',').map(v => v.trim().replace(/[^\w\s-]/g, ''))
|
|
515
|
+
example = { ...exampleMatches[1].split(',').map(v => v.trim().replace(/[^\w\s-]/g, '')) };
|
|
604
516
|
title = title.replace(/\(.*?\)/, '').trim();
|
|
605
517
|
}
|
|
606
518
|
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enhanced NUnit XML Parser that properly handles test-suite hierarchy
|
|
3
|
-
* and parameterized tests
|
|
4
|
-
*/
|
|
5
|
-
export class NUnitXmlParser {
|
|
6
|
-
constructor(options?: {});
|
|
7
|
-
options: {};
|
|
8
|
-
tests: any[];
|
|
9
|
-
stats: {
|
|
10
|
-
total: number;
|
|
11
|
-
passed: number;
|
|
12
|
-
failed: number;
|
|
13
|
-
skipped: number;
|
|
14
|
-
inconclusive: number;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Parse NUnit XML test-run structure
|
|
18
|
-
* @param {Object} testRun - Parsed XML test-run object
|
|
19
|
-
* @returns {Object} - Parsed test results
|
|
20
|
-
*/
|
|
21
|
-
parseTestRun(testRun: any): any;
|
|
22
|
-
/**
|
|
23
|
-
* Recursively parse test-suite elements based on their type
|
|
24
|
-
* @param {Object|Array} testSuite - Test suite object or array
|
|
25
|
-
* @param {Array} parentPath - Current path in the hierarchy
|
|
26
|
-
*/
|
|
27
|
-
parseTestSuite(testSuite: any | any[], parentPath?: any[]): void;
|
|
28
|
-
/**
|
|
29
|
-
* Process child elements of a test suite
|
|
30
|
-
* @param {Object} testSuite - Test suite object
|
|
31
|
-
* @param {Array} currentPath - Current path in hierarchy
|
|
32
|
-
*/
|
|
33
|
-
processChildren(testSuite: any, currentPath: any[]): void;
|
|
34
|
-
/**
|
|
35
|
-
* Parse test-case elements (actual tests)
|
|
36
|
-
* @param {Object|Array} testCases - Test case object or array
|
|
37
|
-
* @param {Array} suitePath - Path to the test suite
|
|
38
|
-
* @param {Object} parentSuite - Parent test suite for context
|
|
39
|
-
*/
|
|
40
|
-
parseTestCases(testCases: any | any[], suitePath: any[], parentSuite: any): void;
|
|
41
|
-
/**
|
|
42
|
-
* Parse individual test case
|
|
43
|
-
* @param {Object} testCase - Test case object
|
|
44
|
-
* @param {Array} suitePath - Path to the test suite
|
|
45
|
-
* @param {Object} parentSuite - Parent test suite for context
|
|
46
|
-
* @returns {Object|null} - Parsed test object
|
|
47
|
-
*/
|
|
48
|
-
parseTestCase(testCase: any, suitePath: any[], parentSuite: any): any | null;
|
|
49
|
-
/**
|
|
50
|
-
* Extract method name and parameters from test name
|
|
51
|
-
* @param {string} testName - Full test name
|
|
52
|
-
* @returns {Object} - Extracted information
|
|
53
|
-
*/
|
|
54
|
-
extractParameters(testName: string): any;
|
|
55
|
-
/**
|
|
56
|
-
* Parse parameter string into array of parameters
|
|
57
|
-
* @param {string} paramString - Parameter string
|
|
58
|
-
* @returns {Array} - Array of parameters
|
|
59
|
-
*/
|
|
60
|
-
parseParameterString(paramString: string): any[];
|
|
61
|
-
/**
|
|
62
|
-
* Extract method name from test name (fallback)
|
|
63
|
-
* @param {string} testName - Test name
|
|
64
|
-
* @returns {string} - Method name
|
|
65
|
-
*/
|
|
66
|
-
extractMethodName(testName: string): string;
|
|
67
|
-
/**
|
|
68
|
-
* Build file path from suite path and class name
|
|
69
|
-
* @param {Array} suitePath - Suite path array
|
|
70
|
-
* @param {string} className - Class name
|
|
71
|
-
* @param {Object} parentSuite - Parent suite for context
|
|
72
|
-
* @returns {string} - File path
|
|
73
|
-
*/
|
|
74
|
-
buildFilePath(suitePath: any[], className: string, parentSuite: any): string;
|
|
75
|
-
/**
|
|
76
|
-
* Group parameterized tests by base method name
|
|
77
|
-
* @param {Array} tests - Array of parsed tests
|
|
78
|
-
* @returns {Object} - Grouped tests
|
|
79
|
-
*/
|
|
80
|
-
groupParameterizedTests(tests: any[]): any;
|
|
81
|
-
}
|
|
82
|
-
export default NUnitXmlParser;
|