From 1413382e1f2faa7dded070e0c67ef1ab936604cc Mon Sep 17 00:00:00 2001 From: DaveT1991 <129008657+DaveT1991@users.noreply.github.com> Date: Fri, 10 Apr 2026 02:00:18 -0400 Subject: [PATCH] fix(coverage): descriptive error message when reports directory is removed during test run (#10117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ari Perkkiƶ --- packages/vitest/src/node/coverage.ts | 22 +++++++++++++++++++ .../test/temporary-files.unit.test.ts | 19 ++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 test/coverage-test/test/temporary-files.unit.test.ts diff --git a/packages/vitest/src/node/coverage.ts b/packages/vitest/src/node/coverage.ts index a8ecec1f3..131cf70b7 100644 --- a/packages/vitest/src/node/coverage.ts +++ b/packages/vitest/src/node/coverage.ts @@ -255,6 +255,22 @@ export class BaseCoverageProvider { this.pendingPromises = [] } + private normalizeCoverageFileError(error: unknown): unknown { + if ( + error instanceof Error + && 'code' in error + && error.code === 'ENOENT' + && !existsSync(this.coverageFilesDirectory) + ) { + return new Error( + `Something removed the coverage directory "${this.coverageFilesDirectory}" Vitest created earlier. Make sure you are not running multiple Vitests with the same "coverage.reportsDirectory" at the same time.`, + { cause: error }, + ) + } + + return error + } + onAfterSuiteRun({ coverage, environment, projectName, testFiles }: AfterSuiteRunMeta): void { if (!coverage) { return @@ -278,6 +294,9 @@ export class BaseCoverageProvider { entry[environment][testFilenames] = filename const promise = fs.writeFile(filename, JSON.stringify(coverage), 'utf-8') + .catch((error) => { + throw this.normalizeCoverageFileError(error) + }) this.pendingPromises.push(promise) } @@ -307,6 +326,9 @@ export class BaseCoverageProvider { await Promise.all(chunk.map(async (filename) => { const contents = await fs.readFile(filename, 'utf-8') + .catch((error) => { + throw this.normalizeCoverageFileError(error) + }) const coverage = JSON.parse(contents) onFileRead(coverage) diff --git a/test/coverage-test/test/temporary-files.unit.test.ts b/test/coverage-test/test/temporary-files.unit.test.ts new file mode 100644 index 000000000..c54fb2f2b --- /dev/null +++ b/test/coverage-test/test/temporary-files.unit.test.ts @@ -0,0 +1,19 @@ +import { resolve } from 'node:path' +import { expect, test } from 'vitest' +import { BaseCoverageProvider } from 'vitest/node' + +test('missing coverage temp directory throws an actionable error', async () => { + const provider = new BaseCoverageProvider() + provider.coverageFilesDirectory = resolve('missing-coverage-directory', '.tmp') + + provider.onAfterSuiteRun({ + coverage: { '/src/math.ts': {} }, + environment: 'ssr', + projectName: '', + testFiles: ['math.test.ts'], + } as any) + + await expect(Promise.all(provider.pendingPromises)).rejects.toThrow( + `Something removed the coverage directory "${provider.coverageFilesDirectory}" Vitest created earlier. Make sure you are not running multiple Vitests with the same "coverage.reportsDirectory" at the same time.`, + ) +}) -- 2.51.2