Skip to content

Commit f789f4c

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 4eb0749 commit f789f4c

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
@@ -1050,6 +1050,16 @@ generated as part of the test runner output. If no tests are run, a coverage
10501050
report is not generated. See the documentation on
10511051
[collecting code coverage from tests][] for more details.
10521052

1053+
### `--experimental-test-module-mocks`
1054+
1055+
<!-- YAML
1056+
added: REPLACEME
1057+
-->
1058+
1059+
> Stability: 1.0 - Early development
1060+
1061+
Enable module mocking in the test runner.
1062+
10531063
### `--experimental-vm-modules`
10541064

10551065
<!-- YAML

doc/api/test.md

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

1738+
## Class: `MockModuleContext`
1739+
1740+
<!-- YAML
1741+
added: REPLACEME
1742+
-->
1743+
1744+
> Stability: 1.0 - Early development
1745+
1746+
The `MockModuleContext` class is used to manipulate the behavior of module mocks
1747+
created via the [`MockTracker`][] APIs.
1748+
1749+
### `ctx.restore()`
1750+
1751+
<!-- YAML
1752+
added: REPLACEME
1753+
-->
1754+
1755+
Resets the implementation of the mock module.
1756+
17381757
## Class: `MockTracker`
17391758

17401759
<!-- YAML
@@ -1868,6 +1887,68 @@ test('spies on an object method', (t) => {
18681887
});
18691888
```
18701889

1890+
### `mock.module(specifier[, options])`
1891+
1892+
<!-- YAML
1893+
added: REPLACEME
1894+
-->
1895+
1896+
> Stability: 1.0 - Early development
1897+
1898+
* `specifier` {string} A string identifying the module to mock.
1899+
* `options` {Object} Optional configuration options for the mock module. The
1900+
following properties are supported:
1901+
* `cache` {boolean} If `false`, each call to `require()` or `import()`
1902+
generates a new mock module. If `true`, subsequent calls will return the same
1903+
module mock, and the mock module is inserted into the CommonJS cache.
1904+
**Default:** false.
1905+
* `defaultExport` {any} An optional value used as the mocked module's default
1906+
export. If this value is not provided, ESM mocks do not include a default
1907+
export. If the mock is a CommonJS or builtin module, this setting is used as
1908+
the value of `module.exports`. If this value is not provided, CJS and builtin
1909+
mocks use an empty object as the value of `module.exports`.
1910+
* `namedExports` {Object} An optional object whose keys and values are used to
1911+
create the named exports of the mock module. If the mock is a CommonJS or
1912+
builtin module, these values are copied onto `module.exports`. Therefore, if a
1913+
mock is created with both named exports and a non-object default export, the
1914+
mock will throw an exception when used as a CJS or builtin module.
1915+
* Returns: {MockModuleContext} An object that can be used to manipulate the mock.
1916+
1917+
This function is used to mock the exports of ECMAScript modules, CommonJS
1918+
modules, and Node.js builtin modules. Any references to the original module
1919+
prior to mocking are not impacted. The following example demonstrates how a mock
1920+
is created for a module.
1921+
1922+
```js
1923+
test('mocks a builtin module in both module systems', async (t) => {
1924+
// Create a mock of 'node:readline' with a named export named 'fn', which
1925+
// does not exist in the original 'node:readline' module.
1926+
const mock = t.mock.module('node:readline', {
1927+
namedExports: { fn() { return 42; } },
1928+
});
1929+
1930+
let esmImpl = await import('node:readline');
1931+
let cjsImpl = require('node:readline');
1932+
1933+
// cursorTo() is an export of the original 'node:readline' module.
1934+
assert.strictEqual(esmImpl.cursorTo, undefined);
1935+
assert.strictEqual(cjsImpl.cursorTo, undefined);
1936+
assert.strictEqual(esmImpl.fn(), 42);
1937+
assert.strictEqual(cjsImpl.fn(), 42);
1938+
1939+
mock.restore();
1940+
1941+
// The mock is restored, so the original builtin module is returned.
1942+
esmImpl = await import('node:readline');
1943+
cjsImpl = require('node:readline');
1944+
1945+
assert.strictEqual(typeof esmImpl.cursorTo, 'function');
1946+
assert.strictEqual(typeof cjsImpl.cursorTo, 'function');
1947+
assert.strictEqual(esmImpl.fn, undefined);
1948+
assert.strictEqual(cjsImpl.fn, undefined);
1949+
});
1950+
```
1951+
18711952
### `mock.reset()`
18721953

18731954
<!-- YAML

doc/node.1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,9 @@ Use this flag to enable ShadowRealm support.
188188
.It Fl -experimental-test-coverage
189189
Enable code coverage in the test runner.
190190
.
191+
.It Fl -experimental-test-module-mocks
192+
Enable module mocking in the test runner.
193+
.
191194
.It Fl -experimental-eventsource
192195
Enable experimental support for the EventSource Web API.
193196
.

0 commit comments

Comments
 (0)