From 0012cec5bc1b1174fadf286782daf464e57ae66b Mon Sep 17 00:00:00 2001 From: AriPerkkio Date: Tue, 12 Mar 2024 19:48:22 +0200 Subject: [PATCH] fix(coverage): prevent `reportsDirectory` from removing user's project --- docs/config/index.md | 4 ++++ packages/vitest/src/node/config.ts | 8 +++++++ test/config/test/failures.test.ts | 38 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/docs/config/index.md b/docs/config/index.md index b297d11c926f..17d4ee6c5523 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -1137,6 +1137,10 @@ Clean coverage report on watch rerun - **Available for providers:** `'v8' | 'istanbul'` - **CLI:** `--coverage.reportsDirectory=` +::: warning +Vitest will delete this directory before running tests if `coverage.clean` is enabled (default value). +::: + Directory to write coverage report to. To preview the coverage report in the output of [HTML reporter](/guide/reporters.html#html-reporter), this option must be set as a sub-directory of the html report directory (for example `./html/coverage`). diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index e1e46d16c6af..e52b8a21eaab 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -135,6 +135,7 @@ export function resolveConfig( } } + // TODO: V2.0.0 remove // @ts-expect-error -- check for removed API option if (resolved.coverage.provider === 'c8') throw new Error('"coverage.provider: c8" is not supported anymore. Use "coverage.provider: v8" instead') @@ -142,6 +143,13 @@ export function resolveConfig( if (resolved.coverage.provider === 'v8' && resolved.coverage.enabled && isBrowserEnabled(resolved)) throw new Error('@vitest/coverage-v8 does not work with --browser. Use @vitest/coverage-istanbul instead') + if (resolved.coverage.enabled && resolved.coverage.reportsDirectory) { + const reportsDirectory = resolve(resolved.root, resolved.coverage.reportsDirectory) + + if (reportsDirectory === resolved.root || reportsDirectory === process.cwd()) + throw new Error(`You cannot set "coverage.reportsDirectory" as ${reportsDirectory}. Vitest needs to be able to remove this directory before test run`) + } + resolved.deps ??= {} resolved.deps.moduleDirectories ??= [] resolved.deps.moduleDirectories = resolved.deps.moduleDirectories.map((dir) => { diff --git a/test/config/test/failures.test.ts b/test/config/test/failures.test.ts index 0007f55aac3f..cc65dd796e80 100644 --- a/test/config/test/failures.test.ts +++ b/test/config/test/failures.test.ts @@ -2,6 +2,7 @@ import { expect, test } from 'vitest' import type { UserConfig } from 'vitest/config' import { version } from 'vitest/package.json' +import { normalize, resolve } from 'pathe' import * as testUtils from '../../test-utils' function runVitest(config: NonNullable & { shard?: any }) { @@ -67,6 +68,43 @@ test('v8 coverage provider cannot be used with browser in workspace', async () = expect(stderr).toMatch('Error: @vitest/coverage-v8 does not work with --browser. Use @vitest/coverage-istanbul instead') }) +test('coverage reportsDirectory cannot be current working directory', async () => { + const { stderr } = await runVitest({ + coverage: { + enabled: true, + reportsDirectory: './', + + // Additional options to make sure this test doesn't accidentally remove whole vitest project + clean: false, + cleanOnRerun: false, + provider: 'custom', + customProviderModule: 'non-existing-provider-so-that-reportsDirectory-is-not-removed', + }, + }) + + const directory = normalize(resolve('./')) + expect(stderr).toMatch(`Error: You cannot set "coverage.reportsDirectory" as ${directory}. Vitest needs to be able to remove this directory before test run`) +}) + +test('coverage reportsDirectory cannot be root', async () => { + const { stderr } = await runVitest({ + root: './fixtures', + coverage: { + enabled: true, + reportsDirectory: './', + + // Additional options to make sure this test doesn't accidentally remove whole vitest project + clean: false, + cleanOnRerun: false, + provider: 'custom', + customProviderModule: 'non-existing-provider-so-that-reportsDirectory-is-not-removed', + }, + }) + + const directory = normalize(resolve('./fixtures')) + expect(stderr).toMatch(`Error: You cannot set "coverage.reportsDirectory" as ${directory}. Vitest needs to be able to remove this directory before test run`) +}) + test('version number is printed when coverage provider fails to load', async () => { const { stderr, stdout } = await runVitest({ coverage: {