1+ import type { File , Test } from '@vitest/runner/types'
2+ import { rmSync } from 'node:fs'
13import { resolve } from 'node:path'
2- import { expect , test } from 'vitest'
4+ import { createFileTask } from '@vitest/runner/utils'
5+ import { beforeEach , expect , test } from 'vitest'
6+ import { version } from 'vitest/package.json'
7+ import { writeBlob } from 'vitest/src/node/reporters/blob.js'
38import { runVitest } from '../../test-utils'
49
10+ // always relative to CWD because it's used only from the CLI,
11+ // so we need to correctly resolve it here
12+ const reportsDir = resolve ( './fixtures/merge-reports/.vitest-reports' )
13+
14+ beforeEach ( ( ) => {
15+ rmSync ( reportsDir , { force : true , recursive : true } )
16+ } )
17+
518test ( 'merge reports' , async ( ) => {
619 await runVitest ( {
720 root : './fixtures/merge-reports' ,
821 include : [ 'first.test.ts' ] ,
922 reporters : [ [ 'blob' , { outputFile : './.vitest-reports/first-run.json' } ] ] ,
1023 } )
24+
1125 await runVitest ( {
1226 root : './fixtures/merge-reports' ,
1327 include : [ 'second.test.ts' ] ,
1428 reporters : [ [ 'blob' , { outputFile : './.vitest-reports/second-run.json' } ] ] ,
1529 } )
1630
17- // always relative to CWD because it's used only from the CLI,
18- // so we need to correctly resolve it here
19- const mergeReports = resolve ( './fixtures/merge-reports/.vitest-reports' )
20-
2131 const { stdout : reporterDefault , stderr : stderrDefault , exitCode } = await runVitest ( {
2232 root : './fixtures/merge-reports' ,
23- mergeReports,
33+ mergeReports : reportsDir ,
2434 reporters : [ [ 'default' , { isTTY : false } ] ] ,
2535 } )
2636
2737 expect ( exitCode ) . toBe ( 1 )
2838
29- // remove "RUN v{} path" and "Duration" because it's not stable
30- const stdoutCheck = reporterDefault
31- . split ( '\n' )
32- . slice ( 2 , - 3 )
33- . join ( '\n' )
34- . replace ( / S t a r t a t [ \w \s : ] + / , 'Start at <time>' )
39+ const stdoutCheck = trimReporterOutput ( reporterDefault )
3540 const stderrArr = stderrDefault . split ( '\n' )
3641 const stderrCheck = [
3742 ...stderrArr . slice ( 4 , 19 ) ,
@@ -76,9 +81,8 @@ test('merge reports', async () => {
7681 "
7782 ` )
7883
79- expect ( stdoutCheck . replace ( / \d + m s / g, '<time>' ) ) . toMatchInlineSnapshot ( `
80- "
81- stdout | first.test.ts
84+ expect ( stdoutCheck ) . toMatchInlineSnapshot ( `
85+ "stdout | first.test.ts
8286 global scope
8387
8488 stdout | first.test.ts > test 1-1
@@ -105,12 +109,13 @@ test('merge reports', async () => {
105109
106110 Test Files 2 failed (2)
107111 Tests 2 failed | 3 passed (5)
108- Start at <time>"
112+ Duration <time> (transform <time>, setup <time>, collect <time>, tests <time>, environment <time>, prepare <time>)
113+ Per blob <time> <time>"
109114 ` )
110115
111116 const { stdout : reporterJson } = await runVitest ( {
112117 root : './fixtures/merge-reports' ,
113- mergeReports,
118+ mergeReports : reportsDir ,
114119 reporters : [ [ 'json' , { outputFile : /** so it outputs into stdout */ null } ] ] ,
115120 } )
116121
@@ -234,3 +239,62 @@ test('merge reports', async () => {
234239 }
235240 ` )
236241} )
242+
243+ test ( 'total and merged execution times are shown' , async ( ) => {
244+ for ( const [ _index , name ] of [ 'first.test.ts' , 'second.test.ts' ] . entries ( ) ) {
245+ const index = 1 + _index
246+ const file = createFileTask (
247+ resolve ( './fixtures/merge-reports' , name ) ,
248+ resolve ( './fixtures/merge-reports' ) ,
249+ '' ,
250+ )
251+ file . tasks . push ( createTest ( 'some test' , file ) )
252+
253+ await writeBlob (
254+ [ version , [ file ] , [ ] , [ ] , undefined , 1500 * index ] ,
255+ resolve ( `./fixtures/merge-reports/.vitest-reports/blob-${ index } -2.json` ) ,
256+ )
257+ }
258+
259+ const { stdout } = await runVitest ( {
260+ root : resolve ( './fixtures/merge-reports' ) ,
261+ mergeReports : resolve ( './fixtures/merge-reports/.vitest-reports' ) ,
262+ reporters : [ [ 'default' , { isTTY : false } ] ] ,
263+ } )
264+
265+ expect ( stdout ) . toContain ( '✓ first.test.ts (1 test)' )
266+ expect ( stdout ) . toContain ( '✓ second.test.ts (1 test)' )
267+
268+ expect ( stdout ) . toContain ( 'Duration 4.50s' )
269+ expect ( stdout ) . toContain ( 'Per blob 1.50s 3.00s' )
270+ } )
271+
272+ function trimReporterOutput ( report : string ) {
273+ const rows = report
274+ . replace ( / \d + m s / g, '<time>' )
275+ . replace ( / \d + \. \d + s / g, '<time>' )
276+ . split ( '\n' )
277+
278+ // Trim start and end, capture just rendered tree
279+ rows . splice ( 0 , 1 + rows . findIndex ( row => row . includes ( 'RUN v' ) ) )
280+ rows . splice ( rows . findIndex ( row => row . includes ( 'Start at' ) ) , 1 )
281+
282+ return rows . join ( '\n' ) . trim ( )
283+ }
284+
285+ function createTest ( name : string , file : File ) : Test {
286+ file . result = { state : 'pass' }
287+
288+ return {
289+ type : 'test' ,
290+ name,
291+ id : `${ file . id } _0` ,
292+ mode : 'run' ,
293+ file,
294+ suite : file ,
295+ timeout : 0 ,
296+ result : { state : 'pass' } ,
297+ meta : { } ,
298+ context : { } as any ,
299+ }
300+ }
0 commit comments