Skip to content

Commit f99cc31

Browse files
authoredJan 9, 2024
fix(vitest): throw "cannot mock" error only in isolated pools (#4905)
1 parent e9fe418 commit f99cc31

File tree

3 files changed

+13
-5
lines changed

3 files changed

+13
-5
lines changed
 

‎packages/utils/src/error.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ export function serializeError(val: any, seen = new WeakMap()): any {
8989
}
9090

9191
function normalizeErrorMessage(message: string) {
92-
return message.replace(/__vite_ssr_import_\d+__\./g, '')
92+
return message.replace(/__(vite_ssr_import|vi_import)_\d+__\./g, '')
9393
}
9494

9595
export function processError(err: any, diffOptions?: DiffOptions) {

‎packages/vitest/src/runtime/execute.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ export class VitestExecutor extends ViteNodeRunner {
216216
return this.primitives
217217
}
218218

219-
get state() {
219+
get state(): WorkerGlobalState {
220220
// @ts-expect-error injected untyped global
221221
return globalThis.__vitest_worker__ || this.options.state
222222
}

‎packages/vitest/src/runtime/mocker.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { existsSync, readdirSync } from 'node:fs'
22
import vm from 'node:vm'
3-
import { basename, dirname, extname, isAbsolute, join, resolve } from 'pathe'
3+
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from 'pathe'
44
import { getColors, getType } from '@vitest/utils'
55
import { isNodeBuiltin } from 'vite-node/utils'
66
import { distDir } from '../paths'
@@ -410,8 +410,16 @@ export class VitestMocker {
410410
public mockPath(originalId: string, path: string, external: string | null, factory: MockFactory | undefined, throwIfExists: boolean) {
411411
const id = this.normalizePath(path)
412412

413-
if (throwIfExists && this.moduleCache.has(id))
414-
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`)
413+
const { config } = this.executor.state
414+
const isIsolatedThreads = config.pool === 'threads' && (config.poolOptions?.threads?.isolate ?? true)
415+
const isIsolatedForks = config.pool === 'forks' && (config.poolOptions?.forks?.isolate ?? true)
416+
417+
// TODO: find a good way to throw this error even in non-isolated mode
418+
if (throwIfExists && (isIsolatedThreads || isIsolatedForks)) {
419+
const cached = this.moduleCache.has(id) && this.moduleCache.getByModuleId(id)
420+
if (cached && cached.importers.size)
421+
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`)
422+
}
415423

416424
const suitefile = this.getSuiteFilepath()
417425
const mocks = this.mockMap.get(suitefile) || {}

0 commit comments

Comments
 (0)
Please sign in to comment.