|
1 | 1 | import { existsSync, promises as fs, readdirSync, writeFileSync } from 'node:fs'
|
| 2 | +import { basename, dirname } from 'node:path' |
2 | 3 | import { resolve } from 'pathe'
|
3 | 4 | import type { AfterSuiteRunMeta, CoverageIstanbulOptions, CoverageProvider, ReportContext, ResolvedCoverageOptions, Vitest } from 'vitest'
|
4 | 5 | import { coverageConfigDefaults, defaultExclude, defaultInclude } from 'vitest/config'
|
@@ -228,6 +229,11 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co
|
228 | 229 | this.ctx.logger.log(c.blue(' % ') + c.dim('Coverage report from ') + c.yellow(this.name))
|
229 | 230 |
|
230 | 231 | for (const reporter of this.options.reporter) {
|
| 232 | + if (reporter[0] === 'blob') { |
| 233 | + await this.createBlobReport(coverageMap, reporter[1]) |
| 234 | + continue |
| 235 | + } |
| 236 | + |
231 | 237 | // Type assertion required for custom reporters
|
232 | 238 | reports.create(reporter[0] as Parameters<typeof reports.create>[0], {
|
233 | 239 | skipFull: this.options.skipFull,
|
@@ -266,6 +272,37 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co
|
266 | 272 | }
|
267 | 273 | }
|
268 | 274 |
|
| 275 | + async mergeReports(path?: string) { |
| 276 | + const directory = resolve(path || '.vitest-reports/coverage') |
| 277 | + const files = await fs.readdir(directory) |
| 278 | + const coverageMap = libCoverage.createCoverageMap({}) |
| 279 | + |
| 280 | + for (const file of files) { |
| 281 | + const report = await fs.readFile(resolve(directory, file), 'utf8') |
| 282 | + coverageMap.merge(JSON.parse(report)) |
| 283 | + } |
| 284 | + |
| 285 | + await this.generateReports(coverageMap, true) |
| 286 | + } |
| 287 | + |
| 288 | + async createBlobReport(coverageMap: CoverageMap, options: Options['reporter'][number][1]) { |
| 289 | + const outputFile = 'outputFile' in options && options.outputFile as string |
| 290 | + const dir = outputFile ? dirname(outputFile) : '.vitest-reports/coverage' |
| 291 | + let file = outputFile && basename(outputFile) |
| 292 | + |
| 293 | + if (!file) { |
| 294 | + const shard = this.ctx.config.shard |
| 295 | + file = shard |
| 296 | + ? `.coverage-blob-${shard.index}-${shard.count}.json` |
| 297 | + : '.coverage-blob.json' |
| 298 | + } |
| 299 | + |
| 300 | + const context = libReport.createContext({ dir, coverageMap }) |
| 301 | + reports.create('json', { file }).execute(context) |
| 302 | + |
| 303 | + this.ctx.logger.log('coverage blob report written to', resolve(dir, file)) |
| 304 | + } |
| 305 | + |
269 | 306 | private async getCoverageMapForUncoveredFiles(coveredFiles: string[]) {
|
270 | 307 | const allFiles = await this.testExclude.glob(this.ctx.config.root)
|
271 | 308 | let includedFiles = allFiles.map(file => resolve(this.ctx.config.root, file))
|
|
0 commit comments