esmock
esmock provides simple, native ESM import mocking on a per-unit basis.
Quick Start
To get started, simply install esmock
, and update your test script to include it as a loader.
Note: esmock must be used with node's experimental --loader
- Install
esmock
:
$ npm i -D esmock
- Update the
test
script in your package.json
:
{
"type": "module",
"scripts": {
"test-ava": "ava --node-arguments=\"--loader=esmock\"",
"test-mocha": "mocha --loader=esmock --no-warnings"
}
}
Mocking ESM Imports inside Unit Tests
Mocking is very simple and can be done on a per-unit basis. This means that each unit in your test file can be mocked differently, to allow for mocking out various scenarios.
The syntax is very simple:
const targetModuleExports = await esmock(targetModule, childMocks, globalMocks)
targetModule
: The path to the module you'll be testing.targetModuleExports
: Anything that targetModule
exports.childMocks
: Modules imported into targetModule
that you want to mock.globalMocks
: Optional Modules that you always want to mock, even if they're not directly imported by targetModule
.
The targetModuleExports
is the default export, or it can be destructured to retrieve named exports.
const defaultExport = await esmock('../src/my-module.js', childMocks, globalMocks)
const { default: defaultExport, namedExport } = await esmock('../src/my-module.js', childMocks, globalMocks)
The *mocks
parameters follow the below syntax:
childMocks | globalMocks = {
'npm-pkg-name': {
default: __mock_value__,
namedExport: __mock_value__
},
'../relative/path/to/imported/file.js': {
default: __mock_value__,
namedExport: __mock_value__
}
}
Where __mock_value__
could be a string
, function
, class
, or anything else, depending on the module/file you're importing in your target.
Example
Here's an example that demonstrates mocking a named module, as well as a local JS file. In this example, we're testing the ./src/main.js
and mocking the modules and files that it imports.
./src/main.js:
import serializer from 'serializepkg';
import someDefaultExport from './someModule.js';
export default () => {
const json = serializer(someDefaultExport());
return json;
}
./tests/main.js:
test('should mock modules and local files at same time', async t => {
const main = await esmock('../src/main.js', {
serializepkg: {
default: obj => JSON.stringify(obj)
},
'../src/someModule.js' : {
default: () => ({ foo: 'bar' })
}
});
t.is(main(), JSON.stringify({ foo: 'bar' }));
});
Example, mocking await import('modulename')
Before esmock
returns a module, by default it deletes mocked definitions for that module. To use 'await import', call esmock.p( ... )
instead of esmock( ... )
so that async imports may use mock definitions during test runtime and after the module is returned.
Foe example, let's test this file using await import('eslint')
,
export default async function usesAwaitImport (config) {
const eslint = await import('eslint');
return new eslint.ESLint(config);
};
Use esmock.p()
rather than esmock()
to load that file,
test('should mock module using inline async import`', async t => {
const usesAwaitImport = await esmock.p('./local/usesAwaitImport.mjs', {
eslint : {
ESLint : o => o
}
});
t.is(await usesAwaitImport('config'), 'config');
esmock.purge(usesAwaitImport);
});
If there are not many tests or if tests complete in separate processes, skipping esmock.purge()
is OK (if you don't have hundreds of tests, its OK to skip)
changelog
- 1.3.1 Nov.26.2021
- add npm keywords, remove lines of code
- 1.3.0 Nov.26.2021
- add support for await import, update README
- 1.1.0 Nov.25.2021
- add windows-latest to testing pipeline and begin windows support
- removed files and functions no longer needed
- increment resolvewithplus package and other dependencies
- 1.0.1 Nov.02.2021
- add node v17.x to testing pipeline
- add, make warning message go away for node 16.12.0+
- 1.0.0 Oct.27.2021
- 0.4.2 Oct.27.2021
- export 'load' hook from moduleLoader, required by node v16.12.0+
- 0.4.1 Oct.10.2021
- version bump, increment devDependencies,
- major improvement to README, thanks @swivelgames
- 0.4.0 Sep.07.2021
- do not runtime error when returning type '[object Module]' default
- 0.3.9 May.05.2021
- small change to README
- added a test, update gitlab action to use node 16.x
- 0.3.8 Apr.21.2021
- 0.3.7 Apr.20.2021
- add test, throw error if mocked module path is not found
- 0.3.6 Apr.19.2021
- throw error if mocked module path is not found
- 0.3.5 Apr.18.2021
- added gitlab actions npm test: node 12.x, 14.x and 15.x
- 0.3.3 Apr.13.2021
- added keywords to package.json, use github action to npm publish
- 0.3.1 Apr.12.2021
- 0.3.0 Apr.10.2021
- adds support for mocking modules 'globally' for the instance
- 0.2.0 Apr.10.2021
- adds support for mocking core modules such as fs and path
- 0.1.0 Apr.10.2021
- adds support for native esm modules