Skip to content

Commit 7a67ecf

Browse files
cjihrigtargos
authored andcommitted
test_runner: support module mocking
This commit adds experimental module mocking to the test runner. PR-URL: #52848 Fixes: #51164 Reviewed-By: Benjamin Gruenbaum <[email protected]> Reviewed-By: Moshe Atlow <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]> Reviewed-By: Geoffrey Booth <[email protected]>
1 parent fe00bec commit 7a67ecf

File tree

14 files changed

+1336
-12
lines changed

14 files changed

+1336
-12
lines changed

doc/api/cli.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,16 @@ generated as part of the test runner output. If no tests are run, a coverage
979979
report is not generated. See the documentation on
980980
[collecting code coverage from tests][] for more details.
981981

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

984994
<!-- YAML

doc/api/test.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,6 +1767,25 @@ added:
17671767
Resets the implementation of the mock function to its original behavior. The
17681768
mock can still be used after calling this function.
17691769

1770+
## Class: `MockModuleContext`
1771+
1772+
<!-- YAML
1773+
added: REPLACEME
1774+
-->
1775+
1776+
> Stability: 1.0 - Early development
1777+
1778+
The `MockModuleContext` class is used to manipulate the behavior of module mocks
1779+
created via the [`MockTracker`][] APIs.
1780+
1781+
### `ctx.restore()`
1782+
1783+
<!-- YAML
1784+
added: REPLACEME
1785+
-->
1786+
1787+
Resets the implementation of the mock module.
1788+
17701789
## Class: `MockTracker`
17711790

17721791
<!-- YAML
@@ -1900,6 +1919,68 @@ test('spies on an object method', (t) => {
19001919
});
19011920
```
19021921

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

19051986
<!-- YAML

doc/node.1

Lines changed: 3 additions & 0 deletions
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)