Skip to content

Commit 79bfc35

Browse files
committed
test_runner: support module mocking
This commit adds experimental module mocking to the test runner.
1 parent c7e4209 commit 79bfc35

File tree

14 files changed

+1327
-12
lines changed

14 files changed

+1327
-12
lines changed

Diff for: doc/api/cli.md

+8
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,14 @@ generated as part of the test runner output. If no tests are run, a coverage
942942
report is not generated. See the documentation on
943943
[collecting code coverage from tests][] for more details.
944944

945+
### `--experimental-test-module-mocks`
946+
947+
<!-- YAML
948+
added: REPLACEME
949+
-->
950+
951+
Enable module mocking in the test runner.
952+
945953
### `--experimental-vm-modules`
946954

947955
<!-- YAML

Diff for: doc/api/test.md

+77
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,23 @@ added:
17631763
Resets the implementation of the mock function to its original behavior. The
17641764
mock can still be used after calling this function.
17651765

1766+
## Class: `MockModuleContext`
1767+
1768+
<!-- YAML
1769+
added: REPLACEME
1770+
-->
1771+
1772+
The `MockModuleContext` class is used to manipulate the behavior of module mocks
1773+
created via the [`MockTracker`][] APIs.
1774+
1775+
### `ctx.restore()`
1776+
1777+
<!-- YAML
1778+
added: REPLACEME
1779+
-->
1780+
1781+
Resets the implementation of the mock module.
1782+
17661783
## Class: `MockTracker`
17671784

17681785
<!-- YAML
@@ -1896,6 +1913,66 @@ test('spies on an object method', (t) => {
18961913
});
18971914
```
18981915

1916+
### `mock.module(specifier[, options])`
1917+
1918+
<!-- YAML
1919+
added: REPLACEME
1920+
-->
1921+
1922+
* `specifier` {string} A string identifying the module to mock.
1923+
* `options` {Object} Optional configuration options for the mock module. The
1924+
following properties are supported:
1925+
* `cache` {boolean} If `false`, each call to `require()` or `import()`
1926+
generates a new mock module. If `true`, subsequent calls will return the same
1927+
module mock, and the mock module is inserted into the CommonJS cache.
1928+
**Default:** false.
1929+
* `defaultExport` {any} An optional value used as the mocked module's default
1930+
export. If this value is not provided, ESM mocks do not include a default
1931+
export. If the mock is a CommonJS or builtin module, this setting is used as
1932+
the value of `module.exports`. If this value is not provided, CJS and builtin
1933+
mocks use an empty object as the value of `module.exports`.
1934+
* `namedExports` {Object} An optional object whose keys and values are used to
1935+
create the named exports of the mock module. If the mock is a CommonJS or
1936+
builtin module, these values are copied onto `module.exports`. Therefor, if a
1937+
mock is created with both named exports and a non-object default export, the
1938+
mock will create an exception when used as a CJS or builtin module.
1939+
* Returns: {MockModuleContext} An object that can be used to manipulate the mock.
1940+
1941+
This function is used to mock the exports of ECMAScript modules, CommonJS
1942+
modules, and Node.js builtin modules. Any references to the original module
1943+
prior to mocking are not impacted. The following example demonstrates how a mock
1944+
is created for a module.
1945+
1946+
```js
1947+
test('mocks a builtin module in both module systems', async (t) => {
1948+
// Create a mock of 'node:readline' with a named export named 'fn', which
1949+
// does not exist in the original 'node:readline' module.
1950+
const mock = t.mock.module('node:readline', {
1951+
namedExports: { fn() { return 42; } },
1952+
});
1953+
1954+
let esmImpl = await import('node:readline');
1955+
let cjsImpl = require('node:readline');
1956+
1957+
// cursorTo() is an export of the original 'node:readline' module.
1958+
assert.strictEqual(esmImpl.cursorTo, undefined);
1959+
assert.strictEqual(cjsImpl.cursorTo, undefined);
1960+
assert.strictEqual(esmImpl.fn(), 42);
1961+
assert.strictEqual(cjsImpl.fn(), 42);
1962+
1963+
mock.restore();
1964+
1965+
// The mock is restored, so the original builtin module is returned.
1966+
esmImpl = await import('node:readline');
1967+
cjsImpl = require('node:readline');
1968+
1969+
assert.strictEqual(typeof esmImpl.cursorTo, 'function');
1970+
assert.strictEqual(typeof cjsImpl.cursorTo, 'function');
1971+
assert.strictEqual(esmImpl.fn, undefined);
1972+
assert.strictEqual(cjsImpl.fn, undefined);
1973+
});
1974+
```
1975+
18991976
### `mock.reset()`
19001977

19011978
<!-- YAML

Diff for: doc/node.1

+3
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,9 @@ Use this flag to enable ShadowRealm support.
183183
.It Fl -experimental-test-coverage
184184
Enable code coverage in the test runner.
185185
.
186+
.It Fl -experimental-test-module-mocks
187+
Enable module mocking in the test runner.
188+
.
186189
.It Fl -no-experimental-websocket
187190
Disable experimental support for the WebSocket API.
188191
.

0 commit comments

Comments
 (0)