From f99cc3132d3457158635200b9391331a96ca661d Mon Sep 17 00:00:00 2001 From: Vladimir Date: Tue, 9 Jan 2024 16:39:18 +0100 Subject: [PATCH] fix(vitest): throw "cannot mock" error only in isolated pools (#4905) --- packages/utils/src/error.ts | 2 +- packages/vitest/src/runtime/execute.ts | 2 +- packages/vitest/src/runtime/mocker.ts | 14 +++++++++++--- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/error.ts b/packages/utils/src/error.ts index 5cd558ad0041..ff9bd37afa7b 100644 --- a/packages/utils/src/error.ts +++ b/packages/utils/src/error.ts @@ -89,7 +89,7 @@ export function serializeError(val: any, seen = new WeakMap()): any { } function normalizeErrorMessage(message: string) { - return message.replace(/__vite_ssr_import_\d+__\./g, '') + return message.replace(/__(vite_ssr_import|vi_import)_\d+__\./g, '') } export function processError(err: any, diffOptions?: DiffOptions) { diff --git a/packages/vitest/src/runtime/execute.ts b/packages/vitest/src/runtime/execute.ts index 2ceda37271b1..db913c9a90dd 100644 --- a/packages/vitest/src/runtime/execute.ts +++ b/packages/vitest/src/runtime/execute.ts @@ -216,7 +216,7 @@ export class VitestExecutor extends ViteNodeRunner { return this.primitives } - get state() { + get state(): WorkerGlobalState { // @ts-expect-error injected untyped global return globalThis.__vitest_worker__ || this.options.state } diff --git a/packages/vitest/src/runtime/mocker.ts b/packages/vitest/src/runtime/mocker.ts index f07182ded7df..f1c912736fa7 100644 --- a/packages/vitest/src/runtime/mocker.ts +++ b/packages/vitest/src/runtime/mocker.ts @@ -1,6 +1,6 @@ import { existsSync, readdirSync } from 'node:fs' import vm from 'node:vm' -import { basename, dirname, extname, isAbsolute, join, resolve } from 'pathe' +import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'pathe' import { getColors, getType } from '@vitest/utils' import { isNodeBuiltin } from 'vite-node/utils' import { distDir } from '../paths' @@ -410,8 +410,16 @@ export class VitestMocker { public mockPath(originalId: string, path: string, external: string | null, factory: MockFactory | undefined, throwIfExists: boolean) { const id = this.normalizePath(path) - if (throwIfExists && this.moduleCache.has(id)) - throw new Error(`[vitest] Cannot mock "${originalId}" because it is already loaded. Did you import it in a setup file?\n\nPlease, remove the import if you want static imports to be mocked, or clear module cache by calling "vi.resetModules()" before mocking if you are going to import the file again. See: https://vitest.dev/guide/common-errors.html#cannot-mock-mocked-file.js-because-it-is-already-loaded`) + const { config } = this.executor.state + const isIsolatedThreads = config.pool === 'threads' && (config.poolOptions?.threads?.isolate ?? true) + const isIsolatedForks = config.pool === 'forks' && (config.poolOptions?.forks?.isolate ?? true) + + // TODO: find a good way to throw this error even in non-isolated mode + if (throwIfExists && (isIsolatedThreads || isIsolatedForks)) { + const cached = this.moduleCache.has(id) && this.moduleCache.getByModuleId(id) + if (cached && cached.importers.size) + throw new Error(`[vitest] Cannot mock "${originalId}" because it is already loaded by "${[...cached.importers.values()].map(i => relative(this.root, i)).join('", "')}".\n\nPlease, remove the import if you want static imports to be mocked, or clear module cache by calling "vi.resetModules()" before mocking if you are going to import the file again. See: https://vitest.dev/guide/common-errors.html#cannot-mock-mocked-file-js-because-it-is-already-loaded`) + } const suitefile = this.getSuiteFilepath() const mocks = this.mockMap.get(suitefile) || {}