1- import type { Task , TestAttachment } from '@vitest/runner'
21import type { ModuleGraphData , RunnerTestFile , SerializedConfig } from 'vitest'
32import type { HTMLOptions , Reporter , Vitest } from 'vitest/node'
4- import crypto from 'node:crypto'
5- import { promises as fs } from 'node:fs'
6- import { readFile , writeFile } from 'node:fs/promises'
3+ import { existsSync , promises as fs } from 'node:fs'
74import { fileURLToPath } from 'node:url'
85import { promisify } from 'node:util'
96import { gzip , constants as zlibConstants } from 'node:zlib'
107import { stringify } from 'flatted'
11- import mime from 'mime/lite'
12- import { dirname , extname , relative , resolve } from 'pathe'
8+ import { dirname , relative , resolve } from 'pathe'
139import { globSync } from 'tinyglobby'
1410import c from 'tinyrainbow'
1511import { getModuleGraph } from '../../vitest/src/utils/graph'
@@ -66,7 +62,6 @@ export default class HTMLReporter implements Reporter {
6662 this . reporterDir = dirname ( htmlFilePath )
6763 this . htmlFilePath = htmlFilePath
6864
69- await fs . mkdir ( resolve ( this . reporterDir , 'data' ) , { recursive : true } )
7065 await fs . mkdir ( resolve ( this . reporterDir , 'assets' ) , { recursive : true } )
7166 }
7267
@@ -82,30 +77,7 @@ export default class HTMLReporter implements Reporter {
8277 }
8378 const promises : Promise < void > [ ] = [ ]
8479
85- const processAttachments = ( task : Task ) => {
86- if ( task . type === 'test' ) {
87- task . annotations . forEach ( ( annotation ) => {
88- const attachment = annotation . attachment
89- if ( attachment ) {
90- promises . push ( this . processAttachment ( attachment ) )
91- }
92- } )
93- task . artifacts . forEach ( ( artifact ) => {
94- const attachments = artifact . attachments
95- if ( attachments ) {
96- attachments . forEach ( ( attachment ) => {
97- promises . push ( this . processAttachment ( attachment ) )
98- } )
99- }
100- } )
101- }
102- else {
103- task . tasks . forEach ( processAttachments )
104- }
105- }
106-
10780 promises . push ( ...result . files . map ( async ( file ) => {
108- processAttachments ( file )
10981 const projectName = file . projectName || ''
11082 const resolvedConfig = this . ctx . getProjectByName ( projectName ) . config
11183 const browser = resolvedConfig . browser . enabled
@@ -132,42 +104,6 @@ export default class HTMLReporter implements Reporter {
132104 await this . writeReport ( stringify ( result ) )
133105 }
134106
135- async processAttachment ( attachment : TestAttachment ) : Promise < void > {
136- if ( attachment . path ) {
137- // keep external resource as is, but remove body if it's set somehow
138- if (
139- attachment . path . startsWith ( 'http://' )
140- || attachment . path . startsWith ( 'https://' )
141- ) {
142- attachment . body = undefined
143- return
144- }
145-
146- const buffer = await readFile ( attachment . path )
147- const hash = crypto . createHash ( 'sha1' ) . update ( buffer ) . digest ( 'hex' )
148- const filename = hash + extname ( attachment . path )
149- // move the file into an html directory to make access/publishing UI easier
150- await writeFile ( resolve ( this . reporterDir , 'data' , filename ) , buffer )
151- attachment . path = filename
152- attachment . body = undefined
153- return
154- }
155-
156- if ( attachment . body ) {
157- const buffer = typeof attachment . body === 'string'
158- ? Buffer . from ( attachment . body , 'base64' )
159- : Buffer . from ( attachment . body )
160-
161- const hash = crypto . createHash ( 'sha1' ) . update ( buffer ) . digest ( 'hex' )
162- const extension = mime . getExtension ( attachment . contentType || 'application/octet-stream' ) || 'dat'
163- const filename = `${ hash } .${ extension } `
164- // store the file in html directory instead of passing down as a body
165- await writeFile ( resolve ( this . reporterDir , 'data' , filename ) , buffer )
166- attachment . path = filename
167- attachment . body = undefined
168- }
169- }
170-
171107 async writeReport ( report : string ) : Promise < void > {
172108 const metaFile = resolve ( this . reporterDir , 'html.meta.json.gz' )
173109
@@ -198,6 +134,15 @@ export default class HTMLReporter implements Reporter {
198134 } ) ,
199135 )
200136
137+ // copy attachments
138+ // TODO: unify attachmentsDir and html outputFile, so both live together without extra copy
139+ if ( existsSync ( this . ctx . config . attachmentsDir ) ) {
140+ const destAttachmentsDir = resolve ( this . reporterDir , 'data' )
141+ await fs . rm ( destAttachmentsDir , { recursive : true , force : true } )
142+ await fs . mkdir ( destAttachmentsDir , { recursive : true } )
143+ await fs . cp ( this . ctx . config . attachmentsDir , destAttachmentsDir , { recursive : true } )
144+ }
145+
201146 this . ctx . logger . log (
202147 `${ c . bold ( c . inverse ( c . magenta ( ' HTML ' ) ) ) } ${ c . magenta (
203148 'Report is generated' ,
0 commit comments