Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions packages/vitest/src/runtime/moduleRunner/moduleRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,23 +168,28 @@ export class VitestModuleRunner
if (mod.meta && 'mockedModule' in mod.meta) {
const mockedModule = mod.meta.mockedModule as MockedModule
const mockId = this.mocker.getMockPath(mod.id)
const currentMock = this.mocker.getDependencyMock(mod.id)
// bypass mock and force "importActual" behavior when:
// - mock was removed by doUnmock (stale mockedModule in meta)
if (!currentMock) {
const node = await this.fetchModule(injectQuery(url, '_vitest_original'))
return this._cachedRequest(node.url, node, callstack, metadata)
}
// - self-import: mock factory/file is importing the module it's mocking
const isStale = !this.mocker.getDependencyMock(mod.id)
const isSelfImport = callstack.includes(mockId)
|| callstack.includes(url)
|| ('redirect' in mockedModule && callstack.includes(mockedModule.redirect))
if (isStale || isSelfImport) {
|| ('redirect' in currentMock && callstack.includes(currentMock.redirect))
if (isSelfImport) {
const node = await this.fetchModule(injectQuery(url, '_vitest_original'))
return this._cachedRequest(node.url, node, callstack, metadata)
}
mocked = await this.mocker.requestWithMockedModule(
url,
mod,
callstack,
mockedModule,
)
if (currentMock !== mockedModule) {
const freshNode = await this.fetchModule(injectQuery(url, '_vitest_original'))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's a manual or redirect mock, then this is not needed because it won't be used to autospy/automock

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly I believe f394cb4 addresses this

mocked = await this.mocker.requestWithMockedModule(url, freshNode, callstack, currentMock)
}
else {
mocked = await this.mocker.requestWithMockedModule(url, mod, callstack, currentMock)
}
}
else {
mocked = await this.mocker.mockedRequest(url, mod, callstack)
Expand Down
64 changes: 63 additions & 1 deletion test/e2e/test/mocking.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { playwright } from '@vitest/browser-playwright'
import { webdriverio } from '@vitest/browser-webdriverio'
import { afterAll, expect, test } from 'vitest'
import { rolldownVersion } from 'vitest/node'
import { runInlineTests, runVitest } from '../../test-utils'
import { runInlineTests, runVitest, StableTestFileOrderSorter } from '../../test-utils'

// webdriver@9 sets dns.setDefaultResultOrder("ipv4first") on import,
// which makes Vite resolve localhost to 127.0.0.1 and breaks other tests asserting "localhost"
Expand Down Expand Up @@ -594,3 +594,65 @@ test("local", async () => {
}
`)
})

test('automocking works with isolate:false when factory mock runs first (resolve alias)', async () => {
const { stderr, testTree } = await runInlineTests({
'vitest.config.js': `
import path from 'node:path'
import { defineConfig } from 'vitest/config'

export default defineConfig({
resolve: {
alias: {
'~': path.resolve(import.meta.dirname, 'src'),
},
},
test: {
isolate: false,
},
})
`,
'./src/dep.ts': `
export function useDep(): string { return 'real' }
export function helperDep(): number { return 42 }
`,
'./a-factory.test.ts': `
import { vi, test, expect } from 'vitest'
import { useDep } from '~/dep'
vi.mock(import('~/dep'), () => ({
useDep: () => 'factory',
helperDep: () => 0,
}))
test('factory mock', () => {
expect(useDep()).toBe('factory')
})
`,
'./b-automock.test.ts': `
import { vi, test, expect } from 'vitest'
import { useDep } from '~/dep'
vi.mock(import('~/dep'))
test('automock exports are mock functions', () => {
expect(vi.isMockFunction(useDep)).toBe(true)
})
test('automock mockReturnValue works', () => {
vi.mocked(useDep).mockReturnValue('mocked')
expect(useDep()).toBe('mocked')
})
`,
}, {
sequence: { sequencer: StableTestFileOrderSorter },
})

expect(stderr).toBe('')
expect(testTree()).toMatchInlineSnapshot(`
{
"a-factory.test.ts": {
"factory mock": "passed",
},
"b-automock.test.ts": {
"automock exports are mock functions": "passed",
"automock mockReturnValue works": "passed",
},
}
`)
})
Loading