Skip to content

Commit

Permalink
feat(reporter): support includeConsoleOutput and addFileAttribute
Browse files Browse the repository at this point in the history
… in junit (#5659)
  • Loading branch information
hi-ogawa committed May 3, 2024
1 parent c571276 commit 2f91322
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 5 deletions.
25 changes: 20 additions & 5 deletions packages/vitest/src/node/reporters/junit.ts
Expand Up @@ -15,6 +15,16 @@ export interface JUnitOptions {
outputFile?: string
classname?: string
suiteName?: string
/**
* Write <system-out> and <system-err> for console output
* @default true
*/
includeConsoleOutput?: boolean
/**
* Add <testcase file="..."> attribute (validated on CIRCLE CI and GitLab CI)
* @default false
*/
addFileAttribute?: boolean
}

function flattenTasks(task: Task, baseName = ''): Task[] {
Expand Down Expand Up @@ -88,7 +98,8 @@ export class JUnitReporter implements Reporter {
private options: JUnitOptions

constructor(options: JUnitOptions) {
this.options = options
this.options = { ...options }
this.options.includeConsoleOutput ??= true
}

async onInit(ctx: Vitest): Promise<void> {
Expand Down Expand Up @@ -160,11 +171,14 @@ export class JUnitReporter implements Reporter {
await this.writeElement('testcase', {
// TODO: v2.0.0 Remove env variable in favor of custom reporter options, e.g. "reporters: [['json', { classname: 'something' }]]"
classname: this.options.classname ?? process.env.VITEST_JUNIT_CLASSNAME ?? filename,
file: this.options.addFileAttribute ? filename : undefined,
name: task.name,
time: getDuration(task),
}, async () => {
await this.writeLogs(task, 'out')
await this.writeLogs(task, 'err')
if (this.options.includeConsoleOutput) {
await this.writeLogs(task, 'out')
await this.writeLogs(task, 'err')
}

if (task.mode === 'skip' || task.mode === 'todo')
await this.logger.log('<skipped/>')
Expand Down Expand Up @@ -259,8 +273,9 @@ export class JUnitReporter implements Reporter {

await this.writeElement('testsuites', stats, async () => {
for (const file of transformed) {
const filename = relative(this.ctx.config.root, file.filepath)
await this.writeElement('testsuite', {
name: relative(this.ctx.config.root, file.filepath),
name: filename,
timestamp: (new Date()).toISOString(),
hostname: hostname(),
tests: file.tasks.length,
Expand All @@ -269,7 +284,7 @@ export class JUnitReporter implements Reporter {
skipped: file.stats.skipped,
time: getDuration(file),
}, async () => {
await this.writeTasks(file.tasks, file.name)
await this.writeTasks(file.tasks, filename)
})
}
})
Expand Down
7 changes: 7 additions & 0 deletions test/reporters/fixtures/console-simple.test.ts
@@ -0,0 +1,7 @@
import { describe, expect, test } from 'vitest'

test('test', () => {
console.log('__test_stdout__')
console.error('__test_stderr__')
expect(0).toBe(0)
})
3 changes: 3 additions & 0 deletions test/reporters/fixtures/ok.test.ts
@@ -0,0 +1,3 @@
import { test } from "vitest"

test("ok", () => {});
52 changes: 52 additions & 0 deletions test/reporters/tests/__snapshots__/junit.test.ts.snap
@@ -1,5 +1,27 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`addFileAttribute false 1`] = `
"<?xml version="1.0" encoding="UTF-8" ?>
<testsuites name="vitest tests" tests="1" failures="0" errors="0" time="...">
<testsuite name="ok.test.ts" timestamp="..." hostname="..." tests="1" failures="0" errors="0" skipped="0" time="...">
<testcase classname="ok.test.ts" name="ok" time="...">
</testcase>
</testsuite>
</testsuites>
"
`;

exports[`addFileAttribute true 1`] = `
"<?xml version="1.0" encoding="UTF-8" ?>
<testsuites name="vitest tests" tests="1" failures="0" errors="0" time="...">
<testsuite name="ok.test.ts" timestamp="..." hostname="..." tests="1" failures="0" errors="0" skipped="0" time="...">
<testcase classname="ok.test.ts" file="ok.test.ts" name="ok" time="...">
</testcase>
</testsuite>
</testsuites>
"
`;

exports[`emits <failure> when beforeAll/afterAll failed 1`] = `
"<?xml version="1.0" encoding="UTF-8" ?>
<testsuites name="vitest tests" tests="8" failures="2" errors="0" time="...">
Expand Down Expand Up @@ -114,3 +136,33 @@ Error: throwSuite
</testsuites>
"
`;
exports[`includeConsoleOutput false 1`] = `
"<?xml version="1.0" encoding="UTF-8" ?>
<testsuites name="vitest tests" tests="1" failures="0" errors="0" time="...">
<testsuite name="console-simple.test.ts" timestamp="..." hostname="..." tests="1" failures="0" errors="0" skipped="0" time="...">
<testcase classname="console-simple.test.ts" name="test" time="...">
</testcase>
</testsuite>
</testsuites>
"
`;
exports[`includeConsoleOutput true 1`] = `
"<?xml version="1.0" encoding="UTF-8" ?>
<testsuites name="vitest tests" tests="1" failures="0" errors="0" time="...">
<testsuite name="console-simple.test.ts" timestamp="..." hostname="..." tests="1" failures="0" errors="0" skipped="0" time="...">
<testcase classname="console-simple.test.ts" name="test" time="...">
<system-out>
__test_stdout__
</system-out>
<system-err>
__test_stderr__
</system-err>
</testcase>
</testsuite>
</testsuites>
"
`;
18 changes: 18 additions & 0 deletions test/reporters/tests/junit.test.ts
Expand Up @@ -102,3 +102,21 @@ test('options.suiteName changes name property', async () => {
function stabilizeReport(report: string) {
return report.replaceAll(/(timestamp|hostname|time)=".*?"/g, '$1="..."')
}

test.each([true, false])('includeConsoleOutput %s', async (t) => {
const { stdout } = await runVitest({
reporters: [['junit', { includeConsoleOutput: t }]],
root,
include: ['console-simple.test.ts'],
})
expect(stabilizeReport(stdout)).matchSnapshot()
})

test.each([true, false])('addFileAttribute %s', async (t) => {
const { stdout } = await runVitest({
reporters: [['junit', { addFileAttribute: t }]],
root,
include: ['ok.test.ts'],
})
expect(stabilizeReport(stdout)).matchSnapshot()
})

0 comments on commit 2f91322

Please sign in to comment.