{"id":13847216,"url":"https://github.com/bhovhannes/jestor","last_synced_at":"2025-04-06T04:34:04.972Z","repository":{"id":36995406,"uuid":"244720959","full_name":"bhovhannes/jestor","owner":"bhovhannes","description":"Defines how Jest mocks should behave","archived":false,"fork":false,"pushed_at":"2024-04-14T08:44:50.000Z","size":1996,"stargazers_count":2,"open_issues_count":1,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-04-14T09:53:21.775Z","etag":null,"topics":["implementation","jest","mock","spy","unit-testing"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/bhovhannes.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}},"created_at":"2020-03-03T19:16:19.000Z","updated_at":"2024-04-15T15:10:34.473Z","dependencies_parsed_at":"2023-02-12T08:25:11.814Z","dependency_job_id":"5a708db9-3e4c-4c7b-8bc4-1507f11f4384","html_url":"https://github.com/bhovhannes/jestor","commit_stats":{"total_commits":494,"total_committers":7,"mean_commits":70.57142857142857,"dds":"0.31376518218623484","last_synced_commit":"0002f57b2f3736abd8d21e8ab40120fdb69daba6"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhovhannes%2Fjestor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhovhannes%2Fjestor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhovhannes%2Fjestor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhovhannes%2Fjestor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bhovhannes","download_url":"https://codeload.github.com/bhovhannes/jestor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247435043,"owners_count":20938530,"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":["implementation","jest","mock","spy","unit-testing"],"created_at":"2024-08-04T18:01:13.536Z","updated_at":"2025-04-06T04:34:04.153Z","avatar_url":"https://github.com/bhovhannes.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# jestor\n\n[![NPM version][npm-version-image]][npm-url] [![NPM downloads][npm-downloads-image]][npm-url] [![MIT License][license-image]][license-url] [![Coverage][codecov-image]][codecov-url]\n\nUtility for creating mock implementations for Jest mocks.\n\n## Usage\n\nFirst add `jestor` as a devDependency.\n\n```bash\nnpm install jestor --save-dev\n```\n\nor if you prefer Yarn:\n\n```bash\nyarn add jestor --dev\n```\n\nAfter that you can import `jestor` in your tests and use it in any test file:\n\n```javascript\nimport { jestor } from 'jestor'\n\nit('should return 4 whan called with 44', function () {\n  const mock = jest.fn()\n\n  // define mock implementation using jestor api\n  jestor(mock).whenCalledWith(44).return(4)\n\n  expect(mock(44)).toBe(4)\n})\n```\n\nProceed to [API](#api) section to see what else `jestor` can do for you.\n\n### API\n\n`jestor` function accepts Jest mock as a single argument and returns an object with the following methods: `whenCalledWith` and `followRules` for defining single and multiple rules correspondingly.\n\n#### Describing single rule\n\nThe best case for `whenCalledWith` is when you want to define only one rule:\n\n```javascript\nimport { jestor } from 'jestor'\n\nit('should return 4 whan called with 44', function () {\n  const mock = jest.fn()\n\n  // whenCalledWith allows to define only a single rule\n  jestor(mock).whenCalledWith(44).return(4)\n\n  expect(mock(44)).toBe(4)\n})\n```\n\n#### Describing multiple rules\n\nIf you want to define multiple rules, `followRules` should be used.  \nIt accepts a function, which define what mock should do when the given condition is met:\n\n```javascript\nit('should allow to define multiple rules', function () {\n  const spy = jest.fn()\n  jestor(spy).followRules((rules) =\u003e {\n    rules.whenCalledWith(1).return(false)\n    rules.whenCalledWith(2).return(true)\n    rules.whenCalledWith('foo').resolveWith('foo')\n    rules.whenCalledWith('bar').rejectWith('bar')\n  })\n\n  expect(spy(1)).toBe(false)\n  expect(spy(2)).toBe(true)\n\n  const foo = await spy('foo')\n  expect(foo).toBe('foo')\n\n  await spy('bar').catch((e) =\u003e {\n    expect(e).toBe('bar')\n  })\n})\n```\n\n#### Describing conditions\n\nAs you've probably noticed, `whenCalledWith` is used directly in case of single rule, and inside callback function in case of multiple rules.  \nIn both cases `whenCalledWith` is used for defining conditions for the arguments mock receives.\n\nYou can pass multiple arguments to `whenCalledWith`:\n\n```javascript\nimport { jestor } from 'jestor'\n\nit('should return 6 whan called with 2 and 3', function () {\n  const mock = jest.fn()\n\n  // whenCalledWith accepts multiple arguments\n  jestor(mock).whenCalledWith(2, 3).return(6)\n\n  expect(mock(2, 3)).toBe(6)\n})\n```\n\nYou can pass any asymmetrical [Expect](https://jestjs.io/docs/en/expect) matcher to `whenCalledWith`.  \nThat includes matchers like [`anything`](https://jestjs.io/docs/en/expect#expectanything), [`any`](https://jestjs.io/docs/en/expect#expectanyconstructor), [`arrayContaining`](https://jestjs.io/docs/en/expect#expectarraycontainingarray), etc.\n\nFor example:\n\n```javascript\nimport { jestor } from 'jestor'\n\nit('should return 6 whan called with string and 3', function () {\n  const mock = jest.fn()\n\n  // whenCalledWith also accepts expect matchers\n  jestor(mock).whenCalledWith(expect.any(String), 3).return(6)\n\n  expect(mock('foo', 3)).toBe(6)\n  expect(mock('baz', 3)).toBe(6)\n})\n```\n\n#### Describing mock behavior\n\nThe `whenCalledWith` function returns an object which can be used to specify mock behavior - i.e. what should happen when mock is called with the given arguments.  \nFor example, in `jestor(mock).whenCalledWith(2, 3).return(6)` sentence the part `.return(6)` describes mock behavior when it is called with arguments `2` and `3`.\n\nYou can use the following behaviors:\n\n##### `.return(val)`\n\nDescribes that the value `val` should be returned when mock is called:\n\n```javascript\nimport { jestor } from 'jestor'\n\nit('should return 6 whan called with string and 3', function () {\n  const mock = jest.fn()\n\n  // tell jestor to return 6 when mock is called with 3\n  jestor(mock).whenCalledWith(3).return(6)\n\n  expect(mock(3)).toBe(6)\n  expect(mock(2)).not.toBe(6)\n})\n```\n\n##### `.resolveWith(val)`\n\nDescribes that the the promise resolved with `val` should be returned when mock is called:\n\n```javascript\nimport { jestor } from 'jestor'\n\nit('should return resolved promise when resolveWith is used', function () {\n  const mock = jest.fn()\n\n  // tell jestor to return promise resolved with 6 when mock is called with 3\n  jestor(mock).whenCalledWith(3).resolveWith(6)\n\n  const promise = mock(3)\n\n  // assert that we got a promise\n  expect(promise.then).toBeDefined()\n\n  // when called with value other than 3, we'll not get a promise,\n  // as there is no jestor rule defined\n  expect(mock(2)).toBe(undefined)\n\n  // assert if we really got a promise resolved with 6\n  const result = await promise\n  expect(result).toBe(6)\n})\n```\n\n##### `.rejectWith(val)`\n\nDescribes that the the promise rejected with `val` should be returned when mock is called:\n\n```javascript\nimport { jestor } from 'jestor'\n\nit('should return rejected promise when rejectWith is used', function () {\n  const mock = jest.fn()\n\n  // tell jestor to return rejected promise\n  jestor(mock).whenCalledWith(2).rejectWith('failure')\n\n  // assert if we really got a promise rejected with 'failure'\n  const err = await mock(2).catch((e) =\u003e e)\n  expect(err).toBe('failure')\n})\n```\n\n##### `.throw(val)`\n\nDescribes that value `val` should be thrown when mock is called:\n\n```javascript\nimport { jestor } from 'jestor'\n\nit('should throw an exception when throw is used', function () {\n  const mock = jest.fn()\n\n  // tell jestor to throw\n  jestor(mock).whenCalledWith(2).throw('exception')\n\n  // assert if we really got an exception\n  jestor(mock).whenCalledWith(2).throw('exception')\n  expect(() =\u003e {\n    spy(2)\n  }).toThrow('exception')\n})\n```\n\n## Rationale\n\nLet's imagine you have a mock, returned by `jest.fn()` and want to define its implementation in a way that you specify what to return based on received arguments. Something like this:\n\n```javascript\ndescribe('my function', function() {\n  it('should return a value', function() {\n    const mock = jest.fn()\n    mock.mockImplementation((obj1, obj2) =\u003e {\n      if (obj1 === 'Alice') {\n        return 'human'\n      }\n      if (typeof obj1 === 'number' \u0026\u0026 typeof obj2 === 'number') {\n        return 'numbers'\n      }\n      if (typeof obj1 === 'function') {\n        return 'function'\n      }\n    }))\n  })\n})\n```\n\nWriting such mock implementation is unpleasant experience, you end up writing a bunch of `if` statements and code quickly become messy.\n\nHere is when `jestor` comes to rescue. With `jestor` test written above can be written as:\n\n```javascript\nimport { jestor } from 'jestor'\n\ndescribe('my function', function () {\n  it('should return a value', function () {\n    const mock = jest.fn()\n    jestor(mock).followRules((rules) =\u003e {\n      rules.whenCalledWith('Alice').return('human')\n      rules.whenCalledWith(expect.any(Number), expect.any(Number)).return('numbers')\n      rules.whenCalledWith(expect.any(Function)).return('function')\n    })\n  })\n})\n```\n\n## Why `jestor`\n\nIt should have been named `jester`, as jester is a person who jests.  \nHowever, the names `jester`, `jestr` and even `jster` have been taken. As well as `mocker` and `jocker`.\n\n## License\n\nMIT (http://www.opensource.org/licenses/mit-license.php)\n\n[license-image]: http://img.shields.io/badge/license-MIT-blue.svg?style=flat\n[license-url]: LICENSE\n[npm-url]: https://www.npmjs.org/package/jestor\n[npm-version-image]: https://img.shields.io/npm/v/jestor.svg?style=flat\n[npm-downloads-image]: https://img.shields.io/npm/dm/jestor.svg?style=flat\n[codecov-url]: https://codecov.io/gh/bhovhannes/jestor\n[codecov-image]: https://img.shields.io/codecov/c/github/bhovhannes/jestor.svg\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhovhannes%2Fjestor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbhovhannes%2Fjestor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhovhannes%2Fjestor/lists"}