Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3143566

Browse filesBrowse files
cjihrigRafaelGSS
authored andcommitted
test_runner: add assert.register() API
This commit adds a top level assert.register() API to the test runner. This function allows users to define their own custom assertion functions on the TestContext. Fixes: #52033 PR-URL: #56434 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com>
1 parent 332ce54 commit 3143566
Copy full SHA for 3143566

File tree

Expand file treeCollapse file tree

5 files changed

+166
-34
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+166
-34
lines changed
Open diff view settings
Collapse file

‎doc/api/test.md‎

Copy file name to clipboardExpand all lines: doc/api/test.md
+23Lines changed: 23 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,29 @@ describe('tests', async () => {
17481748
});
17491749
```
17501750

1751+
## `assert`
1752+
1753+
<!-- YAML
1754+
added: REPLACEME
1755+
-->
1756+
1757+
An object whose methods are used to configure available assertions on the
1758+
`TestContext` objects in the current process. The methods from `node:assert`
1759+
and snapshot testing functions are available by default.
1760+
1761+
It is possible to apply the same configuration to all files by placing common
1762+
configuration code in a module
1763+
preloaded with `--require` or `--import`.
1764+
1765+
### `assert.register(name, fn)`
1766+
1767+
<!-- YAML
1768+
added: REPLACEME
1769+
-->
1770+
1771+
Defines a new assertion function with the provided name and function. If an
1772+
assertion already exists with the same name, it is overwritten.
1773+
17511774
## `snapshot`
17521775

17531776
<!-- YAML
Collapse file

‎lib/internal/test_runner/assert.js‎

Copy file name to clipboard
+50Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'use strict';
2+
const {
3+
SafeMap,
4+
} = primordials;
5+
const {
6+
validateFunction,
7+
validateString,
8+
} = require('internal/validators');
9+
const assert = require('assert');
10+
const methodsToCopy = [
11+
'deepEqual',
12+
'deepStrictEqual',
13+
'doesNotMatch',
14+
'doesNotReject',
15+
'doesNotThrow',
16+
'equal',
17+
'fail',
18+
'ifError',
19+
'match',
20+
'notDeepEqual',
21+
'notDeepStrictEqual',
22+
'notEqual',
23+
'notStrictEqual',
24+
'partialDeepStrictEqual',
25+
'rejects',
26+
'strictEqual',
27+
'throws',
28+
];
29+
let assertMap;
30+
31+
function getAssertionMap() {
32+
if (assertMap === undefined) {
33+
assertMap = new SafeMap();
34+
35+
for (let i = 0; i < methodsToCopy.length; i++) {
36+
assertMap.set(methodsToCopy[i], assert[methodsToCopy[i]]);
37+
}
38+
}
39+
40+
return assertMap;
41+
}
42+
43+
function register(name, fn) {
44+
validateString(name, 'name');
45+
validateFunction(fn, 'fn');
46+
const map = getAssertionMap();
47+
map.set(name, fn);
48+
}
49+
50+
module.exports = { getAssertionMap, register };
Collapse file

‎lib/internal/test_runner/test.js‎

Copy file name to clipboardExpand all lines: lib/internal/test_runner/test.js
+18-34Lines changed: 18 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -100,34 +100,15 @@ function lazyFindSourceMap(file) {
100100

101101
function lazyAssertObject(harness) {
102102
if (assertObj === undefined) {
103-
assertObj = new SafeMap();
104-
const assert = require('assert');
105-
const { SnapshotManager } = require('internal/test_runner/snapshot');
106-
const methodsToCopy = [
107-
'deepEqual',
108-
'deepStrictEqual',
109-
'doesNotMatch',
110-
'doesNotReject',
111-
'doesNotThrow',
112-
'equal',
113-
'fail',
114-
'ifError',
115-
'match',
116-
'notDeepEqual',
117-
'notDeepStrictEqual',
118-
'notEqual',
119-
'notStrictEqual',
120-
'partialDeepStrictEqual',
121-
'rejects',
122-
'strictEqual',
123-
'throws',
124-
];
125-
for (let i = 0; i < methodsToCopy.length; i++) {
126-
assertObj.set(methodsToCopy[i], assert[methodsToCopy[i]]);
127-
}
103+
const { getAssertionMap } = require('internal/test_runner/assert');
104+
105+
assertObj = getAssertionMap();
106+
if (!assertObj.has('snapshot')) {
107+
const { SnapshotManager } = require('internal/test_runner/snapshot');
128108

129-
harness.snapshotManager = new SnapshotManager(harness.config.updateSnapshots);
130-
assertObj.set('snapshot', harness.snapshotManager.createAssert());
109+
harness.snapshotManager = new SnapshotManager(harness.config.updateSnapshots);
110+
assertObj.set('snapshot', harness.snapshotManager.createAssert());
111+
}
131112
}
132113
return assertObj;
133114
}
@@ -264,15 +245,18 @@ class TestContext {
264245
};
265246
});
266247

267-
// This is a hack. It allows the innerOk function to collect the stacktrace from the correct starting point.
268-
function ok(...args) {
269-
if (plan !== null) {
270-
plan.actual++;
248+
if (!map.has('ok')) {
249+
// This is a hack. It allows the innerOk function to collect the
250+
// stacktrace from the correct starting point.
251+
function ok(...args) {
252+
if (plan !== null) {
253+
plan.actual++;
254+
}
255+
innerOk(ok, args.length, ...args);
271256
}
272-
innerOk(ok, args.length, ...args);
273-
}
274257

275-
assert.ok = ok;
258+
assert.ok = ok;
259+
}
276260
}
277261
return this.#assert;
278262
}
Collapse file

‎lib/test.js‎

Copy file name to clipboardExpand all lines: lib/test.js
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,15 @@ ObjectDefineProperty(module.exports, 'snapshot', {
6161
return lazySnapshot;
6262
},
6363
});
64+
65+
ObjectDefineProperty(module.exports, 'assert', {
66+
__proto__: null,
67+
configurable: true,
68+
enumerable: true,
69+
get() {
70+
const { register } = require('internal/test_runner/assert');
71+
const assert = { __proto__: null, register };
72+
ObjectDefineProperty(module.exports, 'assert', assert);
73+
return assert;
74+
},
75+
});
Collapse file
+63Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
'use strict';
2+
require('../common');
3+
const assert = require('node:assert');
4+
const { test, assert: testAssertions } = require('node:test');
5+
6+
testAssertions.register('isOdd', (n) => {
7+
assert.strictEqual(n % 2, 1);
8+
});
9+
10+
testAssertions.register('ok', () => {
11+
return 'ok';
12+
});
13+
14+
testAssertions.register('snapshot', () => {
15+
return 'snapshot';
16+
});
17+
18+
testAssertions.register('deepStrictEqual', () => {
19+
return 'deepStrictEqual';
20+
});
21+
22+
testAssertions.register('context', function() {
23+
return this;
24+
});
25+
26+
test('throws if name is not a string', () => {
27+
assert.throws(() => {
28+
testAssertions.register(5);
29+
}, {
30+
code: 'ERR_INVALID_ARG_TYPE',
31+
message: 'The "name" argument must be of type string. Received type number (5)'
32+
});
33+
});
34+
35+
test('throws if fn is not a function', () => {
36+
assert.throws(() => {
37+
testAssertions.register('foo', 5);
38+
}, {
39+
code: 'ERR_INVALID_ARG_TYPE',
40+
message: 'The "fn" argument must be of type function. Received type number (5)'
41+
});
42+
});
43+
44+
test('invokes a custom assertion as part of the test plan', (t) => {
45+
t.plan(2);
46+
t.assert.isOdd(5);
47+
assert.throws(() => {
48+
t.assert.isOdd(4);
49+
}, {
50+
code: 'ERR_ASSERTION',
51+
message: /Expected values to be strictly equal/
52+
});
53+
});
54+
55+
test('can override existing assertions', (t) => {
56+
assert.strictEqual(t.assert.ok(), 'ok');
57+
assert.strictEqual(t.assert.snapshot(), 'snapshot');
58+
assert.strictEqual(t.assert.deepStrictEqual(), 'deepStrictEqual');
59+
});
60+
61+
test('"this" is set to the TestContext', (t) => {
62+
assert.strictEqual(t.assert.context(), t);
63+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.