Skip to content

Commit 386dce3

Browse files
Merge pull request #21 from ysfaran/feat/error-snippet
Feature: Add Error Snippet to Test Report Objects
2 parents 31d6f32 + 768da18 commit 386dce3

File tree

7 files changed

+141
-1
lines changed

7 files changed

+141
-1
lines changed

.github/workflows/main.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ jobs:
2020
- run: npm run build
2121
- run: npm run lint-check
2222
- run: npm run format-check
23+
- run: npm run test

src/generate-report.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ class GenerateCtrfReport implements Reporter {
189189
)
190190
test.message = this.extractFailureDetails(testResult).message
191191
test.trace = this.extractFailureDetails(testResult).trace
192+
test.snippet = this.extractFailureDetails(testResult).snippet
192193
test.rawStatus = testResult.status
193194
test.tags = this.extractTagsFromTitle(testCase.title)
194195
test.type = this.reporterConfigOptions.testType ?? 'e2e'
@@ -381,6 +382,9 @@ class GenerateCtrfReport implements Reporter {
381382
if (testResult.error.stack !== undefined) {
382383
failureDetails.trace = testResult.error.stack
383384
}
385+
if (testResult.error.snippet !== undefined) {
386+
failureDetails.snippet = testResult.error.snippet
387+
}
384388
return failureDetails
385389
}
386390
return {}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import {
2+
type Suite,
3+
type TestCase,
4+
type Location,
5+
type TestResult,
6+
type TestError,
7+
} from '@playwright/test/reporter'
8+
9+
/**
10+
* Creates a minimal Suite object with a single failed test
11+
*/
12+
export const createFailedTestSuite = (): Suite => {
13+
const testError: TestError = {
14+
message: 'test-error-message',
15+
stack: 'test-error-stack',
16+
snippet: 'test-error-snippet',
17+
}
18+
19+
const testResult: TestResult = {
20+
retry: 0,
21+
duration: 120,
22+
status: 'failed',
23+
startTime: new Date('2023-01-01T00:00:00.000Z'),
24+
parallelIndex: 0,
25+
workerIndex: 0,
26+
attachments: [],
27+
errors: [testError],
28+
error: testError,
29+
steps: [],
30+
stdout: [],
31+
stderr: [],
32+
}
33+
34+
const testCase: TestCase = {
35+
title: 'should validate the expected condition',
36+
id: 'test-id-123',
37+
annotations: [],
38+
expectedStatus: 'passed',
39+
timeout: 30000,
40+
results: [testResult],
41+
location: {
42+
file: 'test-file.spec.ts',
43+
line: 42,
44+
column: 3,
45+
},
46+
parent: undefined as any, // Will be set later
47+
outcome: () => 'unexpected',
48+
ok: () => false,
49+
titlePath: () => [
50+
'Failed Test Suite',
51+
'should validate the expected condition',
52+
],
53+
repeatEachIndex: 0,
54+
retries: 0,
55+
}
56+
57+
const suite: Suite = {
58+
title: 'Failed Test Suite',
59+
titlePath: () => ['Failed Test Suite'],
60+
location: {
61+
file: 'test-file.spec.ts',
62+
line: 10,
63+
column: 1,
64+
} as Location,
65+
project: () => ({
66+
name: 'Test Project',
67+
outputDir: './test-results',
68+
grep: /.*/,
69+
grepInvert: null,
70+
metadata: {},
71+
dependencies: [],
72+
repeatEach: 1,
73+
retries: 0,
74+
timeout: 30000,
75+
use: {},
76+
testDir: './tests',
77+
testIgnore: [],
78+
testMatch: [],
79+
snapshotDir: './snapshots',
80+
}),
81+
allTests: () => [testCase],
82+
tests: [testCase],
83+
suites: [],
84+
}
85+
86+
testCase.parent = suite
87+
88+
return suite
89+
}

tests/failed-tests.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { createFailedTestSuite } from './dummy-suites/failed-test-suite'
2+
import GenerateCtrfReport from '../src/generate-report'
3+
import fs from 'fs'
4+
import { CtrfReport } from '../types/ctrf'
5+
6+
jest.mock('fs', () => ({
7+
writeFileSync: jest.fn(),
8+
existsSync: jest.fn(() => true),
9+
}))
10+
const nowDateMock = new Date('2023-01-01T00:00:00.000Z')
11+
jest.useFakeTimers().setSystemTime(nowDateMock)
12+
13+
const mockedFs = fs as jest.Mocked<typeof fs>
14+
15+
describe('Failed Tests', () => {
16+
it('should generate report with error details correctly', async () => {
17+
// Arrange
18+
const testSuite = createFailedTestSuite()
19+
const report = new GenerateCtrfReport()
20+
21+
// Act
22+
report.onBegin(undefined as any, testSuite)
23+
report.onEnd()
24+
25+
// Assert
26+
expect(mockedFs.writeFileSync).toHaveBeenCalledTimes(1)
27+
28+
const reportJsonContent = mockedFs.writeFileSync.mock.calls[0][1] as string
29+
const parsedReport: CtrfReport = JSON.parse(reportJsonContent)
30+
31+
expect(parsedReport.results.tests).toHaveLength(1)
32+
expect(parsedReport.results.tests[0].status).toBe('failed')
33+
expect(parsedReport.results.tests[0].message).toBe('test-error-message')
34+
expect(parsedReport.results.tests[0].trace).toBe('test-error-stack')
35+
expect(parsedReport.results.tests[0].snippet).toBe('test-error-snippet')
36+
})
37+
})

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
"rootDir": "./src",
99
"declaration": true,
1010
"forceConsistentCasingInFileNames": true
11-
}
11+
},
12+
"include": ["src/**/*"]
1213
}

tsconfig.test.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"compilerOptions": {
4+
"rootDirs": ["src", "tests"],
5+
"noEmit": true
6+
}
7+
}

types/ctrf.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export interface CtrfTest {
3232
suite?: string
3333
message?: string
3434
trace?: string
35+
snippet?: string
3536
rawStatus?: string
3637
tags?: string[]
3738
type?: string

0 commit comments

Comments
 (0)