我如何在 NodeJS 中模拟 ES 模块?
How do I mock ES modules in NodeJS?
假设我实现了一个模块如下:
import { foo } from 'dep1'
export const bar = () => foo()
我如何模拟 dep1
以便我可以进行单元测试 bar
?
一种可能的方法是使用 ES 模块加载器挂钩。
假设 dep1
包含工作代码,我们想模拟它。我会创建一个名为 mymodule.mocks.mjs
的文件,我会在其中模拟 foo
:
// Regular mymodule.mjs
import { foo } from 'dep1'
export const bar = () => foo()
// Mocked mymodule.mocks.mjs
// dep1.foo() returns string
export const bar = () => 'whatever'
现在我们应该能够在测试期间请求 mymodule.mjs
时加载 mymodule.mocks.mjs
运行。
所以我们实施[=19=]
这是一个实现 *.mocks.mjs
约定的自定义模块加载器挂钩:
import { existsSync } from 'fs'
import { dirname, extname, basename, join } from 'path'
import { parse } from 'url'
// The 'specifier' is the name or path that we provide
// when we import a module (i.e. import { x } from '[[specifier]]')
export function resolve (
specifier,
parentModuleURL,
defaultResolver
) {
// For built-ins
if ( !parentModuleURL )
return defaultResolver ( specifier, parentModuleURL )
// If the specifier has no extension we provide the
// Michael Jackson extension as the default one
const moduleExt = extname ( specifier ) || '.mjs'
const moduleDir = dirname ( specifier )
const { pathname: parentModulePath } = parse (
parentModuleURL
)
const fileName = basename ( specifier, moduleExt )
// We build the possible mocks' module file path
const mockFilePath = join (
dirname ( parentModulePath ),
moduleDir,
`${fileName}.mocks${moduleExt}`
)
// If there's a file which ends with '.mocks.mjs'
// we resolve that module instead of the regular one
if ( existsSync ( mockFilePath ) )
return defaultResolver ( mockFilePath, parentModuleURL )
return defaultResolver ( specifier, parentModuleURL )
}
使用它
就是提供给node
:
node --experimental-modules --loader ./path/to/testModuleLoader.mjs ./path/to/app.mjs
Learn more 关于 ES 模块加载器钩子。
假设我实现了一个模块如下:
import { foo } from 'dep1'
export const bar = () => foo()
我如何模拟 dep1
以便我可以进行单元测试 bar
?
一种可能的方法是使用 ES 模块加载器挂钩。
假设 dep1
包含工作代码,我们想模拟它。我会创建一个名为 mymodule.mocks.mjs
的文件,我会在其中模拟 foo
:
// Regular mymodule.mjs
import { foo } from 'dep1'
export const bar = () => foo()
// Mocked mymodule.mocks.mjs
// dep1.foo() returns string
export const bar = () => 'whatever'
现在我们应该能够在测试期间请求 mymodule.mjs
时加载 mymodule.mocks.mjs
运行。
所以我们实施[=19=]
这是一个实现 *.mocks.mjs
约定的自定义模块加载器挂钩:
import { existsSync } from 'fs'
import { dirname, extname, basename, join } from 'path'
import { parse } from 'url'
// The 'specifier' is the name or path that we provide
// when we import a module (i.e. import { x } from '[[specifier]]')
export function resolve (
specifier,
parentModuleURL,
defaultResolver
) {
// For built-ins
if ( !parentModuleURL )
return defaultResolver ( specifier, parentModuleURL )
// If the specifier has no extension we provide the
// Michael Jackson extension as the default one
const moduleExt = extname ( specifier ) || '.mjs'
const moduleDir = dirname ( specifier )
const { pathname: parentModulePath } = parse (
parentModuleURL
)
const fileName = basename ( specifier, moduleExt )
// We build the possible mocks' module file path
const mockFilePath = join (
dirname ( parentModulePath ),
moduleDir,
`${fileName}.mocks${moduleExt}`
)
// If there's a file which ends with '.mocks.mjs'
// we resolve that module instead of the regular one
if ( existsSync ( mockFilePath ) )
return defaultResolver ( mockFilePath, parentModuleURL )
return defaultResolver ( specifier, parentModuleURL )
}
使用它
就是提供给node
:
node --experimental-modules --loader ./path/to/testModuleLoader.mjs ./path/to/app.mjs
Learn more 关于 ES 模块加载器钩子。