diff --git a/docs/config/index.md b/docs/config/index.md index 61f95f9c5b01..297524402c5f 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -339,7 +339,7 @@ Custom reporters for output. Reporters can be [a Reporter instance](https://gith - `'default'` - collapse suites when they pass - `'verbose'` - keep the full task tree visible - `'dot'` - show each task as a single dot - - `'junit'` - JUnit XML reporter + - `'junit'` - JUnit XML reporter (you can configure `testsuites` tag name with `VITEST_JUNIT_SUITE_NAME` environmental variable) - `'json'` - give a simple JSON summary - path of a custom reporter (e.g. `'./path/to/reporter.ts'`, `'@scope/reporter'`) diff --git a/packages/vitest/src/node/reporters/junit.ts b/packages/vitest/src/node/reporters/junit.ts index f452a4767f44..16fd717158fe 100644 --- a/packages/vitest/src/node/reporters/junit.ts +++ b/packages/vitest/src/node/reporters/junit.ts @@ -58,9 +58,13 @@ function escapeXML(value: any): string { true) } +function executionTime(durationMS: number) { + return (durationMS / 1000).toLocaleString(undefined, { useGrouping: false, maximumFractionDigits: 10 }) +} + export function getDuration(task: Task): string | undefined { const duration = task.result?.duration ?? 0 - return (duration / 1000).toLocaleString(undefined, { useGrouping: false, maximumFractionDigits: 10 }) + return executionTime(duration) } export class JUnitReporter implements Reporter { @@ -68,6 +72,7 @@ export class JUnitReporter implements Reporter { private reportFile?: string private baseLog!: (text: string) => Promise private logger!: IndentedLogger> + private _timeStart = new Date() async onInit(ctx: Vitest): Promise { this.ctx = ctx @@ -89,6 +94,7 @@ export class JUnitReporter implements Reporter { this.baseLog = async (text: string) => this.ctx.logger.log(text) } + this._timeStart = new Date() this.logger = new IndentedLogger(this.baseLog) } @@ -205,7 +211,19 @@ export class JUnitReporter implements Reporter { } }) - await this.writeElement('testsuites', {}, async () => { + const stats = transformed.reduce((stats, file) => { + stats.tests += file.tasks.length + stats.failures += file.stats.failures + return stats + }, { + name: process.env.VITEST_JUNIT_SUITE_NAME || 'vitest tests', + tests: 0, + failures: 0, + errors: 0, // we cannot detect those + time: executionTime(new Date().getTime() - this._timeStart.getTime()), + }) + + await this.writeElement('testsuites', stats, async () => { for (const file of transformed) { await this.writeElement('testsuite', { name: file.name, diff --git a/test/reporters/package.json b/test/reporters/package.json index 8403bc3468ea..9f3fe4261b29 100644 --- a/test/reporters/package.json +++ b/test/reporters/package.json @@ -2,7 +2,7 @@ "name": "@vitest/test-reporters", "private": true, "scripts": { - "test": "vitest" + "test": "vitest run" }, "devDependencies": { "execa": "^6.1.0", diff --git a/test/reporters/tests/__snapshots__/reporters.spec.ts.snap b/test/reporters/tests/__snapshots__/reporters.spec.ts.snap index ae1db42bf395..e3ba742d5659 100644 --- a/test/reporters/tests/__snapshots__/reporters.spec.ts.snap +++ b/test/reporters/tests/__snapshots__/reporters.spec.ts.snap @@ -2,7 +2,7 @@ exports[`JUnit reporter (no outputFile entry) 1`] = ` " - + @@ -38,7 +38,7 @@ AssertionError: expected 2.23606797749979 to equal 2 exports[`JUnit reporter 1`] = ` " - + @@ -79,7 +79,7 @@ exports[`JUnit reporter with outputFile 1`] = ` exports[`JUnit reporter with outputFile 2`] = ` " - + @@ -120,7 +120,7 @@ exports[`JUnit reporter with outputFile in non-existing directory 1`] = ` exports[`JUnit reporter with outputFile in non-existing directory 2`] = ` " - + @@ -161,7 +161,7 @@ exports[`JUnit reporter with outputFile object 1`] = ` exports[`JUnit reporter with outputFile object 2`] = ` " - + @@ -202,7 +202,7 @@ exports[`JUnit reporter with outputFile object in non-existing directory 1`] = ` exports[`JUnit reporter with outputFile object in non-existing directory 2`] = ` " - + @@ -243,7 +243,7 @@ exports[`JUnit reporter with outputFile with XML in error message 1`] = ` exports[`JUnit reporter with outputFile with XML in error message 2`] = ` " - + diff --git a/test/reporters/tests/reporters.spec.ts b/test/reporters/tests/reporters.spec.ts index d0061a9439a5..d26db9b953b7 100644 --- a/test/reporters/tests/reporters.spec.ts +++ b/test/reporters/tests/reporters.spec.ts @@ -1,4 +1,4 @@ -import { existsSync, readFileSync, rmSync, rmdirSync } from 'fs' +import { existsSync, readFileSync, rmSync } from 'fs' import { afterEach, expect, test, vi } from 'vitest' import { normalize, resolve } from 'pathe' import { JsonReporter } from '../../../packages/vitest/src/node/reporters/json' @@ -185,7 +185,7 @@ test('JUnit reporter with outputFile in non-existing directory', async () => { expect(readFileSync(outputFile, 'utf8')).toMatchSnapshot() // Cleanup - rmdirSync(rootDirectory, { recursive: true }) + rmSync(rootDirectory, { recursive: true }) }) test('JUnit reporter with outputFile object in non-existing directory', async () => { @@ -214,7 +214,7 @@ test('JUnit reporter with outputFile object in non-existing directory', async () expect(readFileSync(outputFile, 'utf8')).toMatchSnapshot() // Cleanup - rmdirSync(rootDirectory, { recursive: true }) + rmSync(rootDirectory, { recursive: true }) }) test('json reporter', async () => { @@ -314,7 +314,7 @@ test('json reporter with outputFile in non-existing directory', async () => { expect(readFileSync(outputFile, 'utf8')).toMatchSnapshot() // Cleanup - rmdirSync(rootDirectory, { recursive: true }) + rmSync(rootDirectory, { recursive: true }) }) test('json reporter with outputFile object in non-existing directory', async () => { @@ -339,7 +339,7 @@ test('json reporter with outputFile object in non-existing directory', async () expect(readFileSync(outputFile, 'utf8')).toMatchSnapshot() // Cleanup - rmdirSync(rootDirectory, { recursive: true }) + rmSync(rootDirectory, { recursive: true }) }) /**