11const pendingCalls = [ ] ;
22
3- /**
4- * Wraps a function and asserts it is called exactly `exact` times before the
5- * process exits. If `fn` is omitted, a no-op function is used.
6- *
7- * Usage:
8- * promise.then(mustCall((result) => {
9- * assert.strictEqual(result, 42);
10- * }));
11- */
12- const mustCall = ( fn , exact = 1 ) => {
3+ // `expected` is a lower bound when `atLeast` is set, an exact count otherwise.
4+ const track = ( fn , expected , atLeast ) => {
135 const entry = {
14- exact,
6+ expected,
7+ atLeast,
158 actual : 0 ,
169 name : fn ?. name || '<anonymous>' ,
1710 error : new Error ( ) , // capture call-site stack
@@ -23,6 +16,25 @@ const mustCall = (fn, exact = 1) => {
2316 } ;
2417} ;
2518
19+ /**
20+ * Wraps a function and asserts it is called exactly `exact` times before the
21+ * process exits. If `fn` is omitted, a no-op function is used.
22+ *
23+ * Usage:
24+ * promise.then(mustCall((result) => {
25+ * assert.strictEqual(result, 42);
26+ * }));
27+ */
28+ const mustCall = ( fn , exact = 1 ) => track ( fn , exact , false ) ;
29+
30+ /**
31+ * Like `mustCall`, but asserts only a lower bound: the wrapper must be called
32+ * at least `minimum` times, and any number of further calls is fine. Use it
33+ * when the runtime decides how often a callback fires (e.g. a proxy trap the
34+ * engine may consult more than once).
35+ */
36+ const mustCallAtLeast = ( fn , minimum = 1 ) => track ( fn , minimum , true ) ;
37+
2638/**
2739 * Returns a function that throws immediately if called.
2840 */
@@ -34,13 +46,17 @@ const mustNotCall = (msg) => {
3446
3547process . on ( 'exit' , ( ) => {
3648 for ( const entry of pendingCalls ) {
37- if ( entry . actual !== entry . exact ) {
49+ const satisfied = entry . atLeast ?
50+ entry . actual >= entry . expected :
51+ entry . actual === entry . expected ;
52+ if ( ! satisfied ) {
3853 entry . error . message =
39- `mustCall "${ entry . name } " expected ${ entry . exact } call(s) ` +
54+ `mustCall${ entry . atLeast ? 'AtLeast' : '' } "${ entry . name } " expected ` +
55+ `${ entry . atLeast ? 'at least ' : '' } ${ entry . expected } call(s) ` +
4056 `but got ${ entry . actual } ` ;
4157 throw entry . error ;
4258 }
4359 }
4460} ) ;
4561
46- Object . assign ( globalThis , { mustCall, mustNotCall } ) ;
62+ Object . assign ( globalThis , { mustCall, mustCallAtLeast , mustNotCall } ) ;
0 commit comments