@testomatio/reporter 2.1.3-beta.1-xml-import → 2.1.3-beta.2-xml-import
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/lib/xmlReader.js +61 -12
- package/package.json +1 -1
- package/src/xmlReader.js +68 -13
package/lib/xmlReader.js
CHANGED
|
@@ -283,16 +283,60 @@ class XmlReader {
|
|
|
283
283
|
const fqn = this.generateNormalizedFQN(test);
|
|
284
284
|
if (fqnMap.has(fqn)) {
|
|
285
285
|
const existingTest = fqnMap.get(fqn);
|
|
286
|
-
//
|
|
287
|
-
if (test.
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
286
|
+
// For parameterized tests, merge as Examples
|
|
287
|
+
if (test.example) {
|
|
288
|
+
// Initialize examples array if it doesn't exist
|
|
289
|
+
if (!existingTest.examples) {
|
|
290
|
+
existingTest.examples = [];
|
|
291
|
+
// Add the existing test's example as the first item
|
|
292
|
+
if (existingTest.example) {
|
|
293
|
+
existingTest.examples.push({
|
|
294
|
+
parameters: existingTest.example,
|
|
295
|
+
status: existingTest.status,
|
|
296
|
+
run_time: existingTest.run_time,
|
|
297
|
+
message: existingTest.message,
|
|
298
|
+
stack: existingTest.stack
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// Add this test's execution as an example
|
|
303
|
+
existingTest.examples.push({
|
|
304
|
+
parameters: test.example,
|
|
305
|
+
status: test.status,
|
|
306
|
+
run_time: test.run_time,
|
|
307
|
+
message: test.message,
|
|
308
|
+
stack: test.stack
|
|
309
|
+
});
|
|
310
|
+
// Update the main test status to reflect the worst status
|
|
311
|
+
if (test.status === 'failed' || existingTest.status === 'failed') {
|
|
312
|
+
existingTest.status = 'failed';
|
|
313
|
+
}
|
|
314
|
+
else if (test.status === 'skipped' && existingTest.status !== 'failed') {
|
|
315
|
+
existingTest.status = 'skipped';
|
|
316
|
+
}
|
|
317
|
+
// Update total run time
|
|
318
|
+
existingTest.run_time = (existingTest.run_time || 0) + (test.run_time || 0);
|
|
319
|
+
// Merge stack traces if they're different
|
|
320
|
+
if (test.stack && test.stack !== existingTest.stack) {
|
|
321
|
+
existingTest.stack = existingTest.stack + '\n\n---\n\n' + test.stack;
|
|
322
|
+
}
|
|
323
|
+
// Merge messages if they're different
|
|
324
|
+
if (test.message && test.message !== existingTest.message) {
|
|
325
|
+
existingTest.message = existingTest.message + '; ' + test.message;
|
|
326
|
+
}
|
|
293
327
|
}
|
|
294
|
-
|
|
295
|
-
|
|
328
|
+
else {
|
|
329
|
+
// Merge test properties for non-parameterized tests, prioritizing Test Explorer structure
|
|
330
|
+
if (test.test_id && !existingTest.test_id) {
|
|
331
|
+
existingTest.test_id = test.test_id;
|
|
332
|
+
}
|
|
333
|
+
// Keep the most complete test data
|
|
334
|
+
if (test.stack && !existingTest.stack) {
|
|
335
|
+
existingTest.stack = test.stack;
|
|
336
|
+
}
|
|
337
|
+
if (test.message && !existingTest.message) {
|
|
338
|
+
existingTest.message = test.message;
|
|
339
|
+
}
|
|
296
340
|
}
|
|
297
341
|
// Prefer Test Explorer structure (longer, more complete suite_title)
|
|
298
342
|
if (test.suite_title && test.suite_title.length > existingTest.suite_title.length) {
|
|
@@ -322,7 +366,7 @@ class XmlReader {
|
|
|
322
366
|
}
|
|
323
367
|
generateNormalizedFQN(test) {
|
|
324
368
|
// Generate normalized FQN for deduplication by extracting the core namespace.class.method
|
|
325
|
-
//
|
|
369
|
+
// For parameterized tests, we want the SAME FQN so they merge into one test with multiple Examples
|
|
326
370
|
const fullClassName = test.suite_title || '';
|
|
327
371
|
const methodName = test.title;
|
|
328
372
|
// Extract the most specific namespace.class pattern
|
|
@@ -579,9 +623,13 @@ function reduceTestCases(prev, item) {
|
|
|
579
623
|
const suiteTitle = extractTestExplorerSuiteTitle(testCaseItem, item);
|
|
580
624
|
title ||= testCaseItem.name || testCaseItem.methodname || testCaseItem.classname;
|
|
581
625
|
tags ||= [];
|
|
582
|
-
|
|
626
|
+
// Store original test name for parameter extraction
|
|
627
|
+
const originalTestName = testCaseItem.name || testCaseItem.methodname;
|
|
628
|
+
const exampleMatches = originalTestName?.match(/\((.*?)\)$/);
|
|
583
629
|
if (exampleMatches) {
|
|
584
|
-
|
|
630
|
+
// Extract and store parameters as Examples
|
|
631
|
+
const parameterValues = exampleMatches[1].split(',').map(v => v.trim().replace(/['"]/g, ''));
|
|
632
|
+
example = { ...parameterValues };
|
|
585
633
|
title = title.replace(/\(.*?\)/, '').trim();
|
|
586
634
|
}
|
|
587
635
|
stack = `${testCaseItem['system-out'] || testCaseItem.output || testCaseItem.log || ''}\n\n${stack}\n\n${suiteOutput}\n\n${suiteErr}`.trim();
|
|
@@ -630,6 +678,7 @@ function reduceTestCases(prev, item) {
|
|
|
630
678
|
run_time: parseFloat(testCaseItem.time || testCaseItem.duration) * 1000,
|
|
631
679
|
status,
|
|
632
680
|
title,
|
|
681
|
+
originalTestName, // Store original name for parameter-aware FQN generation
|
|
633
682
|
root_suite_id: TESTOMATIO_SUITE,
|
|
634
683
|
suite_title: suiteTitle,
|
|
635
684
|
files,
|
package/package.json
CHANGED
package/src/xmlReader.js
CHANGED
|
@@ -330,17 +330,66 @@ class XmlReader {
|
|
|
330
330
|
|
|
331
331
|
if (fqnMap.has(fqn)) {
|
|
332
332
|
const existingTest = fqnMap.get(fqn);
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
333
|
+
|
|
334
|
+
// For parameterized tests, merge as Examples
|
|
335
|
+
if (test.example) {
|
|
336
|
+
// Initialize examples array if it doesn't exist
|
|
337
|
+
if (!existingTest.examples) {
|
|
338
|
+
existingTest.examples = [];
|
|
339
|
+
// Add the existing test's example as the first item
|
|
340
|
+
if (existingTest.example) {
|
|
341
|
+
existingTest.examples.push({
|
|
342
|
+
parameters: existingTest.example,
|
|
343
|
+
status: existingTest.status,
|
|
344
|
+
run_time: existingTest.run_time,
|
|
345
|
+
message: existingTest.message,
|
|
346
|
+
stack: existingTest.stack
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Add this test's execution as an example
|
|
352
|
+
existingTest.examples.push({
|
|
353
|
+
parameters: test.example,
|
|
354
|
+
status: test.status,
|
|
355
|
+
run_time: test.run_time,
|
|
356
|
+
message: test.message,
|
|
357
|
+
stack: test.stack
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Update the main test status to reflect the worst status
|
|
361
|
+
if (test.status === 'failed' || existingTest.status === 'failed') {
|
|
362
|
+
existingTest.status = 'failed';
|
|
363
|
+
} else if (test.status === 'skipped' && existingTest.status !== 'failed') {
|
|
364
|
+
existingTest.status = 'skipped';
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Update total run time
|
|
368
|
+
existingTest.run_time = (existingTest.run_time || 0) + (test.run_time || 0);
|
|
369
|
+
|
|
370
|
+
// Merge stack traces if they're different
|
|
371
|
+
if (test.stack && test.stack !== existingTest.stack) {
|
|
372
|
+
existingTest.stack = existingTest.stack + '\n\n---\n\n' + test.stack;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Merge messages if they're different
|
|
376
|
+
if (test.message && test.message !== existingTest.message) {
|
|
377
|
+
existingTest.message = existingTest.message + '; ' + test.message;
|
|
378
|
+
}
|
|
379
|
+
} else {
|
|
380
|
+
// Merge test properties for non-parameterized tests, prioritizing Test Explorer structure
|
|
381
|
+
if (test.test_id && !existingTest.test_id) {
|
|
382
|
+
existingTest.test_id = test.test_id;
|
|
383
|
+
}
|
|
384
|
+
// Keep the most complete test data
|
|
385
|
+
if (test.stack && !existingTest.stack) {
|
|
386
|
+
existingTest.stack = test.stack;
|
|
387
|
+
}
|
|
388
|
+
if (test.message && !existingTest.message) {
|
|
389
|
+
existingTest.message = test.message;
|
|
390
|
+
}
|
|
343
391
|
}
|
|
392
|
+
|
|
344
393
|
// Prefer Test Explorer structure (longer, more complete suite_title)
|
|
345
394
|
if (test.suite_title && test.suite_title.length > existingTest.suite_title.length) {
|
|
346
395
|
existingTest.suite_title = test.suite_title;
|
|
@@ -373,7 +422,7 @@ class XmlReader {
|
|
|
373
422
|
|
|
374
423
|
generateNormalizedFQN(test) {
|
|
375
424
|
// Generate normalized FQN for deduplication by extracting the core namespace.class.method
|
|
376
|
-
//
|
|
425
|
+
// For parameterized tests, we want the SAME FQN so they merge into one test with multiple Examples
|
|
377
426
|
|
|
378
427
|
const fullClassName = test.suite_title || '';
|
|
379
428
|
const methodName = test.title;
|
|
@@ -654,9 +703,14 @@ function reduceTestCases(prev, item) {
|
|
|
654
703
|
title ||= testCaseItem.name || testCaseItem.methodname || testCaseItem.classname;
|
|
655
704
|
tags ||= [];
|
|
656
705
|
|
|
657
|
-
|
|
706
|
+
// Store original test name for parameter extraction
|
|
707
|
+
const originalTestName = testCaseItem.name || testCaseItem.methodname;
|
|
708
|
+
|
|
709
|
+
const exampleMatches = originalTestName?.match(/\((.*?)\)$/);
|
|
658
710
|
if (exampleMatches) {
|
|
659
|
-
|
|
711
|
+
// Extract and store parameters as Examples
|
|
712
|
+
const parameterValues = exampleMatches[1].split(',').map(v => v.trim().replace(/['"]/g, ''));
|
|
713
|
+
example = { ...parameterValues };
|
|
660
714
|
title = title.replace(/\(.*?\)/, '').trim();
|
|
661
715
|
}
|
|
662
716
|
|
|
@@ -712,6 +766,7 @@ function reduceTestCases(prev, item) {
|
|
|
712
766
|
run_time: parseFloat(testCaseItem.time || testCaseItem.duration) * 1000,
|
|
713
767
|
status,
|
|
714
768
|
title,
|
|
769
|
+
originalTestName, // Store original name for parameter-aware FQN generation
|
|
715
770
|
root_suite_id: TESTOMATIO_SUITE,
|
|
716
771
|
suite_title: suiteTitle,
|
|
717
772
|
files,
|