[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(reporter): use default error formatter for JUnit (#5629)

authored by

Hiroshi Ogawa and committed by
GitHub
(Apr 29, 2024, 1:22 PM +0200) 200609cc eeaebff1

+188 -390
+49
test/reporters/fixtures/error.test.ts
··· 1 + import { afterAll, it, expect } from "vitest"; 2 + 3 + afterAll(() => { 4 + throwSuite() 5 + }) 6 + 7 + it('stack', () => { 8 + throwDeep() 9 + }) 10 + 11 + it('diff', () => { 12 + expect({ hello: 'x' }).toEqual({ hello: 'y' }) 13 + }) 14 + 15 + it('unhandled', () => { 16 + (async () => throwSimple())() 17 + }) 18 + 19 + it('no name object', () => { 20 + throw { noName: 'hi' }; 21 + }); 22 + 23 + it('string', () => { 24 + throw "hi"; 25 + }); 26 + 27 + it('number', () => { 28 + throw 1234; 29 + }); 30 + 31 + it('number name object', () => { 32 + throw { name: 1234 }; 33 + }); 34 + 35 + it('xml', () => { 36 + throw new Error('error message that has XML in it <div><input/></div>'); 37 + }) 38 + 39 + function throwDeep() { 40 + throwSimple() 41 + } 42 + 43 + function throwSimple() { 44 + throw new Error('throwSimple') 45 + } 46 + 47 + function throwSuite() { 48 + throw new Error('throwSuite') 49 + }
-63
test/reporters/src/data-for-junit.ts
··· 1 - import { AssertionError } from 'node:assert' 2 - import type { File, Suite, Task } from 'vitest' 3 - 4 - function createSuiteHavingFailedTestWithXmlInError(): File[] { 5 - const file: File = { 6 - id: '1223128da3', 7 - name: 'test/core/test/basic.test.ts', 8 - type: 'suite', 9 - meta: {}, 10 - mode: 'run', 11 - filepath: '/vitest/test/core/test/basic.test.ts', 12 - result: { state: 'fail', duration: 145.99284195899963 }, 13 - tasks: [], 14 - projectName: '', 15 - } 16 - 17 - const suite: Suite = { 18 - id: '', 19 - type: 'suite', 20 - name: 'suite', 21 - mode: 'run', 22 - meta: {}, 23 - file, 24 - result: { state: 'pass', duration: 1.90183687210083 }, 25 - tasks: [], 26 - projectName: '', 27 - } 28 - 29 - const errorWithXml = new AssertionError({ 30 - message: 'error message that has XML in it <tag>', 31 - }) 32 - 33 - errorWithXml.stack = 'Error: error message that has XML in it <tag>\n' 34 - + ' at /vitest/test/core/test/basic.test.ts:8:32\n' 35 - + ' at /vitest/test/core/test/<bracket-name>.ts:3:11\n' 36 - + ' at etc....' 37 - 38 - const tasks: Task[] = [ 39 - { 40 - id: '123_0', 41 - type: 'test', 42 - name: 'test with xml in error', 43 - mode: 'run', 44 - meta: {}, 45 - suite, 46 - fails: undefined, 47 - file, 48 - result: { 49 - state: 'fail', 50 - errors: [errorWithXml], 51 - duration: 2.123123123, 52 - }, 53 - context: null as any, 54 - }, 55 - ] 56 - 57 - file.tasks = [suite] 58 - suite.tasks = tasks 59 - 60 - return [file] 61 - } 62 - 63 - export { createSuiteHavingFailedTestWithXmlInError }
+5
test/reporters/tests/junit.test.ts
··· 57 57 expect(xml).toMatchSnapshot() 58 58 }) 59 59 60 + test('format error', async () => { 61 + const { stdout } = await runVitest({ reporters: 'junit', root }, ['error.test.ts']) 62 + expect(stabilizeReport(stdout)).toMatchSnapshot() 63 + }) 64 + 60 65 test('write testsuite name relative to root config', async () => { 61 66 const { stdout } = await runVitest({ reporters: 'junit', root: './fixtures/better-testsuite-name' }) 62 67
+16 -75
test/reporters/tests/reporters.spec.ts
··· 1 1 import { existsSync, readFileSync, rmSync } from 'node:fs' 2 - import { afterEach, expect, test, vi } from 'vitest' 2 + import { beforeEach, expect, test, vi } from 'vitest' 3 3 import { normalize, resolve } from 'pathe' 4 4 import { JsonReporter } from '../../../packages/vitest/src/node/reporters/json' 5 5 import { JUnitReporter } from '../../../packages/vitest/src/node/reporters/junit' ··· 7 7 import { TapFlatReporter } from '../../../packages/vitest/src/node/reporters/tap-flat' 8 8 import { getContext } from '../src/context' 9 9 import { files } from '../src/data' 10 - import { createSuiteHavingFailedTestWithXmlInError } from '../src/data-for-junit' 11 10 12 - afterEach(() => { 13 - vi.useRealTimers() 11 + vi.mock('os', () => ({ 12 + hostname: () => 'hostname', 13 + })) 14 + 15 + beforeEach(() => { 16 + vi.setSystemTime(1642587001759) 17 + return () => { 18 + vi.useRealTimers() 19 + } 14 20 }) 15 21 16 22 test('tap reporter', async () => { ··· 44 50 const reporter = new JUnitReporter({}) 45 51 const context = getContext() 46 52 47 - vi.mock('os', () => ({ 48 - hostname: () => 'hostname', 49 - })) 50 - 51 - vi.setSystemTime(1642587001759) 52 - 53 53 // Act 54 54 await reporter.onInit(context.vitest) 55 - await reporter.onFinished(files) 55 + await reporter.onFinished([]) 56 56 57 57 // Assert 58 58 expect(context.output).toMatchSnapshot() ··· 64 64 const context = getContext() 65 65 context.vitest.config.outputFile = {} 66 66 67 - vi.mock('os', () => ({ 68 - hostname: () => 'hostname', 69 - })) 70 - 71 - vi.setSystemTime(1642587001759) 72 - 73 67 // Act 74 68 await reporter.onInit(context.vitest) 75 - await reporter.onFinished(files) 69 + await reporter.onFinished([]) 76 70 77 71 // Assert 78 72 expect(context.output).toMatchSnapshot() ··· 85 79 const context = getContext() 86 80 context.vitest.config.outputFile = outputFile 87 81 88 - vi.mock('os', () => ({ 89 - hostname: () => 'hostname', 90 - })) 91 - 92 - vi.setSystemTime(1642587001759) 93 - 94 82 // Act 95 83 await reporter.onInit(context.vitest) 96 - await reporter.onFinished(files) 97 - 98 - // Assert 99 - expect(normalizeCwd(context.output)).toMatchSnapshot() 100 - expect(existsSync(outputFile)).toBe(true) 101 - expect(readFileSync(outputFile, 'utf8')).toMatchSnapshot() 102 - 103 - // Cleanup 104 - rmSync(outputFile) 105 - }) 106 - 107 - test('JUnit reporter with outputFile with XML in error message', async () => { 108 - // Arrange 109 - const reporter = new JUnitReporter({}) 110 - const outputFile = resolve('report_escape_msg_xml.xml') 111 - const context = getContext() 112 - context.vitest.config.outputFile = outputFile 113 - 114 - vi.mock('os', () => ({ 115 - hostname: () => 'hostname', 116 - })) 117 - 118 - vi.setSystemTime(1642587001759) 119 - 120 - // setup suite with failed test with xml 121 - const filesWithTestHavingXmlInError = createSuiteHavingFailedTestWithXmlInError() 122 - 123 - // Act 124 - await reporter.onInit(context.vitest) 125 - await reporter.onFinished(filesWithTestHavingXmlInError) 84 + await reporter.onFinished([]) 126 85 127 86 // Assert 128 87 expect(normalizeCwd(context.output)).toMatchSnapshot() ··· 142 101 junit: outputFile, 143 102 } 144 103 145 - vi.mock('os', () => ({ 146 - hostname: () => 'hostname', 147 - })) 148 - 149 - vi.setSystemTime(1642587001759) 150 - 151 104 // Act 152 105 await reporter.onInit(context.vitest) 153 - await reporter.onFinished(files) 106 + await reporter.onFinished([]) 154 107 155 108 // Assert 156 109 expect(normalizeCwd(context.output)).toMatchSnapshot() ··· 169 122 const context = getContext() 170 123 context.vitest.config.outputFile = outputFile 171 124 172 - vi.mock('os', () => ({ 173 - hostname: () => 'hostname', 174 - })) 175 - 176 - vi.setSystemTime(1642587001759) 177 - 178 125 // Act 179 126 await reporter.onInit(context.vitest) 180 - await reporter.onFinished(files) 127 + await reporter.onFinished([]) 181 128 182 129 // Assert 183 130 expect(normalizeCwd(context.output)).toMatchSnapshot() ··· 198 145 junit: outputFile, 199 146 } 200 147 201 - vi.mock('os', () => ({ 202 - hostname: () => 'hostname', 203 - })) 204 - 205 - vi.setSystemTime(1642587001759) 206 - 207 148 // Act 208 149 await reporter.onInit(context.vitest) 209 - await reporter.onFinished(files) 150 + await reporter.onFinished([]) 210 151 211 152 // Assert 212 153 expect(normalizeCwd(context.output)).toMatchSnapshot()
+22 -1
packages/vitest/src/node/error.ts
··· 1 1 /* eslint-disable prefer-template */ 2 2 import { existsSync, readFileSync } from 'node:fs' 3 + import { Writable } from 'node:stream' 3 4 import { normalize, relative } from 'pathe' 4 5 import c from 'picocolors' 5 6 import cliTruncate from 'cli-truncate' ··· 13 14 import { isPrimitive } from '../utils' 14 15 import type { Vitest } from './core' 15 16 import { divider } from './reporters/renderers/utils' 16 - import type { Logger } from './logger' 17 + import { Logger } from './logger' 17 18 import type { WorkspaceProject } from './workspace' 18 19 19 20 interface PrintErrorOptions { ··· 25 26 26 27 interface PrintErrorResult { 27 28 nearest?: ParsedStack 29 + } 30 + 31 + // use Logger with custom Console to capture entire error printing 32 + export async function captuerPrintError( 33 + error: unknown, 34 + ctx: Vitest, 35 + project: WorkspaceProject, 36 + ) { 37 + let output = '' 38 + const writable = new Writable({ 39 + write(chunk, _encoding, callback) { 40 + output += String(chunk) 41 + callback() 42 + }, 43 + }) 44 + const result = await printError(error, project, { 45 + showCodeFrame: false, 46 + logger: new Logger(ctx, writable, writable), 47 + }) 48 + return { nearest: result?.nearest, output } 28 49 } 29 50 30 51 export async function printError(error: unknown, project: WorkspaceProject | undefined, options: PrintErrorOptions): Promise<PrintErrorResult | undefined> {
+80
test/reporters/tests/__snapshots__/junit.test.ts.snap
··· 34 34 </testsuites> 35 35 " 36 36 `; 37 + 38 + exports[`format error 1`] = ` 39 + "<?xml version="1.0" encoding="UTF-8" ?> 40 + <testsuites name="vitest tests" tests="9" failures="8" errors="0" time="..."> 41 + <testsuite name="error.test.ts" timestamp="..." hostname="..." tests="9" failures="8" errors="0" skipped="0" time="..."> 42 + <testcase classname="error.test.ts" name="stack" time="..."> 43 + <failure message="throwSimple" type="Error"> 44 + Error: throwSimple 45 + ❯ throwSimple error.test.ts:44:9 46 + ❯ throwDeep error.test.ts:40:3 47 + ❯ error.test.ts:8:3 48 + </failure> 49 + </testcase> 50 + <testcase classname="error.test.ts" name="diff" time="..."> 51 + <failure message="expected { hello: &apos;x&apos; } to deeply equal { hello: &apos;y&apos; }" type="AssertionError"> 52 + AssertionError: expected { hello: &apos;x&apos; } to deeply equal { hello: &apos;y&apos; } 53 + 54 + - Expected 55 + + Received 56 + 57 + Object { 58 + - &quot;hello&quot;: &quot;y&quot;, 59 + + &quot;hello&quot;: &quot;x&quot;, 60 + } 61 + 62 + ❯ error.test.ts:12:26 63 + </failure> 64 + </testcase> 65 + <testcase classname="error.test.ts" name="unhandled" time="..."> 66 + </testcase> 67 + <testcase classname="error.test.ts" name="no name object" time="..."> 68 + <failure> 69 + { 70 + noName: &apos;hi&apos;, 71 + expected: &apos;undefined&apos;, 72 + actual: &apos;undefined&apos;, 73 + stacks: [] 74 + } 75 + ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ 76 + Serialized Error: { noName: &apos;hi&apos; } 77 + </failure> 78 + </testcase> 79 + <testcase classname="error.test.ts" name="string" time="..."> 80 + <failure message="hi"> 81 + Unknown Error: hi 82 + </failure> 83 + </testcase> 84 + <testcase classname="error.test.ts" name="number" time="..."> 85 + <failure message="1234"> 86 + Unknown Error: 1234 87 + </failure> 88 + </testcase> 89 + <testcase classname="error.test.ts" name="number name object" time="..."> 90 + <failure type="1234"> 91 + { 92 + name: 1234, 93 + nameStr: &apos;1234&apos;, 94 + expected: &apos;undefined&apos;, 95 + actual: &apos;undefined&apos;, 96 + stacks: [] 97 + } 98 + </failure> 99 + </testcase> 100 + <testcase classname="error.test.ts" name="xml" time="..."> 101 + <failure message="error message that has XML in it &lt;div&gt;&lt;input/&gt;&lt;/div&gt;" type="Error"> 102 + Error: error message that has XML in it &lt;div&gt;&lt;input/&gt;&lt;/div&gt; 103 + ❯ error.test.ts:36:9 104 + </failure> 105 + </testcase> 106 + <testcase classname="error.test.ts" name="error.test.ts" time="..."> 107 + <failure message="throwSuite" type="Error"> 108 + Error: throwSuite 109 + ❯ throwSuite error.test.ts:48:9 110 + ❯ error.test.ts:4:3 111 + </failure> 112 + </testcase> 113 + </testsuite> 114 + </testsuites> 115 + " 116 + `;
+6 -201
test/reporters/tests/__snapshots__/reporters.spec.ts.snap
··· 2 2 3 3 exports[`JUnit reporter (no outputFile entry) 1`] = ` 4 4 "<?xml version="1.0" encoding="UTF-8" ?> 5 - <testsuites name="vitest tests" tests="9" failures="1" errors="0" time="0"> 6 - <testsuite name="test/core/test/basic.test.ts" timestamp="2022-01-19T10:10:01.759Z" hostname="hostname" tests="9" failures="1" errors="0" skipped="2" time="0.145992842"> 7 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; inner suite &gt; Math.sqrt()" time="0.001442286"> 8 - <failure message="expected 2.23606797749979 to equal 2" type="AssertionError"> 9 - AssertionError: expected 2.23606797749979 to equal 2 10 - ❯ test/core/test/basic.test.ts:8:32 11 - </failure> 12 - </testcase> 13 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; JSON" time="0.001023711"> 14 - </testcase> 15 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; async with timeout" time="0"> 16 - <skipped/> 17 - </testcase> 18 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; timeout" time="0.1005059841"> 19 - </testcase> 20 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success " time="0.020184875"> 21 - </testcase> 22 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success " time="0.0003324542"> 23 - </testcase> 24 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success done(false)" time="0.019738606"> 25 - </testcase> 26 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success done(false)" time="0.0001923509"> 27 - <system-err> 28 - [33merror[39m 29 - </system-err> 30 - </testcase> 31 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; todo test" time="0"> 32 - <skipped/> 33 - </testcase> 34 - </testsuite> 5 + <testsuites name="vitest tests" tests="0" failures="0" errors="0" time="0"> 35 6 </testsuites> 36 7 " 37 8 `; 38 9 39 10 exports[`JUnit reporter 1`] = ` 40 11 "<?xml version="1.0" encoding="UTF-8" ?> 41 - <testsuites name="vitest tests" tests="9" failures="1" errors="0" time="0"> 42 - <testsuite name="test/core/test/basic.test.ts" timestamp="2022-01-19T10:10:01.759Z" hostname="hostname" tests="9" failures="1" errors="0" skipped="2" time="0.145992842"> 43 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; inner suite &gt; Math.sqrt()" time="0.001442286"> 44 - <failure message="expected 2.23606797749979 to equal 2" type="AssertionError"> 45 - AssertionError: expected 2.23606797749979 to equal 2 46 - ❯ test/core/test/basic.test.ts:8:32 47 - </failure> 48 - </testcase> 49 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; JSON" time="0.001023711"> 50 - </testcase> 51 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; async with timeout" time="0"> 52 - <skipped/> 53 - </testcase> 54 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; timeout" time="0.1005059841"> 55 - </testcase> 56 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success " time="0.020184875"> 57 - </testcase> 58 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success " time="0.0003324542"> 59 - </testcase> 60 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success done(false)" time="0.019738606"> 61 - </testcase> 62 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success done(false)" time="0.0001923509"> 63 - <system-err> 64 - [33merror[39m 65 - </system-err> 66 - </testcase> 67 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; todo test" time="0"> 68 - <skipped/> 69 - </testcase> 70 - </testsuite> 12 + <testsuites name="vitest tests" tests="0" failures="0" errors="0" time="0"> 71 13 </testsuites> 72 14 " 73 15 `; ··· 79 21 80 22 exports[`JUnit reporter with outputFile 2`] = ` 81 23 "<?xml version="1.0" encoding="UTF-8" ?> 82 - <testsuites name="vitest tests" tests="9" failures="1" errors="0" time="0"> 83 - <testsuite name="test/core/test/basic.test.ts" timestamp="2022-01-19T10:10:01.759Z" hostname="hostname" tests="9" failures="1" errors="0" skipped="2" time="0.145992842"> 84 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; inner suite &gt; Math.sqrt()" time="0.001442286"> 85 - <failure message="expected 2.23606797749979 to equal 2" type="AssertionError"> 86 - AssertionError: expected 2.23606797749979 to equal 2 87 - ❯ test/core/test/basic.test.ts:8:32 88 - </failure> 89 - </testcase> 90 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; JSON" time="0.001023711"> 91 - </testcase> 92 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; async with timeout" time="0"> 93 - <skipped/> 94 - </testcase> 95 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; timeout" time="0.1005059841"> 96 - </testcase> 97 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success " time="0.020184875"> 98 - </testcase> 99 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success " time="0.0003324542"> 100 - </testcase> 101 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success done(false)" time="0.019738606"> 102 - </testcase> 103 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success done(false)" time="0.0001923509"> 104 - <system-err> 105 - [33merror[39m 106 - </system-err> 107 - </testcase> 108 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; todo test" time="0"> 109 - <skipped/> 110 - </testcase> 111 - </testsuite> 24 + <testsuites name="vitest tests" tests="0" failures="0" errors="0" time="0"> 112 25 </testsuites> 113 26 " 114 27 `; ··· 120 33 121 34 exports[`JUnit reporter with outputFile in non-existing directory 2`] = ` 122 35 "<?xml version="1.0" encoding="UTF-8" ?> 123 - <testsuites name="vitest tests" tests="9" failures="1" errors="0" time="0"> 124 - <testsuite name="test/core/test/basic.test.ts" timestamp="2022-01-19T10:10:01.759Z" hostname="hostname" tests="9" failures="1" errors="0" skipped="2" time="0.145992842"> 125 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; inner suite &gt; Math.sqrt()" time="0.001442286"> 126 - <failure message="expected 2.23606797749979 to equal 2" type="AssertionError"> 127 - AssertionError: expected 2.23606797749979 to equal 2 128 - ❯ test/core/test/basic.test.ts:8:32 129 - </failure> 130 - </testcase> 131 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; JSON" time="0.001023711"> 132 - </testcase> 133 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; async with timeout" time="0"> 134 - <skipped/> 135 - </testcase> 136 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; timeout" time="0.1005059841"> 137 - </testcase> 138 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success " time="0.020184875"> 139 - </testcase> 140 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success " time="0.0003324542"> 141 - </testcase> 142 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success done(false)" time="0.019738606"> 143 - </testcase> 144 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success done(false)" time="0.0001923509"> 145 - <system-err> 146 - [33merror[39m 147 - </system-err> 148 - </testcase> 149 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; todo test" time="0"> 150 - <skipped/> 151 - </testcase> 152 - </testsuite> 36 + <testsuites name="vitest tests" tests="0" failures="0" errors="0" time="0"> 153 37 </testsuites> 154 38 " 155 39 `; ··· 161 45 162 46 exports[`JUnit reporter with outputFile object 2`] = ` 163 47 "<?xml version="1.0" encoding="UTF-8" ?> 164 - <testsuites name="vitest tests" tests="9" failures="1" errors="0" time="0"> 165 - <testsuite name="test/core/test/basic.test.ts" timestamp="2022-01-19T10:10:01.759Z" hostname="hostname" tests="9" failures="1" errors="0" skipped="2" time="0.145992842"> 166 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; inner suite &gt; Math.sqrt()" time="0.001442286"> 167 - <failure message="expected 2.23606797749979 to equal 2" type="AssertionError"> 168 - AssertionError: expected 2.23606797749979 to equal 2 169 - ❯ test/core/test/basic.test.ts:8:32 170 - </failure> 171 - </testcase> 172 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; JSON" time="0.001023711"> 173 - </testcase> 174 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; async with timeout" time="0"> 175 - <skipped/> 176 - </testcase> 177 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; timeout" time="0.1005059841"> 178 - </testcase> 179 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success " time="0.020184875"> 180 - </testcase> 181 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success " time="0.0003324542"> 182 - </testcase> 183 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success done(false)" time="0.019738606"> 184 - </testcase> 185 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success done(false)" time="0.0001923509"> 186 - <system-err> 187 - [33merror[39m 188 - </system-err> 189 - </testcase> 190 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; todo test" time="0"> 191 - <skipped/> 192 - </testcase> 193 - </testsuite> 48 + <testsuites name="vitest tests" tests="0" failures="0" errors="0" time="0"> 194 49 </testsuites> 195 50 " 196 51 `; ··· 202 57 203 58 exports[`JUnit reporter with outputFile object in non-existing directory 2`] = ` 204 59 "<?xml version="1.0" encoding="UTF-8" ?> 205 - <testsuites name="vitest tests" tests="9" failures="1" errors="0" time="0"> 206 - <testsuite name="test/core/test/basic.test.ts" timestamp="2022-01-19T10:10:01.759Z" hostname="hostname" tests="9" failures="1" errors="0" skipped="2" time="0.145992842"> 207 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; inner suite &gt; Math.sqrt()" time="0.001442286"> 208 - <failure message="expected 2.23606797749979 to equal 2" type="AssertionError"> 209 - AssertionError: expected 2.23606797749979 to equal 2 210 - ❯ test/core/test/basic.test.ts:8:32 211 - </failure> 212 - </testcase> 213 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; JSON" time="0.001023711"> 214 - </testcase> 215 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; async with timeout" time="0"> 216 - <skipped/> 217 - </testcase> 218 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; timeout" time="0.1005059841"> 219 - </testcase> 220 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success " time="0.020184875"> 221 - </testcase> 222 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success " time="0.0003324542"> 223 - </testcase> 224 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback setup success done(false)" time="0.019738606"> 225 - </testcase> 226 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; callback test success done(false)" time="0.0001923509"> 227 - <system-err> 228 - [33merror[39m 229 - </system-err> 230 - </testcase> 231 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; todo test" time="0"> 232 - <skipped/> 233 - </testcase> 234 - </testsuite> 235 - </testsuites> 236 - " 237 - `; 238 - 239 - exports[`JUnit reporter with outputFile with XML in error message 1`] = ` 240 - "JUNIT report written to <process-cwd>/report_escape_msg_xml.xml 241 - " 242 - `; 243 - 244 - exports[`JUnit reporter with outputFile with XML in error message 2`] = ` 245 - "<?xml version="1.0" encoding="UTF-8" ?> 246 - <testsuites name="vitest tests" tests="1" failures="1" errors="0" time="0"> 247 - <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"> 248 - <testcase classname="test/core/test/basic.test.ts" name="suite &gt; test with xml in error" time="0.0021231231"> 249 - <failure message="error message that has XML in it &lt;tag&gt;" type="AssertionError"> 250 - AssertionError: error message that has XML in it &lt;tag&gt; 251 - ❯ test/core/test/basic.test.ts:8:32 252 - ❯ test/core/test/&lt;bracket-name&gt;.ts:3:11 253 - </failure> 254 - </testcase> 255 - </testsuite> 60 + <testsuites name="vitest tests" tests="0" failures="0" errors="0" time="0"> 256 61 </testsuites> 257 62 " 258 63 `;
+2 -21
packages/vitest/src/node/reporters/github-actions.ts
··· 1 - import { Writable } from 'node:stream' 2 1 import { getTasks } from '@vitest/runner/utils' 3 2 import stripAnsi from 'strip-ansi' 4 3 import type { File, Reporter, Vitest } from '../../types' 5 4 import { getFullName } from '../../utils' 6 - import { printError } from '../error' 7 - import { Logger } from '../logger' 5 + import { captuerPrintError } from '../error' 8 6 import type { WorkspaceProject } from '../workspace' 9 7 10 8 export class GithubActionsReporter implements Reporter { ··· 44 42 45 43 // format errors via `printError` 46 44 for (const { project, title, error } of projectErrors) { 47 - const result = await printErrorWrapper(error, this.ctx, project) 45 + const result = await captuerPrintError(error, this.ctx, project) 48 46 const stack = result?.nearest 49 47 if (!stack) 50 48 continue ··· 61 59 this.ctx.logger.log(`\n${formatted}`) 62 60 } 63 61 } 64 - } 65 - 66 - // use Logger with custom Console to extract messgage from `processError` util 67 - // TODO: maybe refactor `processError` to require single function `(message: string) => void` instead of full Logger? 68 - async function printErrorWrapper(error: unknown, ctx: Vitest, project: WorkspaceProject) { 69 - let output = '' 70 - const writable = new Writable({ 71 - write(chunk, _encoding, callback) { 72 - output += String(chunk) 73 - callback() 74 - }, 75 - }) 76 - const result = await printError(error, project, { 77 - showCodeFrame: false, 78 - logger: new Logger(ctx, writable, writable), 79 - }) 80 - return { nearest: result?.nearest, output } 81 62 } 82 63 83 64 // workflow command formatting based on
+8 -29
packages/vitest/src/node/reporters/junit.ts
··· 3 3 import { dirname, relative, resolve } from 'pathe' 4 4 5 5 import type { Task } from '@vitest/runner' 6 - import type { ErrorWithDiff } from '@vitest/utils' 7 6 import { getSuites } from '@vitest/runner/utils' 7 + import stripAnsi from 'strip-ansi' 8 8 import type { Vitest } from '../../node' 9 9 import type { Reporter } from '../../types/reporter' 10 - import { parseErrorStacktrace } from '../../utils/source-map' 11 - import { F_POINTER } from '../../utils/figures' 12 10 import { getOutputFile } from '../../utils/config-helpers' 11 + import { captuerPrintError } from '../error' 13 12 import { IndentedLogger } from './renderers/indented-logger' 14 13 15 14 export interface JUnitOptions { ··· 140 139 await this.logger.log(`</${name}>`) 141 140 } 142 141 143 - async writeErrorDetails(task: Task, error: ErrorWithDiff): Promise<void> { 144 - const errorName = error.name ?? error.nameStr ?? 'Unknown Error' 145 - const errorDetails = `${errorName}: ${error.message}` 146 - 147 - // Be sure to escape any XML in the error Details 148 - await this.baseLog(escapeXML(errorDetails)) 149 - 150 - const project = this.ctx.getProjectByTaskId(task.id) 151 - const stack = parseErrorStacktrace(error, { 152 - getSourceMap: file => project.getBrowserSourceMapModuleById(file), 153 - frameFilter: this.ctx.config.onStackTrace, 154 - }) 155 - 156 - // TODO: This is same as printStack but without colors. Find a way to reuse code. 157 - for (const frame of stack) { 158 - const path = relative(this.ctx.config.root, frame.file) 159 - 160 - await this.baseLog(escapeXML(` ${F_POINTER} ${[frame.method, `${path}:${frame.line}:${frame.column}`].filter(Boolean).join(' ')}`)) 161 - 162 - // reached at test file, skip the follow stack 163 - if (frame.file in this.ctx.state.filesMap) 164 - break 165 - } 166 - } 167 - 168 142 async writeLogs(task: Task, type: 'err' | 'out'): Promise<void> { 169 143 if (task.logs == null || task.logs.length === 0) 170 144 return ··· 205 179 if (!error) 206 180 return 207 181 208 - await this.writeErrorDetails(task, error) 182 + const result = await captuerPrintError( 183 + error, 184 + this.ctx, 185 + this.ctx.getProjectByTaskId(task.id), 186 + ) 187 + await this.baseLog(escapeXML(stripAnsi(result.output.trim()))) 209 188 }) 210 189 } 211 190 }