Skip to content

Commit cb1caed

Browse files
committed
test_runner: support module mocking
This commit adds experimental module mocking to the test runner.
1 parent 28b0a58 commit cb1caed

File tree

14 files changed

+1325
-12
lines changed

14 files changed

+1325
-12
lines changed

doc/api/cli.md

+10
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,16 @@ generated as part of the test runner output. If no tests are run, a coverage
981981
report is not generated. See the documentation on
982982
[collecting code coverage from tests][] for more details.
983983

984+
### `--experimental-test-module-mocks`
985+
986+
<!-- YAML
987+
added: REPLACEME
988+
-->
989+
990+
> Stability: 1.0 - Early development
991+
992+
Enable module mocking in the test runner.
993+
984994
### `--experimental-vm-modules`
985995

986996
<!-- YAML

doc/api/test.md

+81
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,25 @@ added:
17751775
Resets the implementation of the mock function to its original behavior. The
17761776
mock can still be used after calling this function.
17771777

1778+
## Class: `MockModuleContext`
1779+
1780+
<!-- YAML
1781+
added: REPLACEME
1782+
-->
1783+
1784+
> Stability: 1.0 - Early development
1785+
1786+
The `MockModuleContext` class is used to manipulate the behavior of module mocks
1787+
created via the [`MockTracker`][] APIs.
1788+
1789+
### `ctx.restore()`
1790+
1791+
<!-- YAML
1792+
added: REPLACEME
1793+
-->
1794+
1795+
Resets the implementation of the mock module.
1796+
17781797
## Class: `MockTracker`
17791798

17801799
<!-- YAML
@@ -1908,6 +1927,68 @@ test('spies on an object method', (t) => {
19081927
});
19091928
```
19101929

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

19131994
<!-- YAML

doc/node.1

+3
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,9 @@ Use this flag to enable ShadowRealm support.
185185
.It Fl -experimental-test-coverage
186186
Enable code coverage in the test runner.
187187
.
188+
.It Fl -experimental-test-module-mocks
189+
Enable module mocking in the test runner.
190+
.
188191
.It Fl -experimental-eventsource
189192
Enable experimental support for the EventSource Web API.
190193
.

0 commit comments

Comments
 (0)