Skip to content

Commit

Permalink
fix: don't clear mocks with vi.resetModules, cache normalised mock pa…
Browse files Browse the repository at this point in the history
…ths (#1726)

* fix: don't reset mocks with vi.resetModules

* chore: reset mocks with --no-threads

* fix: normalize path when caching mocks
  • Loading branch information
sheremet-va committed Jul 27, 2022
1 parent 57c2367 commit 68951e0
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 24 deletions.
3 changes: 2 additions & 1 deletion packages/vitest/src/integrations/vi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,8 @@ class VitestUtils {
}

public resetModules() {
resetModules()
const state = getWorkerState()
resetModules(state.moduleCache)
return this
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/runtime/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export async function run(files: string[], config: ResolvedConfig): Promise<void
await withEnv(environment, config.environmentOptions || {}, async () => {
for (const file of files) {
workerState.mockMap.clear()
resetModules()
resetModules(workerState.moduleCache, true)

workerState.filepath = file

Expand Down
33 changes: 19 additions & 14 deletions packages/vitest/src/runtime/mocker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,20 @@ export class VitestMocker {
}

private async callFunctionMock(dep: string, mock: () => any) {
const cacheName = `${dep}__mock`
const cached = this.moduleCache.get(cacheName)?.exports
const cached = this.moduleCache.get(dep)?.exports
if (cached)
return cached
const exports = await mock()
this.moduleCache.set(cacheName, { exports })
this.moduleCache.set(dep, { exports })
return exports
}

public getDependencyMock(dep: string) {
return this.getMocks()[this.normalizePath(dep)]
private getMockPath(dep: string) {
return `mock:${dep}`
}

public getDependencyMock(id: string) {
return this.getMocks()[id]
}

public normalizePath(path: string) {
Expand Down Expand Up @@ -263,7 +266,8 @@ export class VitestMocker {
const { path, external } = await this.resolvePath(id, importer)

const fsPath = this.getFsPath(path, external)
let mock = this.getDependencyMock(fsPath)
const normalizedId = this.normalizePath(fsPath)
let mock = this.getDependencyMock(normalizedId)

if (mock === undefined)
mock = this.resolveMockPath(fsPath, external)
Expand Down Expand Up @@ -291,25 +295,26 @@ export class VitestMocker {
this.resolveMocks(),
])

const mock = this.getDependencyMock(dep)
const id = this.normalizePath(dep)
const mock = this.getDependencyMock(id)

const callstack = this.request.callstack
const mockPath = this.getMockPath(id)

if (mock === null) {
const cacheName = `${dep}__mock`
const cache = this.moduleCache.get(cacheName)
const cache = this.moduleCache.get(mockPath)
if (cache?.exports)
return cache.exports
const cacheKey = toFilePath(dep, this.root)
const mod = this.moduleCache.get(cacheKey)?.exports || await this.request(dep)
const exports = this.mockObject(mod)
this.moduleCache.set(cacheName, { exports })
this.moduleCache.set(mockPath, { exports })
return exports
}
if (typeof mock === 'function' && !callstack.includes(`mock:${dep}`)) {
callstack.push(`mock:${dep}`)
const result = await this.callFunctionMock(dep, mock)
const indexMock = callstack.indexOf(`mock:${dep}`)
if (typeof mock === 'function' && !callstack.includes(mockPath)) {
callstack.push(mockPath)
const result = await this.callFunctionMock(mockPath, mock)
const indexMock = callstack.indexOf(mockPath)
callstack.splice(indexMock, 1)
return result
}
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/runtime/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ function init(ctx: WorkerContext) {
if (ctx.invalidates) {
ctx.invalidates.forEach((fsPath) => {
moduleCache.delete(fsPath)
moduleCache.delete(`${fsPath}__mock`)
moduleCache.delete(`mock:${fsPath}`)
})
}
ctx.files.forEach(i => moduleCache.delete(i))
Expand Down
11 changes: 6 additions & 5 deletions packages/vitest/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { relative as relativeBrowser } from 'path'
import c from 'picocolors'
import { isPackageExists } from 'local-pkg'
import { relative as relativeNode } from 'pathe'
import type { ModuleCacheMap } from 'vite-node'
import type { Suite, Task } from '../types'
import { getWorkerState } from '../utils/global'
import { getNames } from './tasks'

export * from './tasks'
Expand Down Expand Up @@ -40,18 +40,19 @@ export function partitionSuiteChildren(suite: Suite) {
return tasksGroups
}

export function resetModules() {
const modules = getWorkerState().moduleCache
const vitestPaths = [
export function resetModules(modules: ModuleCacheMap, resetMocks = false) {
const skipPaths = [
// Vitest
/\/vitest\/dist\//,
// yarn's .store folder
/vitest-virtual-\w+\/dist/,
// cnpm
/@vitest\/dist/,
// don't clear mocks
...(!resetMocks ? [/^mock:/] : []),
]
modules.forEach((_, path) => {
if (vitestPaths.some(re => re.test(path)))
if (skipPaths.some(re => re.test(path)))
return
modules.delete(path)
})
Expand Down
2 changes: 1 addition & 1 deletion packages/web-worker/src/pure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export function defineWebWorker() {
invalidates.forEach((fsPath) => {
// worker should be new every time
moduleCache.delete(fsPath)
moduleCache.delete(`${fsPath}__mock`)
moduleCache.delete(`mock:${fsPath}`)
})
const q = this.messageQueue
this.messageQueue = null
Expand Down
37 changes: 36 additions & 1 deletion test/core/test/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { describe, expect, test } from 'vitest'
import { assertTypes, deepClone, deepMerge, toArray } from '../../../packages/vitest/src/utils'
import { assertTypes, deepClone, deepMerge, resetModules, toArray } from '../../../packages/vitest/src/utils'
import { deepMergeSnapshot } from '../../../packages/vitest/src/integrations/snapshot/port/utils'
import type { ModuleCacheMap } from '../../../packages/vite-node/src/types'

describe('assertTypes', () => {
test('the type of value should be number', () => {
Expand Down Expand Up @@ -147,3 +148,37 @@ describe('deepClone', () => {
expect(deepClone(objD)).toEqual(objD)
})
})

describe('resetModules doesn\'t resets only user modules', () => {
test('resets user modules', () => {
const moduleCache = new Map() as ModuleCacheMap
moduleCache.set('/some-module.ts', {})
moduleCache.set('/@fs/some-path.ts', {})

resetModules(moduleCache)

expect(moduleCache.size).toBe(0)
})

test('doesn\'t reset vitest modules', () => {
const moduleCache = new Map() as ModuleCacheMap
moduleCache.set('/node_modules/vitest/dist/index.js', {})
moduleCache.set('/node_modules/vitest-virtual-da9876a/dist/index.js', {})
moduleCache.set('/node_modules/some-module@vitest/dist/index.js', {})
moduleCache.set('/packages/vitest/dist/index.js', {})

resetModules(moduleCache)

expect(moduleCache.size).toBe(4)
})

test('doesn\'t reset mocks', () => {
const moduleCache = new Map() as ModuleCacheMap
moduleCache.set('mock:/some-module.ts', {})
moduleCache.set('mock:/@fs/some-path.ts', {})

resetModules(moduleCache)

expect(moduleCache.size).toBe(2)
})
})

0 comments on commit 68951e0

Please sign in to comment.