Skip to content

Commit

Permalink
fix(mocker): respect namespace import when hoisting vi.mock (#3547)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va committed Jun 9, 2023
1 parent bc283ae commit 158c4bb
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 9 deletions.
26 changes: 17 additions & 9 deletions packages/vitest/src/node/hoistMocks.ts
@@ -1,5 +1,5 @@
import MagicString from 'magic-string'
import type { CallExpression, Identifier, ImportDeclaration, VariableDeclaration, Node as _Node } from 'estree'
import type { CallExpression, Identifier, ImportDeclaration, ImportNamespaceSpecifier, VariableDeclaration, Node as _Node } from 'estree'
import { findNodeAround, simple as simpleWalk } from 'acorn-walk'
import type { AcornNode } from 'rollup'

Expand All @@ -24,11 +24,6 @@ function isIdentifier(node: any): node is Positioned<Identifier> {
}

function transformImportSpecifiers(node: ImportDeclaration) {
const specifiers = node.specifiers

if (specifiers.length === 1 && specifiers[0].type === 'ImportNamespaceSpecifier')
return specifiers[0].local.name

const dynamicImports = node.specifiers.map((specifier) => {
if (specifier.type === 'ImportDefaultSpecifier')
return `default: ${specifier.local.name}`
Expand Down Expand Up @@ -86,12 +81,25 @@ export function hoistMocks(code: string, id: string, parse: (code: string, optio
const transformImportDeclaration = (node: ImportDeclaration) => {
const source = node.source.value as string

const namespace = node.specifiers.find(specifier => specifier.type === 'ImportNamespaceSpecifier') as ImportNamespaceSpecifier | undefined

let code = ''
if (namespace)
code += `const ${namespace.local.name} = await import('${source}')\n`

// if we don't hijack ESM and process this file, then we definetly have mocks,
// so we need to transform imports into dynamic ones, so "vi.mock" can be executed before
const specifiers = transformImportSpecifiers(node)
const code = specifiers
? `const ${specifiers} = await import('${source}')\n`
: `await import('${source}')\n`

if (specifiers) {
if (namespace)
code += `const ${specifiers} = ${namespace.local.name}\n`
else
code += `const ${specifiers} = await import('${source}')\n`
}
else if (!namespace) {
code += `await import('${source}')\n`
}
return code
}

Expand Down
13 changes: 13 additions & 0 deletions test/core/test/injector-mock.test.ts
Expand Up @@ -58,3 +58,16 @@ test('always hoists all imports but they are under mocks', () => {
const { someValue2 } = await import('./path2.js')"
`)
})

test('correctly mocks namespaced', () => {
expect(hoistSimpleCode(`
import { vi } from 'vitest'
import add, * as AddModule from '../src/add'
vi.mock('../src/add', () => {})
`)).toMatchInlineSnapshot(`
"const { vi } = await import('vitest')
vi.mock('../src/add', () => {})
const AddModule = await import('../src/add')
const { default: add } = AddModule"
`)
})

0 comments on commit 158c4bb

Please sign in to comment.