1 | ```diff
|
2 | + ██╗
|
3 | + ██████╗ ███████╗ █████═████╗ ██████╗ ██████╗██║ ██╗
|
4 | +██╔═══██╗██╔═════╝██╔══██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝
|
5 | +████████║╚██████╗ ██║ ██║ ██║██║ ██║██║ ██████╔╝
|
6 | +██╔═════╝ ╚════██╗██║ ██║ ██║██║ ██║██║ ██╔══██╗
|
7 | +╚███████╗███████╔╝██║ ██║ ██║╚██████╔╝╚██████╗██║ ╚██╗
|
8 | + ╚══════╝╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝
|
9 | ```
|
10 | [![npm][9]][7] [![coverage][8]][2] [![install size][6]][5] [![downloads][10]][7]
|
11 |
|
12 | **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,][4] or browse [esmock's test runner examples.][3]
|
13 |
|
14 |
|
15 | `esmock` is used with node's --loader
|
16 | ``` json
|
17 | {
|
18 | "name": "give-esmock-a-star",
|
19 | "type": "module",
|
20 | "scripts": {
|
21 | "test": "node --loader=esmock --test",
|
22 | "test-mocha": "mocha --loader=esmock",
|
23 | "test-tap": "NODE_OPTIONS=--loader=esmock tap",
|
24 | "test-ava": "NODE_OPTIONS=--loader=esmock ava",
|
25 | "test-uvu": "NODE_OPTIONS=--loader=esmock uvu spec",
|
26 | "test-tsm": "node --loader=tsm --loader=esmock --test *ts",
|
27 | "test-ts": "node --loader=ts-node/esm --loader=esmock --test *ts",
|
28 | "test-jest": "NODE_OPTIONS=--loader=esmock jest",
|
29 | "test-tsx": "⚠ https://github.com/esbuild-kit/tsx/issues/264"
|
30 | },
|
31 | "jest": {
|
32 | "runner": "jest-light-runner"
|
33 | }
|
34 | }
|
35 | ```
|
36 |
|
37 | `esmock` has the below signature
|
38 | ``` javascript
|
39 | await esmock(
|
40 | './to/module.js', // path to target module being tested
|
41 | { ...childmocks }, // mock definitions imported by target module
|
42 | { ...globalmocks }) // mock definitions imported everywhere
|
43 | ```
|
44 |
|
45 | `esmock` examples
|
46 | ``` javascript
|
47 | import test from 'node:test'
|
48 | import assert from 'node:assert/strict'
|
49 | import esmock from 'esmock'
|
50 |
|
51 | test('package, alias and local file mocks', async () => {
|
52 | const cookup = await esmock('../src/cookup.js', {
|
53 | addpkg: (a, b) => a + b,
|
54 | '#icon': { coffee: '☕', bacon: '🥓' },
|
55 | '../src/breakfast.js': {
|
56 | default: () => ['coffee', 'bacon'],
|
57 | addSalt: meal => meal + '🧂'
|
58 | }
|
59 | })
|
60 |
|
61 | assert.equal(cookup('breakfast'), '☕🥓🧂')
|
62 | })
|
63 |
|
64 | test('full import tree mocks —third param', async () => {
|
65 | const { getFile } = await esmock('../src/main.js', {}, {
|
66 | // mocks *every* fs.readFileSync inside the import tree
|
67 | fs: { readFileSync: () => 'returned to 🌲 every caller in the tree' }
|
68 | })
|
69 |
|
70 | assert.equal(getFile(), 'returned to 🌲 every caller in the tree')
|
71 | })
|
72 |
|
73 | test('mock fetch, Date, setTimeout and any globals', async () => {
|
74 | // https://github.com/iambumblehead/esmock/wiki#call-esmock-globals
|
75 | const { userCount } = await esmock('../Users.js', {
|
76 | '../req.js': await esmock('../req.js', {
|
77 | import: { // define globals like 'fetch' on the import namespace
|
78 | fetch: async () => ({
|
79 | status: 200,
|
80 | json: async () => [['jim','😄'],['jen','😊']]
|
81 | })
|
82 | }
|
83 | })
|
84 | })
|
85 |
|
86 | assert.equal(await userCount(), 2)
|
87 | })
|
88 |
|
89 | test('mocks "await import()" using esmock.p', async () => {
|
90 | // using esmock.p, mock definitions are kept in cache
|
91 | const doAwaitImport = await esmock.p('../awaitImportLint.js', {
|
92 | eslint: { ESLint: cfg => cfg }
|
93 | })
|
94 |
|
95 | // mock definition is returned from cache, when import is called
|
96 | assert.equal(await doAwaitImport('cfg🛠️'), 'cfg🛠️')
|
97 | // a bit more info are found in the wiki guide
|
98 | })
|
99 |
|
100 | test('esmock.strict mocks', async () => {
|
101 | // replace original module definitions and do not merge them
|
102 | const pathWrapper = await esmock.strict('../src/pathWrapper.js', {
|
103 | path: { dirname: () => '/path/to/file' }
|
104 | })
|
105 |
|
106 | // error, because "path" mock above does not define path.basename
|
107 | assert.rejects(() => pathWrapper.basename('/dog.🐶.png'), {
|
108 | name: 'TypeError',
|
109 | message: 'path.basename is not a function'
|
110 | })
|
111 | })
|
112 | ```
|
113 |
|
114 | [0]: https://www.bumblehead.com "bumblehead"
|
115 | [1]: https://github.com/iambumblehead/esmock/workflows/nodejs-ci/badge.svg "nodejs-ci pipeline"
|
116 | [2]: https://github.com/iambumblehead/esmock "esmock"
|
117 | [3]: https://github.com/iambumblehead/esmock/tree/master/tests "tests"
|
118 | [4]: https://github.com/iambumblehead/esmock/wiki
|
119 | [5]: https://packagephobia.now.sh/result?p=esmock
|
120 | [6]: https://packagephobia.now.sh/badge?p=esmock
|
121 | [7]: https://www.npmjs.com/package/esmock
|
122 | [8]: https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/iambumblehead/166d927bd0089d7bfdee4e98a537712c/raw/esmock__heads_master.json
|
123 | [9]: https://img.shields.io/npm/v/esmock
|
124 | [10]: https://badgen.now.sh/npm/dm/esmock
|