provides native ESM import and globals mocking for unit tests


Keywords
esm, es module, mjs, unit-test, esmock, import, module, loader, load, export, require, experimental, es6, dependency, injection, dependency injection, mock dependency, di, inject, swap, test, mock, ava, modules, mocking, proxyquire, rewire, global, fetch, mock fetch, globals, mocking-modules
License
ISC
Install
npm install esmock@2.2.3

Documentation

+                                                β–ˆβ–ˆβ•—
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•β–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—  β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•—
+β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•”β•
+β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘     β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•
+β–ˆβ–ˆβ•”β•β•β•β•β•β• β•šβ•β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘   β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘     β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—
+β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘  β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘  β•šβ–ˆβ–ˆβ•—
+ β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β• β•šβ•β•  β•šβ•β•  β•šβ•β• β•šβ•β•β•β•β•β•  β•šβ•β•β•β•β•β•β•šβ•β•   β•šβ•β•

npm coverage install size downloads

esmock provides native ESM import and globals mocking for unit tests. Use examples below as a quick-start guide, see the descriptive and friendly esmock guide here, or browse esmock's test runner examples.

Note: For versions of node prior to v20.6.0, "--loader" command line arguments must be used with esmock as demonstrated in the wiki. Current versions of node do not require "--loader".

Note: due to --loader issues, support for ava and jest are dropped.

esmock has the below signature

await esmock(
  './to/module.js', // path to target module being tested
  { ...childmocks }, // mock definitions imported by target module
  { ...globalmocks }) // mock definitions imported everywhere

esmock examples

import test from 'node:test'
import assert from 'node:assert'
import esmock from 'esmock'

test('package, alias and local file mocks', async () => {
  const cookup = await esmock('../src/cookup.js', {
    addpkg: (a, b) => a + b,
    '#icon': { coffee: 'β˜•', bacon: 'πŸ₯“' },
    '../src/breakfast.js': {
      default: () => ['coffee', 'bacon'],
      addSalt: meal => meal + 'πŸ§‚'
    }
  })

  assert.equal(cookup('breakfast'), 'β˜•πŸ₯“πŸ§‚')
})

test('full import tree mocks β€”third param', async () => {
  const { getFile } = await esmock('../src/main.js', {}, {
    // mocks *every* fs.readFileSync inside the import tree
    fs: { readFileSync: () => 'returned to 🌲 every caller in the tree' }
  })

  assert.equal(getFile(), 'returned to 🌲 every caller in the tree')
})

test('mock fetch, Date, setTimeout and any globals', async () => {
  // https://github.com/iambumblehead/esmock/wiki#call-esmock-globals
  const { userCount } = await esmock('../Users.js', {
    '../req.js': await esmock('../req.js', {
      import: { // define globals like 'fetch' on the import namespace
        fetch: async () => ({
          status: 200,
          json: async () => [['jim','πŸ˜„'],['jen','😊']]
        })
      }
    })
  })

  assert.equal(await userCount(), 2)
})

test('mocks "await import()" using esmock.p', async () => {
  // using esmock.p, mock definitions are kept in cache
  const doAwaitImport = await esmock.p('../awaitImportLint.js', {
    eslint: { ESLint: cfg => cfg }
  })

  // mock definition is returned from cache, when import is called
  assert.equal(await doAwaitImport('cfgπŸ› οΈ'), 'cfgπŸ› οΈ')
  // a bit more info are found in the wiki guide
})

test('esmock.strict mocks', async () => {
  // replace original module definitions and do not merge them
  const pathWrapper = await esmock.strict('../src/pathWrapper.js', {
    path: { dirname: () => '/path/to/file' }
  })

  // error, because "path" mock above does not define path.basename
  assert.rejects(() => pathWrapper.basename('/dog.🐢.png'), {
    name: 'TypeError',
    message: 'path.basename is not a function'
  })
})