Skip to content

Commit 89d9a7e

Browse files
committed
test_runner: support test plans
1 parent a21b15a commit 89d9a7e

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

lib/internal/test_runner/test.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ const {
8585
testOnlyFlag,
8686
} = parseCommandLine();
8787
let kResistStopPropagation;
88+
let assertObj;
8889
let findSourceMap;
8990

9091
function lazyFindSourceMap(file) {
@@ -95,6 +96,34 @@ function lazyFindSourceMap(file) {
9596
return findSourceMap(file);
9697
}
9798

99+
function lazyAssertObject() {
100+
if (assertObj === undefined) {
101+
const assert = require('assert');
102+
103+
assertObj = new SafeMap([
104+
['deepEqual', assert.deepEqual],
105+
['deepStrictEqual', assert.deepStrictEqual],
106+
['doesNotMatch', assert.doesNotMatch],
107+
['doesNotReject', assert.doesNotReject],
108+
['doesNotThrow', assert.doesNotThrow],
109+
['equal', assert.equal],
110+
['fail', assert.fail],
111+
['ifError', assert.ifError],
112+
['match', assert.match],
113+
['notDeepEqual', assert.notDeepEqual],
114+
['notDeepStrictEqual', assert.notDeepStrictEqual],
115+
['notEqual', assert.notEqual],
116+
['notStrictEqual', assert.notStrictEqual],
117+
['ok', assert.ok],
118+
['rejects', assert.rejects],
119+
['strictEqual', assert.strictEqual],
120+
['throws', assert.throws],
121+
]);
122+
}
123+
124+
return assertObj;
125+
}
126+
98127
function stopTest(timeout, signal) {
99128
const deferred = createDeferredPromise();
100129
const abortListener = addAbortListener(signal, deferred.resolve);
@@ -134,7 +163,25 @@ function stopTest(timeout, signal) {
134163
return deferred.promise;
135164
}
136165

166+
class TestPlan {
167+
constructor(count) {
168+
validateUint32(count, 'count', 0);
169+
this.expected = count;
170+
this.actual = 0;
171+
}
172+
173+
check() {
174+
if (this.actual !== this.expected) {
175+
throw new ERR_TEST_FAILURE(
176+
`plan expected ${this.expected} assertions but received ${this.actual}`,
177+
kTestCodeFailure,
178+
);
179+
}
180+
}
181+
}
182+
137183
class TestContext {
184+
#assert;
138185
#test;
139186

140187
constructor(test) {
@@ -161,6 +208,38 @@ class TestContext {
161208
this.#test.diagnostic(message);
162209
}
163210

211+
plan(count) {
212+
if (this.#test.plan !== null) {
213+
throw new ERR_TEST_FAILURE(
214+
'cannot set plan more than once',
215+
kTestCodeFailure,
216+
);
217+
}
218+
219+
this.#test.plan = new TestPlan(count);
220+
}
221+
222+
get assert() {
223+
if (this.#assert === undefined) {
224+
const { plan } = this.#test;
225+
const map = lazyAssertObject();
226+
const assert = { __proto__: null };
227+
228+
this.#assert = assert;
229+
map.forEach((method, name) => {
230+
assert[name] = function(...args) {
231+
if (plan !== null) {
232+
plan.actual++;
233+
}
234+
235+
return ReflectApply(method, assert, args);
236+
};
237+
});
238+
}
239+
240+
return this.#assert;
241+
}
242+
164243
get mock() {
165244
this.#test.mock ??= new MockTracker();
166245
return this.#test.mock;
@@ -347,6 +426,7 @@ class Test extends AsyncResource {
347426
this.fn = fn;
348427
this.harness = null; // Configured on the root test by the test harness.
349428
this.mock = null;
429+
this.plan = null;
350430
this.cancelled = false;
351431
this.skipped = skip !== undefined && skip !== false;
352432
this.isTodo = todo !== undefined && todo !== false;
@@ -708,6 +788,7 @@ class Test extends AsyncResource {
708788
return;
709789
}
710790

791+
this.plan?.check();
711792
this.pass();
712793
try {
713794
await afterEach();

0 commit comments

Comments
 (0)