mirror of
https://github.com/vitest-dev/vitest.git
synced 2025-12-08 18:26:03 +00:00
146 lines
4.0 KiB
TypeScript
146 lines
4.0 KiB
TypeScript
import { promises as fs } from 'node:fs'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { promisify } from 'node:util'
|
|
import { gzip, constants as zlibConstants } from 'node:zlib'
|
|
import { basename, dirname, relative, resolve } from 'pathe'
|
|
import { globSync } from 'tinyglobby'
|
|
import c from 'tinyrainbow'
|
|
import { stringify } from 'flatted'
|
|
import type {
|
|
File,
|
|
ModuleGraphData,
|
|
Reporter,
|
|
SerializedConfig,
|
|
Vitest,
|
|
} from 'vitest'
|
|
import type { HTMLOptions } from 'vitest/node'
|
|
import { getModuleGraph } from '../../vitest/src/utils/graph'
|
|
|
|
interface PotentialConfig {
|
|
outputFile?: string | Partial<Record<string, string>>
|
|
}
|
|
|
|
function getOutputFile(config: PotentialConfig | undefined) {
|
|
if (!config?.outputFile) {
|
|
return
|
|
}
|
|
|
|
if (typeof config.outputFile === 'string') {
|
|
return config.outputFile
|
|
}
|
|
|
|
return config.outputFile.html
|
|
}
|
|
|
|
interface HTMLReportData {
|
|
paths: string[]
|
|
files: File[]
|
|
config: SerializedConfig
|
|
moduleGraph: Record<string, Record<string, ModuleGraphData>>
|
|
unhandledErrors: unknown[]
|
|
// filename -> source
|
|
sources: Record<string, string>
|
|
}
|
|
|
|
const distDir = resolve(fileURLToPath(import.meta.url), '../../dist')
|
|
|
|
export default class HTMLReporter implements Reporter {
|
|
start = 0
|
|
ctx!: Vitest
|
|
reportUIPath!: string
|
|
options: HTMLOptions
|
|
|
|
constructor(options: HTMLOptions) {
|
|
this.options = options
|
|
}
|
|
|
|
async onInit(ctx: Vitest) {
|
|
this.ctx = ctx
|
|
this.start = Date.now()
|
|
}
|
|
|
|
async onFinished() {
|
|
const result: HTMLReportData = {
|
|
paths: this.ctx.state.getPaths(),
|
|
files: this.ctx.state.getFiles(),
|
|
config: this.ctx.getCoreWorkspaceProject().getSerializableConfig(),
|
|
unhandledErrors: this.ctx.state.getUnhandledErrors(),
|
|
moduleGraph: {},
|
|
sources: {},
|
|
}
|
|
await Promise.all(
|
|
result.files.map(async (file) => {
|
|
const projectName = file.projectName || ''
|
|
result.moduleGraph[projectName] ??= {}
|
|
result.moduleGraph[projectName][file.filepath] = await getModuleGraph(
|
|
this.ctx as any,
|
|
projectName,
|
|
file.filepath,
|
|
)
|
|
if (!result.sources[file.filepath]) {
|
|
try {
|
|
result.sources[file.filepath] = await fs.readFile(file.filepath, {
|
|
encoding: 'utf-8',
|
|
})
|
|
}
|
|
catch {
|
|
// just ignore
|
|
}
|
|
}
|
|
}),
|
|
)
|
|
await this.writeReport(stringify(result))
|
|
}
|
|
|
|
async writeReport(report: string) {
|
|
const htmlFile
|
|
= this.options.outputFile
|
|
|| getOutputFile(this.ctx.config)
|
|
|| 'html/index.html'
|
|
const htmlFileName = basename(htmlFile)
|
|
const htmlDir = resolve(this.ctx.config.root, dirname(htmlFile))
|
|
|
|
const metaFile = resolve(htmlDir, 'html.meta.json.gz')
|
|
|
|
await fs.mkdir(resolve(htmlDir, 'assets'), { recursive: true })
|
|
|
|
const promiseGzip = promisify(gzip)
|
|
const data = await promiseGzip(report, {
|
|
level: zlibConstants.Z_BEST_COMPRESSION,
|
|
})
|
|
await fs.writeFile(metaFile, data, 'base64')
|
|
const ui = resolve(distDir, 'client')
|
|
// copy ui
|
|
const files = globSync(['**/*'], { cwd: ui, expandDirectories: false })
|
|
await Promise.all(
|
|
files.map(async (f) => {
|
|
if (f === 'index.html') {
|
|
const html = await fs.readFile(resolve(ui, f), 'utf-8')
|
|
const filePath = relative(htmlDir, metaFile)
|
|
await fs.writeFile(
|
|
resolve(htmlDir, htmlFileName),
|
|
html.replace(
|
|
'<!-- !LOAD_METADATA! -->',
|
|
`<script>window.METADATA_PATH="${filePath}"</script>`,
|
|
),
|
|
)
|
|
}
|
|
else {
|
|
await fs.copyFile(resolve(ui, f), resolve(htmlDir, f))
|
|
}
|
|
}),
|
|
)
|
|
|
|
this.ctx.logger.log(
|
|
`${c.bold(c.inverse(c.magenta(' HTML ')))} ${c.magenta(
|
|
'Report is generated',
|
|
)}`,
|
|
)
|
|
this.ctx.logger.log(
|
|
`${c.dim(' You can run ')}${c.bold(
|
|
`npx vite preview --outDir ${relative(this.ctx.config.root, htmlDir)}`,
|
|
)}${c.dim(' to see the test results.')}`,
|
|
)
|
|
}
|
|
}
|