From 2138cc4f6db3d39a694287066a24dd1f43ca21f9 Mon Sep 17 00:00:00 2001 From: AriPerkkio Date: Sun, 21 Jan 2024 12:32:06 +0200 Subject: [PATCH] fix(coverage): don't crash when re-run removes earlier run's reports --- packages/coverage-istanbul/src/provider.ts | 26 ++++++++++++++++++++++ packages/vitest/src/node/core.ts | 19 +++++++--------- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/packages/coverage-istanbul/src/provider.ts b/packages/coverage-istanbul/src/provider.ts index 82949c79b1195..7f850a1ad3bc5 100644 --- a/packages/coverage-istanbul/src/provider.ts +++ b/packages/coverage-istanbul/src/provider.ts @@ -53,6 +53,10 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co coverageFilesDirectory!: string pendingPromises: Promise[] = [] + onRunFinish: (() => void) | null = null + runningPromise: Promise | null = null + cancelRun = false + initialize(ctx: Vitest) { const config: CoverageIstanbulOptions = ctx.config.coverage @@ -145,6 +149,20 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co } async clean(clean = true) { + if (this.runningPromise) { + this.cancelRun = true + await this.runningPromise + } + + this.runningPromise = new Promise((resolve) => { + this.onRunFinish = () => { + resolve() + this.onRunFinish = null + this.runningPromise = null + this.cancelRun = false + } + }) + if (clean && existsSync(this.options.reportsDirectory)) await fs.rm(this.options.reportsDirectory, { recursive: true, force: true, maxRetries: 10 }) @@ -179,11 +197,18 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co // TODO: Remove this.ctx.logger.log(c.yellow(`Checking ${filename}`)) await new Promise(r => setTimeout(r, 1000)) + + if (this.cancelRun) + return + const contents = await fs.readFile(filename, 'utf-8') const coverage = JSON.parse(contents) as CoverageMap coverageMapByTransformMode.merge(coverage) })) + + if (this.cancelRun) + return this.onRunFinish?.() } // Source maps can change based on projectName and transform mode. @@ -250,6 +275,7 @@ export class IstanbulCoverageProvider extends BaseCoverageProvider implements Co await fs.rm(this.coverageFilesDirectory, { recursive: true }) this.coverageFiles = new Map() + this.onRunFinish?.() } async getCoverageMapForUncoveredFiles(coveredFiles: string[]) { diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index c9d531b16c956..bdec7b3363541 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -346,7 +346,6 @@ export class Vitest { try { await this.initCoverageProvider() - await this.coverageProvider?.clean(this.config.coverage.clean) await this.initBrowserProviders() } finally { @@ -377,7 +376,7 @@ export class Vitest { // populate once, update cache on watch await this.cache.stats.populateStats(this.config.root, files) - await this.runFiles(files) + await this.runFiles(files, true) } await this.reportCoverage(true) @@ -472,7 +471,7 @@ export class Vitest { await project.initializeGlobalSetup() } - async runFiles(paths: WorkspaceSpec[]) { + async runFiles(paths: WorkspaceSpec[], isFirstRun = false) { const filepaths = paths.map(([, file]) => file) this.state.collectPaths(filepaths) @@ -492,6 +491,10 @@ export class Vitest { this.invalidates.clear() this.snapshot.clear() this.state.clearErrors() + + if (this.coverageProvider) + await this.coverageProvider.clean(isFirstRun ? this.config.coverage.clean : this.config.coverage.cleanOnRerun) + await this.initializeGlobalSetup(paths) try { @@ -530,11 +533,8 @@ export class Vitest { files = files.filter(file => filteredFiles.some(f => f[1] === file)) } - if (this.coverageProvider && this.config.coverage.cleanOnRerun) - await this.coverageProvider.clean() - await this.report('onWatcherRerun', files, trigger) - await this.runFiles(files.flatMap(file => this.getProjectsByTestFile(file))) + await this.runFiles(files.flatMap(file => this.getProjectsByTestFile(file)), false) await this.reportCoverage(!trigger) @@ -632,14 +632,11 @@ export class Vitest { this.changedTests.clear() - if (this.coverageProvider && this.config.coverage.cleanOnRerun) - await this.coverageProvider.clean() - const triggerIds = new Set(triggerId.map(id => relative(this.config.root, id))) const triggerLabel = Array.from(triggerIds).join(', ') await this.report('onWatcherRerun', files, triggerLabel) - await this.runFiles(files.flatMap(file => this.getProjectsByTestFile(file))) + await this.runFiles(files.flatMap(file => this.getProjectsByTestFile(file)), false) await this.reportCoverage(false)