{"id":13725071,"url":"https://github.com/timkindberg/jest-when","last_synced_at":"2025-04-29T14:38:26.285Z","repository":{"id":28280781,"uuid":"117790528","full_name":"timkindberg/jest-when","owner":"timkindberg","description":"Jest support for mock argument-matched return values.","archived":false,"fork":false,"pushed_at":"2024-12-03T14:45:14.000Z","size":807,"stargazers_count":738,"open_issues_count":12,"forks_count":38,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-25T19:56:27.372Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timkindberg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-17T05:47:35.000Z","updated_at":"2025-03-14T19:18:14.000Z","dependencies_parsed_at":"2024-06-18T12:19:33.741Z","dependency_job_id":"ee1bf498-5610-481a-82b7-796148bc558d","html_url":"https://github.com/timkindberg/jest-when","commit_stats":{"total_commits":125,"total_committers":27,"mean_commits":4.62962962962963,"dds":0.704,"last_synced_commit":"4476ba5741f69ec21c7cd5b7d767a52ca41e1258"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timkindberg%2Fjest-when","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timkindberg%2Fjest-when/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timkindberg%2Fjest-when/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timkindberg%2Fjest-when/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timkindberg","download_url":"https://codeload.github.com/timkindberg/jest-when/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251520269,"owners_count":21602462,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T01:02:11.737Z","updated_at":"2025-04-29T14:38:26.253Z","avatar_url":"https://github.com/timkindberg.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# jest-when\n\n[![build status](https://travis-ci.org/timkindberg/jest-when.svg?branch=master)](https://travis-ci.org/timkindberg/jest-when)\n[![codecov](https://codecov.io/gh/timkindberg/jest-when/branch/master/graph/badge.svg)](https://codecov.io/gh/timkindberg/jest-when)\n[![GitHub license](https://img.shields.io/github/license/timkindberg/jest-when.svg)](https://github.com/timkindberg/jest-when/blob/master/LICENSE)\n[![npm](https://img.shields.io/npm/v/jest-when.svg)](https://www.npmjs.com/package/jest-when)\n[![ThoughtWorks Tech Radar 2020 | Adopt](https://img.shields.io/badge/Tech%20Radar-Adopt-b3005d)](https://www.thoughtworks.com/radar/languages-and-frameworks?blipid=201911030)\n\nSpecify dynamic return values for specifically matched mocked function arguments. Flexible matchers. Feels like canonical jest syntax.\n\nThoughtWorks says:\n\u003e jest-when is a lightweight JavaScript library that complements Jest by matching mock function call arguments. Jest is a great tool for testing the stack; jest-when allows you to expect specific arguments for mock functions which enables you to write more robust unit tests of modules with many dependencies. It's easy to use and provides great support for multiple matchers, which is why our teams have made jest-when their default choice for mocking in this space.\n\n### Introduction\n`jest-when` allows you to use a set of the original\n[Jest mock functions](https://facebook.github.io/jest/docs/en/mock-function-api) in order to train\nyour mocks only based on parameters your mocked function is called with.\n\n#### An Example\n\nSo in jest if you want to mock a return value you would do:\n\n```javascript\nconst fn = jest.fn()\nfn.mockReturnValue('yay!')\n```\n\nBut that will return \"yay!\" regardless of what arguments are send to the `fn`. If you want to change the return value\nbased on the arguments, you have to use `mockImplementation` and it can be a bit cumbersome.\n\n`jest-when` makes this easy and fun!\n\n```javascript\nwhen(fn).calledWith(1).mockReturnValue('yay!')\n```\n\nNow, the mock function `fn` will behave as follows\u0026mdash;assuming no other trainings took place:\n* return `yay!` if called with `1` _as the only parameter_\n* return `undefined` if called with _any parameters other_ than `1`\n\nSo the steps are:\n```javascript\nconst fn = jest.fn()                    // 1) Start with any normal jest mock function\nwhen(fn)                                // 2) Wrap it with when()\n  .calledWith(/* any matchers here */)  // 3) Add your matchers with calledWith()\n  .mockReturnValue(/* some value */)    // 4) Then use any of the normal set of jest mock functions\n```\n\nThe supported set of mock functions is:\n* `mockReturnValue`\n* `mockReturnValueOnce`\n* `mockResolvedValue`\n* `mockResolvedValueOnce`\n* `mockRejectedValue`\n* `mockRejectedValueOnce`\n* `mockImplementation`\n* `mockImplementationOnce`\n\nFor extended usage see the examples below.\n\n### Features\n\n- Match literals: `1`, `true`, `\"string\"`, `/regex/`, `null`, etc\n- Match objects or arrays: `{ foo: true }`, `[1, 2, 3]`\n- Match [asymmetric matchers](https://jestjs.io/docs/en/expect#expectanything): expect.any(), expect.objectContaining(), expect.stringMatching(), etc\n- Setup multiple matched calls with differing returns\n- Chaining of mock trainings\n- Replacement of mock trainings\n- One-time trainings, removed after they are matched\n- Promises, resolved or rejected\n- Can also wrap jest.spyOn functions with when()\n- Supports function matchers\n- Setup a default behavior\n- Supports resetting mocks between tests\n- Supports verifying all whenMocks were called\n\n### Usage Examples\n\n#### Installation\n```bash\nnpm i --save-dev jest-when\n```\n\n#### Basic usage:\n```javascript\nimport { when } from 'jest-when'\n\nconst fn = jest.fn()\nwhen(fn).calledWith(1).mockReturnValue('yay!')\n\nexpect(fn(1)).toEqual('yay!')\n```\n\n#### Supports chaining of mock trainings:\n```javascript\nwhen(fn)\n  .calledWith(1).mockReturnValue('yay!')\n  .calledWith(2).mockReturnValue('nay!')\n\nexpect(fn(1)).toEqual('yay!')\nexpect(fn(2)).toEqual('nay!')\n```\nThanks to [@fkloes](https://github.com/fkloes).\n\n```javascript\nwhen(fn)\n  .calledWith(1)\n  .mockReturnValueOnce('yay!')\n  .mockReturnValue('nay!')\n\nexpect(fn(1)).toEqual('yay!')\nexpect(fn(1)).toEqual('nay!')\n```\nThanks to [@danielhusar](https://github.com/danielhusar).\n\n#### Supports replacement of mock trainings:\n```javascript\nwhen(fn).calledWith(1).mockReturnValue('yay!')\nexpect(fn(1)).toEqual('yay!')\n\nwhen(fn).calledWith(1).mockReturnValue('nay!')\nexpect(fn(1)).toEqual('nay!')\n```\nThis replacement of the training only happens for mock functions _not_ ending in `*Once`.\nTrainings like `mockReturnValueOnce` are removed after a matching function call anyway.\n\nThanks to [@fkloes](https://github.com/fkloes).\n\n#### Supports training for single calls\n```javascript\nwhen(fn).calledWith(1, true, 'foo').mockReturnValueOnce('yay!')\nwhen(fn).calledWith(1, true, 'foo').mockReturnValueOnce('nay!')\n\nexpect(fn(1, true, 'foo')).toEqual('yay!')\nexpect(fn(1, true, 'foo')).toEqual('nay!')\nexpect(fn(1, true, 'foo')).toBeUndefined()\n```\n\n#### Supports Promises, both resolved and rejected\n```javascript\nwhen(fn).calledWith(1).mockResolvedValue('yay!')\nwhen(fn).calledWith(2).mockResolvedValueOnce('nay!')\n\nawait expect(fn(1)).resolves.toEqual('yay!')\nawait expect(fn(1)).resolves.toEqual('yay!')\n\nawait expect(fn(2)).resolves.toEqual('nay!')\nexpect(await fn(2)).toBeUndefined()\n\n\nwhen(fn).calledWith(3).mockRejectedValue(new Error('oh no!'))\nwhen(fn).calledWith(4).mockRejectedValueOnce(new Error('oh no, an error again!'))\n\nawait expect(fn(3)).rejects.toThrow('oh no!')\nawait expect(fn(3)).rejects.toThrow('oh no!')\n\nawait expect(fn(4)).rejects.toThrow('oh no, an error again!')\nexpect(await fn(4)).toBeUndefined()\n```\n\n#### Supports jest.spyOn:\n```javascript\nconst theSpiedMethod = jest.spyOn(theInstance, 'theMethod');\nwhen(theSpiedMethod)\n  .calledWith(1)\n  .mockReturnValue('mock');\nconst returnValue = theInstance.theMethod(1);\nexpect(returnValue).toBe('mock');\n```\n\n#### Supports jest [asymmetric matchers](https://jestjs.io/docs/en/expect#expectanything):\n\nUse all the same asymmetric matchers available to the `toEqual()` assertion\n\n```javascript\nwhen(fn).calledWith(\n  expect.anything(),\n  expect.any(Number),\n  expect.arrayContaining(false)\n).mockReturnValue('yay!')\n\nconst result = fn('whatever', 100, [true, false])\nexpect(result).toEqual('yay!')\n```\n\n#### Supports function matchers:\n\nJust wrap any regular function (cannot be a jest mock or spy!) with `when`.\n\nThe function will receive the arg and will be considered a match if the function returns true.\n\nIt works with both calledWith and expectCalledWith.\n\n```javascript\nconst allValuesTrue = when((arg) =\u003e Object.values(arg).every(Boolean))\nconst numberDivisibleBy3 = when((arg) =\u003e arg % 3 === 0)\n\nwhen(fn)\n.calledWith(allValuesTrue, numberDivisibleBy3)\n.mockReturnValue('yay!')\n\nexpect(fn({ foo: true, bar: true }, 9)).toEqual('yay!')\nexpect(fn({ foo: true, bar: false }, 9)).toEqual(undefined)\nexpect(fn({ foo: true, bar: false }, 13)).toEqual(undefined)\n```\n\n#### Supports compound declarations:\n```javascript\nwhen(fn).calledWith(1).mockReturnValue('no')\nwhen(fn).calledWith(2).mockReturnValue('way?')\nwhen(fn).calledWith(3).mockReturnValue('yes')\nwhen(fn).calledWith(4).mockReturnValue('way!')\n\nexpect(fn(1)).toEqual('no')\nexpect(fn(2)).toEqual('way?')\nexpect(fn(3)).toEqual('yes')\nexpect(fn(4)).toEqual('way!')\nexpect(fn(5)).toEqual(undefined)\n```\n\n#### Supports matching or asserting against all of the arguments together using `when.allArgs`:\n\nPass a single special matcher, `when.allArgs`, if you'd like to handle all of the arguments \nwith one function matcher. The function will receive all of the arguments as an array and you \nare responsible for returning true if they are a match, or false if not. The function also is\nprovided with the powerful `equals` utility from Jasmine.\n\n\nThis allows some convenient patterns:\n- Less verbose for variable args where all need to be of a certain type or match (e.g. all numbers)\n- Can be useful for partial matching, because you can assert just the first arg for example and ignore the rest\n\nE.g. All args should be numbers:\n```javascript\nconst areNumbers = (args, equals) =\u003e args.every(arg =\u003e equals(arg, expect.any(Number)))\nwhen(fn).calledWith(when.allArgs(areNumbers)).mockReturnValue('yay!')\n\nexpect(fn(3, 6, 9)).toEqual('yay!')\nexpect(fn(3, 666)).toEqual('yay!')\nexpect(fn(-100, 2, 3.234234, 234, 90e3)).toEqual('yay!')\nexpect(fn(123, 'not a number')).toBeUndefined()\n```\n\nE.g. Single arg match:\n```javascript\nconst argAtIndex = (index, matcher) =\u003e when.allArgs((args, equals) =\u003e equals(args[index], matcher))\n\nwhen(fn).calledWith(argAtIndex(0, expect.any(Number))).mockReturnValue('yay!')\n\nexpect(fn(3, 6, 9)).toEqual('yay!')\nexpect(fn(3, 666)).toEqual('yay!')\nexpect(fn(-100, 2, 3.234234, 234, 90e3)).toEqual('yay!')\nexpect(fn(123, 'not a number')).toBeUndefined()\n```\n\nE.g. Partial match, only first defined matching args matter:\n```javascript\nconst fn = jest.fn()\nconst partialArgs = (...argsToMatch) =\u003e when.allArgs((args, equals) =\u003e equals(args, expect.arrayContaining(argsToMatch)))\n\nwhen(fn)\n  .calledWith(partialArgs(1, 2, 3))\n  .mockReturnValue('x')\n\nexpect(fn(1, 2, 3)).toEqual('x')\nexpect(fn(1, 2, 3, 4, 5, 6)).toEqual('x')\nexpect(fn(1, 2)).toBeUndefined()\nexpect(fn(1, 2, 4)).toBeUndefined()\n```\n\n#### Assert the args:\n\nUse `expectCalledWith` instead to run an assertion that the `fn` was called with the provided\nargs. Your test will fail if the jest mock function is ever called without those exact\n`expectCalledWith` params.\n\nDisclaimer: This won't really work very well with compound declarations, because one of them will\nalways fail, and throw an assertion error.\n```javascript\nwhen(fn).expectCalledWith(1).mockReturnValue('x')\n\nfn(2); // Will throw a helpful jest assertion error with args diff\n```\n\n#### Supports default behavior\n\nUse any of `defaultReturnValue`, `defaultResolvedValue`, `defaultRejectedValue`, `defaultImplementation`\nto set up a default behavior, which will serve as fallback if no matcher fits.\n\n```javascript\nwhen(fn)\n  .calledWith('foo').mockReturnValue('special')\n  .defaultReturnValue('default') // This line can be placed anywhere, doesn't have to be at the end\n\nexpect(fn('foo')).toEqual('special')\nexpect(fn('bar')).toEqual('default')\n```\n\nOr if you use any of `mockReturnValue`, `mockResolvedValue`, `mockRejectedValue`, `mockImplementation` directly on the object\nbefore using `calledWith` it will also behave as a default fallback.\n\n```javascript\n// Same as above example\nwhen(fn)\n  .mockReturnValue('default')\n  .calledWith('foo').mockReturnValue('special')\n\nexpect(fn('foo')).toEqual('special')\nexpect(fn('bar')).toEqual('default')\n```\n\nOne idea is to set up a default implementation that throws an error if an improper call is made to the mock.\n\n```javascript\nwhen(fn)\n  .calledWith(correctArgs)\n  .mockReturnValue(expectedValue)\n  .defaultImplementation(unsupportedCallError)\n\n// A default implementation that fails your test\nfunction unsupportedCallError(...args) {\n  throw new Error(`Wrong args: ${JSON.stringify(args, null, 2)}`);\n}\n```\n\n#### Supports custom mockImplementation\n\nYou could use this to call callbacks passed to your mock fn or other custom functionality.\n\n```javascript\nconst cb = jest.fn()\n\nwhen(fn).calledWith(cb).mockImplementation(callbackArg =\u003e callbackArg())\n\nfn(cb)\n\nexpect(cb).toBeCalled()\n```\n\nThanks to [@idan-at](https://github.com/idan-at).\n\n#### Supports reseting mocks between tests\n\nYou could use this to prevent mocks from carrying state between tests or assertions.\n\n```javascript\nconst { when, resetAllWhenMocks } = require('jest-when')\nconst fn = jest.fn()\n\n// Test 1\nwhen(fn).expectCalledWith(1).mockReturnValueOnce('x')\nexpect(fn(1)).toEqual('x')\n\nresetAllWhenMocks()\n\n// Test 2\nwhen(fn).expectCalledWith(1).mockReturnValueOnce('z')\nexpect(fn(1)).toEqual('z')\n```\n\nThanks to [@whoaa512](https://github.com/whoaa512).\n\n#### Supports resetting individual mocks entirely or by matchers\n\nYou can reset a single mocked function by calling `mockReset` on the mock function.\n\n```javascript\nconst fn = jest.fn()\n\nwhen(fn).calledWith(1).mockReturnValue('yay!')\nwhen(fn).calledWith(2).mockReturnValue('boo!')\nfn.mockReset()\n\nexpect(fn(1)).toBeUndefined() // no mocks\nexpect(fn(2)).toBeUndefined() // no mocks\n```\n\nYou can reset a single set of matchers by calling `mockReset` after `calledWith`. The matchers\npassed to calledWith will be used to remove any existing `calledWith` trainings with the same mathers.\n\n```javascript\nconst fn = jest.fn()\n\nwhen(fn).calledWith(1, 2, 3).mockReturnValue('yay!')\nwhen(fn).calledWith(2).mockReturnValue('boo!')\n\n// Reset only the 1, 2, 3 mock call\nwhen(fn).calledWith(1, 2, 3).mockReset()\n\nexpect(fn(1, 2, 3)).toBeUndefined() // no mock for 1, 2, 3\nexpect(fn(2)).toEqual('boo!') // success!\n```\n\n#### Supports verifying that all mocked functions were called\n\nCall `verifyAllWhenMocksCalled` after your test to assert that all mocks were used.\n\n```javascript\nconst { when, verifyAllWhenMocksCalled } = require('jest-when')\nconst fn = jest.fn()\n\nwhen(fn).expectCalledWith(1).mockReturnValueOnce('x')\n\nexpect(fn(1)).toEqual('x')\n\nverifyAllWhenMocksCalled() // passes\n```\n\n```javascript\nconst { when, verifyAllWhenMocksCalled } = require('jest-when')\nconst fn = jest.fn()\n\nwhen(fn).expectCalledWith(1).mockReturnValueOnce('x')\n\nverifyAllWhenMocksCalled() // fails\n```\n\nThanks to [@roaclark](https://github.com/roaclark).\n\n\n### Contributors (in order of contribution)\n* [@timkindberg](https://github.com/timkindberg/) (original author)\n* [@jonasholtkamp](https://github.com/jonasholtkamp) (forked @ https://github.com/jonasholtkamp/jest-when-xt)\n\u003e Many thanks to @jonasholtkamp. He forked this repo when I was inactive and stewarded several key features and bug fixes!\n* [@fkloes](https://github.com/fkloes)\n* [@danielhusar](https://github.com/danielhusar)\n* [@idan-at](https://github.com/idan-at)\n* [@whoaa512](https://github.com/whoaa512).\n* [@roaclark](https://github.com/roaclark)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimkindberg%2Fjest-when","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimkindberg%2Fjest-when","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimkindberg%2Fjest-when/lists"}