From 2f9132223870cee12ea84fe125e788a54207ccef Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Fri, 3 May 2024 17:15:59 +0900 Subject: [PATCH] feat(reporter): support `includeConsoleOutput` and `addFileAttribute` in junit (#5659) --- packages/vitest/src/node/reporters/junit.ts | 25 +++++++-- .../reporters/fixtures/console-simple.test.ts | 7 +++ test/reporters/fixtures/ok.test.ts | 3 ++ .../tests/__snapshots__/junit.test.ts.snap | 52 +++++++++++++++++++ test/reporters/tests/junit.test.ts | 18 +++++++ 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 test/reporters/fixtures/console-simple.test.ts create mode 100644 test/reporters/fixtures/ok.test.ts diff --git a/packages/vitest/src/node/reporters/junit.ts b/packages/vitest/src/node/reporters/junit.ts index 3054aba84b95..cf08a09ca51d 100644 --- a/packages/vitest/src/node/reporters/junit.ts +++ b/packages/vitest/src/node/reporters/junit.ts @@ -15,6 +15,16 @@ export interface JUnitOptions { outputFile?: string classname?: string suiteName?: string + /** + * Write and for console output + * @default true + */ + includeConsoleOutput?: boolean + /** + * Add attribute (validated on CIRCLE CI and GitLab CI) + * @default false + */ + addFileAttribute?: boolean } function flattenTasks(task: Task, baseName = ''): Task[] { @@ -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 { @@ -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('') @@ -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, @@ -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) }) } }) diff --git a/test/reporters/fixtures/console-simple.test.ts b/test/reporters/fixtures/console-simple.test.ts new file mode 100644 index 000000000000..4387b4101795 --- /dev/null +++ b/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) +}) diff --git a/test/reporters/fixtures/ok.test.ts b/test/reporters/fixtures/ok.test.ts new file mode 100644 index 000000000000..b7091bc41eb2 --- /dev/null +++ b/test/reporters/fixtures/ok.test.ts @@ -0,0 +1,3 @@ +import { test } from "vitest" + +test("ok", () => {}); diff --git a/test/reporters/tests/__snapshots__/junit.test.ts.snap b/test/reporters/tests/__snapshots__/junit.test.ts.snap index 7bcaeec8a22e..43756e0cbd01 100644 --- a/test/reporters/tests/__snapshots__/junit.test.ts.snap +++ b/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`] = ` +" + + + + + + +" +`; + +exports[`addFileAttribute true 1`] = ` +" + + + + + + +" +`; + exports[`emits when beforeAll/afterAll failed 1`] = ` " @@ -114,3 +136,33 @@ Error: throwSuite " `; + +exports[`includeConsoleOutput false 1`] = ` +" + + + + + + +" +`; + +exports[`includeConsoleOutput true 1`] = ` +" + + + + +__test_stdout__ + + + +__test_stderr__ + + + + + +" +`; diff --git a/test/reporters/tests/junit.test.ts b/test/reporters/tests/junit.test.ts index 07b2698ce050..be577887de7c 100644 --- a/test/reporters/tests/junit.test.ts +++ b/test/reporters/tests/junit.test.ts @@ -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() +})