Skip to content

Commit

Permalink
fix(reporter-junit): escape XML when in error message (fix: #1823) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisTowles committed Aug 23, 2022
1 parent 0d7c464 commit b35f42d
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 2 deletions.
5 changes: 4 additions & 1 deletion packages/vitest/src/node/reporters/junit.ts
Expand Up @@ -112,7 +112,10 @@ export class JUnitReporter implements Reporter {

async writeErrorDetails(error: ErrorWithDiff): Promise<void> {
const errorName = error.name ?? error.nameStr ?? 'Unknown Error'
await this.baseLog(`${errorName}: ${error.message}`)
const errorDetails = `${errorName}: ${error.message}`

// Be sure to escape any XML in the error Details
await this.baseLog(escapeXML(errorDetails))

const stack = parseStacktrace(error)

Expand Down
58 changes: 58 additions & 0 deletions test/reporters/src/data-for-junit.ts
@@ -0,0 +1,58 @@
import { AssertionError } from 'assert'
import type { File, Suite, Task } from 'vitest'

function createSuiteHavingFailedTestWithXmlInError(): File[] {
const file: File = {
id: '1223128da3',
name: 'test/core/test/basic.test.ts',
type: 'suite',
mode: 'run',
filepath: '/vitest/test/core/test/basic.test.ts',
result: { state: 'fail', duration: 145.99284195899963 },
tasks: [],
}

const suite: Suite = {
id: '',
type: 'suite',
name: 'suite',
mode: 'run',
file,
result: { state: 'pass', duration: 1.90183687210083 },
tasks: [],
}

const errorWithXml = new AssertionError({
message: 'error message that has XML in it <tag>',
})

errorWithXml.stack = 'Error: error message that has XML in it <tag>\n'
+ ' at /vitest/test/core/test/basic.test.ts:8:32\n'
+ ' at etc....'

const tasks: Task[] = [
{
id: '123_0',
type: 'test',
name: 'test with xml in error',
mode: 'run',
suite,
fails: undefined,
file,
result: {
state: 'fail',
error: errorWithXml,
duration: 2.123123123,
},
context: null as any,
},
]

file.tasks = [suite]
suite.tasks = tasks

return [file]
}

export { createSuiteHavingFailedTestWithXmlInError }

5 changes: 4 additions & 1 deletion test/reporters/src/data.ts
Expand Up @@ -174,4 +174,7 @@ const tasks: Task[] = [
file.tasks = [suite]
suite.tasks = tasks

export const files = [file]
const files = [file]

export { files }

20 changes: 20 additions & 0 deletions test/reporters/tests/__snapshots__/reporters.spec.ts.snap
Expand Up @@ -236,6 +236,26 @@ AssertionError: expected 2.23606797749979 to equal 2
"
`;
exports[`JUnit reporter with outputFile with XML in error message 1`] = `
"JUNIT report written to <process-cwd>/report_escape_msg_xml.xml
"
`;
exports[`JUnit reporter with outputFile with XML in error message 2`] = `
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" ?>
<testsuites>
<testsuite name=\\"test/core/test/basic.test.ts\\" timestamp=\\"2022-01-19T10:10:01.759Z\\" hostname=\\"hostname\\" tests=\\"1\\" failures=\\"1\\" errors=\\"0\\" skipped=\\"0\\" time=\\"0.145992842\\">
<testcase classname=\\"test/core/test/basic.test.ts\\" name=\\"suite &gt; test with xml in error\\" time=\\"0.0021231231\\">
<failure message=\\"error message that has XML in it &lt;tag&gt;\\" type=\\"AssertionError\\">
AssertionError: error message that has XML in it &lt;tag&gt;
vitest/test/core/test/basic.test.ts:8:32
</failure>
</testcase>
</testsuite>
</testsuites>
"
`;
exports[`json reporter (no outputFile entry) 1`] = `
{
"numFailedTestSuites": 0,
Expand Down
30 changes: 30 additions & 0 deletions test/reporters/tests/reporters.spec.ts
Expand Up @@ -7,6 +7,7 @@ import { TapReporter } from '../../../packages/vitest/src/node/reporters/tap'
import { TapFlatReporter } from '../../../packages/vitest/src/node/reporters/tap-flat'
import { getContext } from '../src/context'
import { files } from '../src/data'
import { createSuiteHavingFailedTestWithXmlInError } from '../src/data-for-junit'

afterEach(() => {
vi.useRealTimers()
Expand Down Expand Up @@ -103,6 +104,35 @@ test('JUnit reporter with outputFile', async () => {
rmSync(outputFile)
})

test('JUnit reporter with outputFile with XML in error message', async () => {
// Arrange
const reporter = new JUnitReporter()
const outputFile = resolve('report_escape_msg_xml.xml')
const context = getContext()
context.vitest.config.outputFile = outputFile

vi.mock('os', () => ({
hostname: () => 'hostname',
}))

vi.setSystemTime(1642587001759)

// setup suite with failed test with xml
const filesWithTestHavingXmlInError = createSuiteHavingFailedTestWithXmlInError()

// Act
await reporter.onInit(context.vitest)
await reporter.onFinished(filesWithTestHavingXmlInError)

// Assert
expect(normalizeCwd(context.output)).toMatchSnapshot()
expect(existsSync(outputFile)).toBe(true)
expect(readFileSync(outputFile, 'utf8')).toMatchSnapshot()

// Cleanup
rmSync(outputFile)
})

test('JUnit reporter with outputFile object', async () => {
// Arrange
const reporter = new JUnitReporter()
Expand Down

0 comments on commit b35f42d

Please sign in to comment.