{"record":{"id":"53870b29e35e9e9b","repo":"denoland/deno","slug":"err-assertion-53870b","errorCode":"ERR_ASSERTION","errorMessage":"Functions were not called the expected number of times","messagePattern":"Functions were not called the expected number of times","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"ext/node/polyfills/internal/assert/calltracker.js","lineNumber":160,"sourceCode":"    const errors = [];\n    for (const context of new SafeSetIterator(this.#callChecks)) {\n      const message = context.report();\n      if (message !== undefined) {\n        ArrayPrototypePush(errors, message);\n      }\n    }\n    return errors;\n  }\n\n  verify() {\n    const errors = this.report();\n    if (errors.length === 0) {\n      return;\n    }\n    const message = errors.length === 1\n      ? errors[0].message\n      : \"Functions were not called the expected number of times\";\n    throw new AssertionError({\n      message,\n      details: errors,\n    });\n  }\n}\n\nreturn {\n  CallTracker,\n};\n})();\n","sourceCodeStart":142,"sourceCodeEnd":171,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/node/polyfills/internal/assert/calltracker.js#L142-L171","documentation":"tracker.verify() runs report(), which compares each tracked function's actual call count against its expected count. Any mismatch throws AssertionError: with exactly one failure the message is that failure's own message; with two or more it is the aggregate 'Functions were not called the expected number of times', and err.details carries every mismatch (including expected/actual counts and the registered stack). This is the intended failure mode of a behavioral assertion, not an infrastructure error.","triggerScenarios":"A wrapper created with tracker.calls(fn, 2) invoked 0, 1, or 3 times by the time verify() runs; async work not awaited before verify(); the code under test calling the original fn instead of the wrapper returned by calls().","commonSituations":"Event handlers not firing (wrong event name, listener attached after emit); missing await on promises before verification; stale expected counts after refactors.","solutions":["Read err.details (or call tracker.report()) to see which function mismatched, with expected vs actual counts and the registration stack.","Make the code under test call the wrapper tracker.calls() returned — reassign fn = tracker.calls(fn) so the real path is intercepted.","Await all async operations before verify(), and pass the correct expected count for legitimately-variable call patterns.","Use tracker.report() when you want failures as data without throwing."],"exampleFix":"// before\nconst save = tracker.calls(repo.save, 1); // wrapper never installed\nawait api.createUser(input);              // repo.save called on original path\ntracker.verify();                          // AssertionError\n\n// after\nrepo.save = tracker.calls(repo.save, 1);  // intercept the real path\nawait api.createUser(input);\ntracker.verify();                          // passes","handlingStrategy":"validation","validationCode":"const failures = tracker.report();\nif (failures.length > 0) {\n  for (const f of failures) console.error(f.message, 'actual:', f.actual, 'expected:', f.expected);\n} else {\n  tracker.verify();\n}","typeGuard":null,"tryCatchPattern":"try {\n  tracker.verify();\n} catch (err) {\n  if (err.code === 'ERR_ASSERTION' && Array.isArray(err.details)) {\n    for (const d of err.details) console.error(d.message);\n  } else throw err;\n}","preventionTips":["Intercept the real code path: fn = tracker.calls(fn) or mock.method(obj, 'name').","Await every async operation before verify().","Call report() first when diagnosing flaky suites — it never throws.","CallTracker is deprecated; migrate to node:test mock.fn + mock assertions for long-term support."],"tags":["testing","assertion","calltracker","node-compat"],"backgroundTag":"assertion-call-count-mismatch","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}