diff --git a/packages/vitest/src/node/reporters/junit.ts b/packages/vitest/src/node/reporters/junit.ts index 9af97aa7aa4f..64d2705cf622 100644 --- a/packages/vitest/src/node/reporters/junit.ts +++ b/packages/vitest/src/node/reporters/junit.ts @@ -210,7 +210,7 @@ function removeInvalidXMLCharacters(value: any, removeDiscouragedChars: boolean) function escapeXML(value: any): string { return removeInvalidXMLCharacters( - String(value) + stripVTControlCharacters(String(value)) .replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') @@ -481,7 +481,7 @@ export class JUnitReporter implements Reporter { return } const result = this.ctx.logger.formatError(error, errorOptions) - await this.baseLog(escapeXML(stripVTControlCharacters(result.output.trim()))) + await this.baseLog(escapeXML(result.output.trim())) }, ) } diff --git a/test/e2e/test/reporters/junit.test.ts b/test/e2e/test/reporters/junit.test.ts index 46936e10f89a..59d7be9a7202 100644 --- a/test/e2e/test/reporters/junit.test.ts +++ b/test/e2e/test/reporters/junit.test.ts @@ -3,7 +3,7 @@ import { readFileSync } from 'node:fs' import { resolve } from 'pathe' import { expect, test, TestRunner } from 'vitest' import { rolldownVersion } from 'vitest/node' -import { runVitest, runVitestCli } from '#test-utils' +import { runInlineTests, runVitest, runVitestCli } from '#test-utils' import { getDuration } from '../../../../packages/vitest/src/node/reporters/junit' const root = resolve(import.meta.dirname, '../../fixtures/reporters') @@ -113,6 +113,36 @@ test('format error', async () => { expect(stabilizeReport(readJunitReport(ctx!.config.root))).toMatchSnapshot() }) +test('strips ANSI sequences from the failure message attribute', async () => { + const { root } = await runInlineTests( + { + 'ansi.test.ts': /* ts */ ` + import { test } from 'vitest' + + test('ansi', () => { + throw new Error('\\x1b[36m
\\x1b[39m') + }) + `, + }, + { reporters: 'junit' }, + ) + + expect(stabilizeReport(readJunitReport(root))).toMatchInlineSnapshot(` + " +