mirror of
https://github.com/vitest-dev/vitest.git
synced 2025-12-08 18:26:03 +00:00
122 lines
3.5 KiB
TypeScript
122 lines
3.5 KiB
TypeScript
import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'
|
|
import { normalize, resolve, sep } from 'node:path'
|
|
import { AfterSuiteRunMeta } from 'vitest'
|
|
import type { CoverageProvider, CoverageProviderModule, ReportContext, ResolvedCoverageOptions, Vitest } from 'vitest/node'
|
|
|
|
const CustomCoverageProviderModule: CoverageProviderModule = {
|
|
getProvider(): CoverageProvider {
|
|
return new CustomCoverageProvider()
|
|
},
|
|
|
|
takeCoverage() {
|
|
// @ts-expect-error -- untyped
|
|
globalThis.CUSTOM_PROVIDER_TAKE_COVERAGE = true
|
|
|
|
// @ts-expect-error -- untyped
|
|
if (!globalThis.CUSTOM_PROVIDER_START_COVERAGE) {
|
|
throw new Error('takeCoverage was called before startCoverage!')
|
|
}
|
|
|
|
return { customCoverage: 'Coverage report passed from workers to main thread' }
|
|
},
|
|
|
|
startCoverage() {
|
|
// @ts-expect-error -- untyped
|
|
globalThis.CUSTOM_PROVIDER_START_COVERAGE = true
|
|
},
|
|
|
|
stopCoverage() {
|
|
// @ts-expect-error -- untyped
|
|
if (!globalThis.CUSTOM_PROVIDER_START_COVERAGE) {
|
|
throw new Error('stopCoverage was called before startCoverage!')
|
|
}
|
|
|
|
// @ts-expect-error -- untyped
|
|
if (!globalThis.CUSTOM_PROVIDER_TAKE_COVERAGE) {
|
|
throw new Error('stopCoverage was called before takeCoverage!')
|
|
}
|
|
},
|
|
}
|
|
|
|
/**
|
|
* Provider that simply keeps track of the functions that were called
|
|
*/
|
|
class CustomCoverageProvider implements CoverageProvider {
|
|
name = 'custom-coverage-provider'
|
|
|
|
options!: ResolvedCoverageOptions
|
|
calls: Set<string> = new Set()
|
|
coverageReports: Set<string> = new Set()
|
|
transformedFiles: Set<string> = new Set()
|
|
|
|
initialize(ctx: Vitest) {
|
|
this.options = ctx.config.coverage
|
|
|
|
this.calls.add(`initialized ${ctx ? 'with' : 'without'} context`)
|
|
}
|
|
|
|
clean(force?: boolean) {
|
|
this.calls.add(`clean ${force ? 'with' : 'without'} force`)
|
|
}
|
|
|
|
onAfterSuiteRun(meta: AfterSuiteRunMeta) {
|
|
// Do not include coverage info here, as order of tests is not guaranteed
|
|
this.calls.add('onAfterSuiteRun')
|
|
|
|
// Keep coverage info separate from calls and ignore its order
|
|
this.coverageReports.add(JSON.stringify({
|
|
...meta,
|
|
|
|
// Project name keeps changing so let's simply check that its present
|
|
projectName: meta.projectName && typeof meta.projectName === 'string',
|
|
}))
|
|
}
|
|
|
|
generateCoverage(_reportContext: ReportContext) {
|
|
return {}
|
|
}
|
|
|
|
reportCoverage(coverage: unknown, reportContext?: ReportContext) {
|
|
this.calls.add(`reportCoverage with ${JSON.stringify(reportContext)}`)
|
|
|
|
const jsonReport = JSON.stringify({
|
|
calls: Array.from(this.calls.values()),
|
|
coverageReports: Array.from(this.coverageReports.values()).sort(),
|
|
transformedFiles: Array.from(this.transformedFiles.values()).sort(),
|
|
}, null, 2)
|
|
|
|
if (existsSync('./coverage')) {
|
|
rmSync('./coverage', { maxRetries: 10, recursive: true })
|
|
}
|
|
|
|
mkdirSync('./coverage')
|
|
writeFileSync('./coverage/custom-coverage-provider-report.json', jsonReport, 'utf-8')
|
|
}
|
|
|
|
onFileTransform(code: string, id: string) {
|
|
const filename = normalizeFilename(id).split('?')[0]
|
|
|
|
if (/\/fixtures\/src\//.test(filename)) {
|
|
this.transformedFiles.add(filename)
|
|
}
|
|
|
|
return { code }
|
|
}
|
|
|
|
resolveOptions(): ResolvedCoverageOptions {
|
|
this.calls.add('resolveOptions')
|
|
|
|
return this.options
|
|
}
|
|
}
|
|
|
|
export default CustomCoverageProviderModule
|
|
|
|
|
|
function normalizeFilename(filename: string) {
|
|
return normalize(filename)
|
|
.replace(normalize(process.cwd()), '<process-cwd>')
|
|
.replace(normalize(resolve(process.cwd(), '../../')), '<project-root>')
|
|
.replaceAll(sep, "/")
|
|
}
|