Skip to content

Commit

Permalink
feat: --merge-reports to support coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
AriPerkkio committed May 16, 2024
1 parent 1ec61ce commit bcb3ba8
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 9 deletions.
48 changes: 43 additions & 5 deletions packages/coverage-v8/src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
coverageMap.merge(await transformCoverage(converted))
}

await this.generateReports(coverageMap, allTestsRun)

// In watch mode we need to preserve the previous results if cleanOnRerun is disabled
const keepResults = !this.options.cleanOnRerun && this.ctx.config.watch

if (!keepResults) {
this.coverageFiles = new Map()
await fs.rm(this.coverageFilesDirectory, { recursive: true })
}
}

async generateReports(coverageMap: CoverageMap, allTestsRun: boolean | undefined) {
const context = libReport.createContext({
dir: this.options.reportsDirectory,
coverageMap,
Expand All @@ -203,6 +215,11 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
this.ctx.logger.log(c.blue(' % ') + c.dim('Coverage report from ') + c.yellow(this.name))

for (const reporter of this.options.reporter) {
if (reporter[0] === 'blob') {
await this.createBlobReport(coverageMap, reporter[1])
continue
}

// Type assertion required for custom reporters
reports.create(reporter[0] as Parameters<typeof reports.create>[0], {
skipFull: this.options.skipFull,
Expand Down Expand Up @@ -239,14 +256,35 @@ export class V8CoverageProvider extends BaseCoverageProvider implements Coverage
})
}
}
}

async mergeReports(path: string) {
const directory = resolve(path, 'coverage')
const files = await fs.readdir(directory)
const coverageMap = libCoverage.createCoverageMap({})

for (const file of files) {
const report = await fs.readFile(resolve(directory, file), 'utf8')
coverageMap.merge(JSON.parse(report))
}

// In watch mode we need to preserve the previous results if cleanOnRerun is disabled
const keepResults = !this.options.cleanOnRerun && this.ctx.config.watch
await this.generateReports(coverageMap, true)
}

if (!keepResults) {
this.coverageFiles = new Map()
await fs.rm(this.coverageFilesDirectory, { recursive: true })
async createBlobReport(coverageMap: CoverageMap, options: Options['reporter'][number][1]) {
let file = 'file' in options && options.file as string

if (!file) {
const shard = this.ctx.config.shard
file = shard
? `.coverage-blob-${shard.index}-${shard.count}.json`
: '.coverage-blob.json'
}

reports.create('json', { file }).execute(libReport.createContext({
dir: this.ctx.config.coverage.reportsDirectory || '.vitest-reports/coverage/',
coverageMap,
}))
}

private async getUntestedFiles(testedFiles: string[]): Promise<RawCoverage> {
Expand Down
2 changes: 2 additions & 0 deletions packages/vitest/src/node/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,8 @@ export class Vitest {
process.exitCode = 1

await this.report('onFinished', files, errors)
await this.initCoverageProvider()
await this.coverageProvider?.mergeReports?.(this.config.mergeReports)
}

async start(filters?: string[]) {
Expand Down
12 changes: 9 additions & 3 deletions packages/vitest/src/node/reporters/blob.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises'
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises'
import { existsSync } from 'node:fs'
import { parse, stringify } from 'flatted'
import { dirname, resolve } from 'pathe'
Expand Down Expand Up @@ -61,11 +61,17 @@ export async function readBlobs(blobsDirectory: string, projectsArray: Workspace
const resolvedDir = resolve(process.cwd(), blobsDirectory)
const blobsFiles = await readdir(resolvedDir)
const promises = blobsFiles.map(async (file) => {
const content = await readFile(resolve(resolvedDir, file), 'utf-8')
const filename = resolve(resolvedDir, file)
const stats = await stat(filename)
if (!stats.isFile())
return null

const content = await readFile(filename, 'utf-8')
const [version, files, errors, moduleKeys] = parse(content) as MergeReport
return { version, files, errors, moduleKeys }
})
const blobs = await Promise.all(promises)
const results = await Promise.all(promises)
const blobs = results.filter((result): result is NonNullable<typeof result> => result != null)

if (!blobs.length)
throw new Error(`vitest.mergeReports() requires at least one blob file paths in the config`)
Expand Down
8 changes: 7 additions & 1 deletion packages/vitest/src/types/coverage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { TransformResult as ViteTransformResult } from 'vite'
import type { ReportOptions } from 'istanbul-reports'
import type { ReportOptions as IstanbulReportOptions } from 'istanbul-reports'
import type { Vitest } from '../node'
import type { Arrayable } from './general'
import type { AfterSuiteRunMeta } from './worker'
Expand All @@ -17,6 +17,8 @@ export interface CoverageProvider {

reportCoverage: (reportContext?: ReportContext) => void | Promise<void>

mergeReports?: (path: string) => void | Promise<void>

onFileTransform?: (
sourceCode: string,
id: string,
Expand Down Expand Up @@ -52,6 +54,10 @@ export interface CoverageProviderModule {
stopCoverage?: () => unknown | Promise<unknown>
}

interface ReportOptions extends IstanbulReportOptions {
blob: { file?: string }
}

export type CoverageReporter = keyof ReportOptions | (string & {})

type CoverageReporterWithOptions<ReporterName extends CoverageReporter = CoverageReporter> =
Expand Down

0 comments on commit bcb3ba8

Please sign in to comment.