{"id":"513e08af97aed934","repo":"vitest-dev/vitest","slug":"utils-inspect-chain-is-not-a-vi-when-instanc","errorCode":null,"errorMessage":"${utils.inspect(chain)} is not a `vi.when` instance","messagePattern":"(.+?) is not a `vi\\.when` instance","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/vitest/src/integrations/mock/chai.ts","lineNumber":13,"sourceCode":"import type { ChaiPlugin } from '@vitest/expect'\nimport { wrapAssertion } from '@vitest/expect'\nimport { isWhenChain } from './when'\n\nexport const MockPlugin: ChaiPlugin = (chai, utils) => {\n  utils.addMethod(\n    chai.Assertion.prototype,\n    'toHaveBeenExhausted',\n    wrapAssertion(utils, 'toHaveBeenExhausted', function (this) {\n      const chain = utils.flag(this, 'object')\n\n      if (!isWhenChain(chain)) {\n        throw new TypeError(\n          `${utils.inspect(chain)} is not a \\`vi.when\\` instance`,\n        )\n      }\n\n      const diagnostics = chain._getDiagnostics()\n\n      this.assert(\n        diagnostics.isExhausted,\n        `expected all behaviors to have been exhausted, but some remain:\\n\\n  ${diagnostics.pendingBehaviors.replaceAll(/\\n(?!\\n)/g, '\\n  ')}`,\n        'expected at least one behavior to remain un-exhausted, but all were',\n      )\n    }),\n  )\n}\n","sourceCodeStart":1,"sourceCodeEnd":28,"githubUrl":"https://github.com/vitest-dev/vitest/blob/d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09/packages/vitest/src/integrations/mock/chai.ts#L1-L28","documentation":"The `.toHaveBeenExhausted` assertion (added by the mock chai plugin) is specifically for verifying that every behavior registered on a `vi.when(...)` chain has been consumed. It inspects the `$$vitest:when` symbol via `isWhenChain`; if the asserted object is not a `vi.when` instance it throws a `TypeError`. This prevents calling the matcher on a plain mock or arbitrary value where exhaustion is undefined.","triggerScenarios":"Calling `expect(someValue).toHaveBeenExhausted()` where `someValue` is a `vi.fn()`/`vi.spyOn()` mock, a raw function, an object, or any value not returned by `vi.when(spy)`.","commonSituations":"Confusing `vi.fn()` with `vi.when()`, or asserting exhaustion on the spy itself rather than the `vi.when` chain handle.","solutions":["Call `.toHaveBeenExhausted` on the value returned by `vi.when(spy)`, not on the spy itself.","If you wanted to assert call counts on a plain mock, use `.toHaveBeenCalled()` / `.toHaveBeenCalledTimes(n)` instead.","Ensure the `vi.when(...)` chain was actually assigned to a variable before asserting on it."],"exampleFix":"// before\nconst spy = vi.fn()\nvi.when(spy).calledWith(1).thenReturn(0)\nexpect(spy).toHaveBeenExhausted()\n// after\nconst w = vi.when(spy).calledWith(1).thenReturn(0)\nexpect(w).toHaveBeenExhausted()","handlingStrategy":"type-guard","validationCode":"import { isWhenChain } from 'vitest'\n// assert on the vi.when handle, not the spy\nconst w = vi.when(spy).calledWith(1).thenReturn(0)\nif (!isWhenChain(w)) throw new Error('expected a vi.when instance')\nexpect(w).toHaveBeenExhausted()","typeGuard":"import { isWhenChain } from 'vitest'\n// isWhenChain(input): input is When — exported from vitest","tryCatchPattern":null,"preventionTips":["Assign the `vi.when(...)` result to a variable and assert exhaustion on that variable.","For plain mocks use `.toHaveBeenCalled*` instead of `.toHaveBeenExhausted`."],"tags":["mock","vi-when","matcher","type-error"],"analyzedSha":"d568f8ce3739b532d5bf2c1ee1e45e8a8a473d09","analyzedAt":"2026-08-03T20:23:56.861Z","schemaVersion":2}