Skip to content

Commit

Permalink
refactor: share the same spy instance between local and global mocks (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va committed Feb 1, 2022
1 parent 9504905 commit d55736d
Show file tree
Hide file tree
Showing 7 changed files with 20 additions and 32 deletions.
3 changes: 0 additions & 3 deletions packages/vite-node/src/cli.ts
Expand Up @@ -82,9 +82,6 @@ async function run(options: CliOptions = {}) {
fetchModule(id) {
return node.fetchModule(id)
},
resolveId(id, importer) {
return node.resolveId(id, importer)
},
})

for (const file of files)
Expand Down
2 changes: 0 additions & 2 deletions packages/vite-node/src/types.ts
Expand Up @@ -28,7 +28,6 @@ export interface FetchResult {
}

export type FetchFunction = (id: string) => Promise<FetchResult>
export type ResolveIdFunction = (id: string, importer?: string) => Promise<ViteNodeResolveId | null>

export interface ModuleCache {
promise?: Promise<any>
Expand All @@ -38,7 +37,6 @@ export interface ModuleCache {

export interface ViteNodeRunnerOptions {
fetchModule: FetchFunction
resolveId: ResolveIdFunction
root: string
base?: string
moduleCache?: Map<string, ModuleCache>
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/rollup.config.js
Expand Up @@ -18,6 +18,7 @@ const entries = [
'src/node.ts',
'src/runtime/worker.ts',
'src/runtime/entry.ts',
'src/integrations/jest-mock.ts',
]

const dtsEntries = [
Expand Down
3 changes: 0 additions & 3 deletions packages/vitest/src/integrations/vi.ts
Expand Up @@ -182,19 +182,16 @@ class VitestUtils {
}

public clearAllMocks() {
this._mocker.clearMocks({ clearMocks: true })
spies.forEach(spy => spy.mockClear())
return this
}

public resetAllMocks() {
this._mocker.clearMocks({ mockReset: true })
spies.forEach(spy => spy.mockReset())
return this
}

public restoreAllMocks() {
this._mocker.clearMocks({ restoreMocks: true })
spies.forEach(spy => spy.mockRestore())
return this
}
Expand Down
5 changes: 4 additions & 1 deletion packages/vitest/src/node/execute.ts
@@ -1,11 +1,14 @@
import { ViteNodeRunner } from 'vite-node/client'
import type { ModuleCache, ViteNodeRunnerOptions } from 'vite-node'
import type { ModuleCache, ViteNodeResolveId, ViteNodeRunnerOptions } from 'vite-node'
import type { SuiteMocks } from './mocker'
import { VitestMocker } from './mocker'

export type ResolveIdFunction = (id: string, importer?: string) => Promise<ViteNodeResolveId | null>

export interface ExecuteOptions extends ViteNodeRunnerOptions {
files: string[]
mockMap: SuiteMocks
resolveId: ResolveIdFunction
}

export async function executeInViteNode(options: ExecuteOptions) {
Expand Down
35 changes: 15 additions & 20 deletions packages/vitest/src/node/mocker.ts
Expand Up @@ -3,8 +3,8 @@ import { isNodeBuiltin } from 'mlly'
import { basename, dirname, join, resolve } from 'pathe'
import type { ModuleCache } from 'vite-node'
import { toFilePath } from 'vite-node/utils'
import { spies, spyOn } from '../integrations/jest-mock'
import { mergeSlashes, normalizeId } from '../utils'
import { distDir } from '../constants'
import type { ExecuteOptions } from './execute'

export type SuiteMocks = Record<string, Record<string, string | null | (() => unknown)>>
Expand All @@ -22,7 +22,7 @@ function getObjectType(value: unknown): string {
return Object.prototype.toString.apply(value).slice(8, -1)
}

function mockPrototype(proto: any) {
function mockPrototype(spyOn: typeof import('../integrations/jest-mock')['spyOn'], proto: any) {
if (!proto) return null

const newProto: any = {}
Expand All @@ -46,17 +46,16 @@ export class VitestMocker {
private request!: (dep: string) => unknown

private root: string
// private mockMap: SuiteMocks

private callbacks: Record<string, ((...args: any[]) => unknown)[]> = {}
private spy?: typeof import('../integrations/jest-mock')

constructor(
public options: ExecuteOptions,
private moduleCache: Map<string, ModuleCache>,
request?: (dep: string) => unknown,
) {
this.root = this.options.root
// this.mockMap = options.mockMap
this.request = request!
}

Expand Down Expand Up @@ -167,6 +166,9 @@ export class VitestMocker {
}

public mockObject(obj: any) {
if (!this.spy)
throw new Error('Internal Vitest error: Spy function is not defined.')

const type = getObjectType(obj)

if (Array.isArray(obj))
Expand All @@ -176,7 +178,7 @@ export class VitestMocker {

const newObj = { ...obj }

const proto = mockPrototype(Object.getPrototypeOf(obj))
const proto = mockPrototype(this.spy.spyOn, Object.getPrototypeOf(obj))
Object.setPrototypeOf(newObj, proto)

// eslint-disable-next-line no-restricted-syntax
Expand All @@ -185,7 +187,7 @@ export class VitestMocker {
const type = getObjectType(obj[k])

if (type.includes('Function') && !obj[k].__isSpy) {
spyOn(newObj, k).mockImplementation(() => {})
this.spy.spyOn(newObj, k).mockImplementation(() => {})
Object.defineProperty(newObj[k], 'length', { value: 0 }) // tinyspy retains length, but jest doesnt
}
}
Expand Down Expand Up @@ -226,6 +228,7 @@ export class VitestMocker {
mock = this.resolveMockPath(path, external)

if (mock === null) {
await this.ensureSpy()
const fsPath = this.getActualPath(path, external)
const mod = await this.request(fsPath)
return this.mockObject(mod)
Expand All @@ -235,7 +238,13 @@ export class VitestMocker {
return this.requestWithMock(mock)
}

private async ensureSpy() {
if (this.spy) return
this.spy = await this.request(resolve(distDir, 'jest-mock.js')) as typeof import('../integrations/jest-mock')
}

public async requestWithMock(dep: string) {
await this.ensureSpy()
await this.resolveMocks()

const mock = this.getDependencyMock(dep)
Expand All @@ -258,20 +267,6 @@ export class VitestMocker {
return this.request(dep)
}

public clearMocks({ clearMocks, mockReset, restoreMocks }: { clearMocks?: boolean; mockReset?: boolean; restoreMocks?: boolean }) {
if (!clearMocks && !mockReset && !restoreMocks)
return

spies.forEach((s) => {
if (restoreMocks)
s.mockRestore()
else if (mockReset)
s.mockReset()
else if (clearMocks)
s.mockClear()
})
}

public queueMock(id: string, importer: string, factory?: () => unknown) {
pendingIds.push({ type: 'mock', id, importer, factory })
}
Expand Down
3 changes: 0 additions & 3 deletions packages/vitest/src/node/plugins/globalSetup.ts
Expand Up @@ -18,9 +18,6 @@ async function loadGlobalSetupFiles(ctx: Vitest): Promise<GlobalSetupFile[]> {
fetchModule(id) {
return node.fetchModule(id)
},
resolveId(id, importer) {
return node.resolveId(id, importer)
},
})
const globalSetupFiles = toArray(server.config.test?.globalSetup)
return Promise.all(globalSetupFiles.map(file => loadGlobalSetupFile(file, runner)))
Expand Down

0 comments on commit d55736d

Please sign in to comment.