{"id":"5f0724e9a24b52a4","repo":"vitest-dev/vitest","slug":"msg","errorCode":null,"errorMessage":"${msg}","messagePattern":"\\$\\{msg\\}","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"packages/expect/src/jest-expect.ts","lineNumber":588,"sourceCode":"  def(['toHaveBeenCalled', 'toBeCalled'], function () {\n    const spy = getSpy(this)\n    const spyName = spy.getMockName()\n    const callCount = spy.mock.calls.length\n    const called = callCount > 0\n    const isNot = utils.flag(this, 'negate') as boolean\n    let msg = utils.getMessage(this, [\n      called,\n      `expected \"${spyName}\" to be called at least once`,\n      `expected \"${spyName}\" to not be called at all, but actually been called ${callCount} times`,\n      true,\n      called,\n    ])\n    if (called && isNot) {\n      msg = formatCalls(spy, msg)\n    }\n\n    if ((called && isNot) || (!called && !isNot)) {\n      throw new AssertionError(msg)\n    }\n  })\n\n  // manually compare array elements since `jestEquals` cannot\n  // apply asymmetric matcher to `undefined` array element.\n  function equalsArgumentArray(a: unknown[], b: unknown[]) {\n    return a.length === b.length && a.every((aItem, i) =>\n      jestEquals(aItem, b[i], [...customTesters, iterableEquality]),\n    )\n  }\n\n  def(['toHaveBeenCalledWith', 'toBeCalledWith'], function (...args) {\n    const spy = getSpy(this)\n    const spyName = spy.getMockName()\n    const pass = spy.mock.calls.some(callArg => equalsArgumentArray(callArg, args))\n    const isNot = utils.flag(this, 'negate') as boolean\n\n    const msg = utils.getMessage(this, [","sourceCodeStart":570,"sourceCodeEnd":606,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/expect/src/jest-expect.ts#L570-L606","documentation":"AssertionError thrown by toHaveBeenCalled/toBeCalled when the spy was either not called at all (positive form) or was called when .not was used. The formatted message (msg) includes the spy name and, in the .not case, the call arguments via formatCalls.","triggerScenarios":"expect(spy).toHaveBeenCalled() where spy.mock.calls.length === 0; or expect(spy).not.toHaveBeenCalled() where the spy was called one or more times. The condition (called && isNot) || (!called && !isNot) controls the throw.","commonSituations":"Asserting a callback was invoked but the event/path was never exercised (e.g. a click handler test where the click was not simulated, or a mocked module that was never imported by the code under test).","solutions":["Verify the code path that should invoke the spy is actually executed (e.g. the event is fired, the function is called).","Confirm the spy is attached to the same reference the code uses (spyOn creates a new reference; re-imports may bypass it).","If using .not, ensure no incidental call site triggers the spy elsewhere."],"exampleFix":"// before\nconst onClick = vi.fn();\nrender(<Button />);\nexpect(onClick).toHaveBeenCalled();\n// after\nconst onClick = vi.fn();\nrender(<Button onClick={onClick} />);\nfireEvent.click(screen.getByRole('button'));\nexpect(onClick).toHaveBeenCalled();","handlingStrategy":"validation","validationCode":"if (spy.mock.calls.length === 0) throw new Error('spy was never called — verify the code path that invokes it');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Trigger the code path explicitly (event, call, import) before asserting.","Confirm the spy is on the same reference the code under test resolves to."],"tags":["assertion","mock","spy","tohavebeencalled"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}