Skip to content

Commit 4b3c77f

Browse files
committed
- introduce test case to validate handling for multiple failures
1 parent f6e018f commit 4b3c77f

File tree

3 files changed

+112
-1
lines changed

3 files changed

+112
-1
lines changed

__tests__/testParser.test.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,70 @@ describe('parseTestReports', () => {
14391439
])
14401440
})
14411441

1442+
it('should handle multiple failures per test case correctly', async () => {
1443+
const testResult = await parseFile('test_results/multiple_failures/test_multiple_failures.xml', '', true)
1444+
expect(testResult).toBeDefined()
1445+
const {totalCount, skippedCount, failedCount, passedCount, globalAnnotations} = testResult!!
1446+
1447+
// Verify overall counts
1448+
expect(totalCount).toBe(4) // 4 total test cases
1449+
expect(skippedCount).toBe(1) // 1 skipped test
1450+
expect(failedCount).toBe(2) // 2 test cases with failures (testWithMultipleFailures, testWithSingleFailure)
1451+
expect(passedCount).toBe(1) // 1 passing test
1452+
1453+
// Filter to only failure annotations for easier verification
1454+
const failureAnnotations = globalAnnotations.filter(annotation => annotation.annotation_level === 'failure')
1455+
1456+
// Should have 4 failure annotations total: 3 from testWithMultipleFailures + 1 from testWithSingleFailure
1457+
expect(failureAnnotations).toHaveLength(4)
1458+
1459+
// Verify the multiple failures test case creates separate annotations
1460+
const multipleFailuresAnnotations = failureAnnotations.filter(annotation =>
1461+
annotation.title.includes('testWithMultipleFailures')
1462+
)
1463+
expect(multipleFailuresAnnotations).toHaveLength(3)
1464+
1465+
// Verify each failure has the correct index in the title
1466+
expect(multipleFailuresAnnotations[0].title).toBe('MultipleFailuresTest.testWithMultipleFailures (failure 1/3)')
1467+
expect(multipleFailuresAnnotations[0].message).toBe('First assertion failed')
1468+
expect(multipleFailuresAnnotations[0].raw_details).toContain('First failure stack trace details')
1469+
expect(multipleFailuresAnnotations[0].start_line).toBe(15)
1470+
1471+
expect(multipleFailuresAnnotations[1].title).toBe('MultipleFailuresTest.testWithMultipleFailures (failure 2/3)')
1472+
expect(multipleFailuresAnnotations[1].message).toBe('Second assertion failed')
1473+
expect(multipleFailuresAnnotations[1].raw_details).toContain('Second failure stack trace details')
1474+
expect(multipleFailuresAnnotations[1].start_line).toBe(20)
1475+
1476+
expect(multipleFailuresAnnotations[2].title).toBe('MultipleFailuresTest.testWithMultipleFailures (failure 3/3)')
1477+
expect(multipleFailuresAnnotations[2].message).toBe('Third assertion failed')
1478+
expect(multipleFailuresAnnotations[2].raw_details).toContain('Third failure stack trace details')
1479+
expect(multipleFailuresAnnotations[2].start_line).toBe(25)
1480+
1481+
// Verify the single failure test case (should not have failure index in title)
1482+
const singleFailureAnnotations = failureAnnotations.filter(annotation =>
1483+
annotation.title.includes('testWithSingleFailure')
1484+
)
1485+
expect(singleFailureAnnotations).toHaveLength(1)
1486+
expect(singleFailureAnnotations[0].title).toBe('MultipleFailuresTest.testWithSingleFailure')
1487+
expect(singleFailureAnnotations[0].message).toBe('Single failure message')
1488+
1489+
// Verify all failure annotations have the correct properties
1490+
failureAnnotations.forEach(annotation => {
1491+
expect(annotation.annotation_level).toBe('failure')
1492+
expect(annotation.status).toBe('failure')
1493+
expect(annotation.retries).toBe(0)
1494+
expect(annotation.path).toBe('MultipleFailuresTest')
1495+
expect(annotation.start_column).toBe(0)
1496+
expect(annotation.end_column).toBe(0)
1497+
})
1498+
1499+
// Verify that success and skipped test cases don't have failure annotations
1500+
const successAnnotations = globalAnnotations.filter(annotation => annotation.status === 'success')
1501+
const skippedAnnotations = globalAnnotations.filter(annotation => annotation.status === 'skipped')
1502+
expect(successAnnotations).toHaveLength(1)
1503+
expect(skippedAnnotations).toHaveLength(1)
1504+
})
1505+
14421506
it('parse corrupt test output', async () => {
14431507
const result = await parseTestReports(
14441508
'',

src/testParser.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,8 @@ async function parseTestCases(
609609
testcases = Array.from(testcaseMap.values())
610610
}
611611

612+
let testCaseFailedCount = 0 // Track number of test cases that failed
613+
612614
for (const testcase of testcases) {
613615
totalCount++
614616

@@ -627,6 +629,11 @@ async function parseTestCases(
627629
skippedCount++
628630
}
629631

632+
// Count this test case as failed if it has any failures (regardless of how many)
633+
if (failed) {
634+
testCaseFailedCount++
635+
}
636+
630637
// If this isn't reported as a failure and processing all passed tests
631638
// isn't enabled, then skip the rest of the processing.
632639
if (annotationLevel !== 'failure' && !includePassed) {
@@ -687,7 +694,7 @@ async function parseTestCases(
687694
if (limit >= 0 && annotations.length >= limit) break
688695
}
689696

690-
const failedCount = annotations.filter(a => a.annotation_level === 'failure').length
697+
const failedCount = testCaseFailedCount // Use test case count, not annotation count
691698
const passedCount = totalCount - failedCount - skippedCount
692699
return {
693700
totalCount,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<testsuites>
3+
<testsuite name="MultipleFailuresTest" tests="4" failures="4" errors="0" skipped="1" time="0.05">
4+
<!-- Test case with multiple failures -->
5+
<testcase name="testWithMultipleFailures" classname="com.example.MultipleFailuresTest" time="0.02">
6+
<failure message="First assertion failed" type="AssertionError">
7+
<![CDATA[AssertionError: First assertion failed
8+
at com.example.MultipleFailuresTest.testWithMultipleFailures(MultipleFailuresTest.java:15)
9+
First failure stack trace details]]>
10+
</failure>
11+
<failure message="Second assertion failed" type="AssertionError">
12+
<![CDATA[AssertionError: Second assertion failed
13+
at com.example.MultipleFailuresTest.testWithMultipleFailures(MultipleFailuresTest.java:20)
14+
Second failure stack trace details]]>
15+
</failure>
16+
<failure message="Third assertion failed" type="IllegalStateException">
17+
<![CDATA[IllegalStateException: Third assertion failed
18+
at com.example.MultipleFailuresTest.testWithMultipleFailures(MultipleFailuresTest.java:25)
19+
Third failure stack trace details]]>
20+
</failure>
21+
</testcase>
22+
23+
<!-- Test case with single failure for comparison -->
24+
<testcase name="testWithSingleFailure" classname="com.example.MultipleFailuresTest" time="0.01">
25+
<failure message="Single failure message" type="AssertionError">
26+
<![CDATA[AssertionError: Single failure message
27+
at com.example.MultipleFailuresTest.testWithSingleFailure(MultipleFailuresTest.java:35)
28+
Single failure stack trace]]>
29+
</failure>
30+
</testcase>
31+
32+
<!-- Test case that is skipped -->
33+
<testcase name="testSkipped" classname="com.example.MultipleFailuresTest" time="0.00">
34+
<skipped message="Test was skipped"/>
35+
</testcase>
36+
37+
<!-- Test case that passes -->
38+
<testcase name="testPassing" classname="com.example.MultipleFailuresTest" time="0.02"/>
39+
</testsuite>
40+
</testsuites>

0 commit comments

Comments
 (0)