{"id":13660493,"url":"https://github.com/NiGhTTraX/strong-mock","last_synced_at":"2025-04-24T19:31:08.157Z","repository":{"id":34978727,"uuid":"193740237","full_name":"NiGhTTraX/strong-mock","owner":"NiGhTTraX","description":"Type safe mocking library for TypeScript","archived":false,"fork":false,"pushed_at":"2025-04-21T23:25:46.000Z","size":5442,"stargazers_count":104,"open_issues_count":3,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-22T00:26:38.821Z","etag":null,"topics":["fake","mock","mocking","stub","tdd","testing","typescript"],"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/NiGhTTraX.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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,"zenodo":null},"funding":{"github":"NiGhTTraX"}},"created_at":"2019-06-25T16:00:53.000Z","updated_at":"2025-04-21T23:25:49.000Z","dependencies_parsed_at":"2023-12-22T19:22:49.707Z","dependency_job_id":"a86900af-0d96-4cbc-8558-d524f4f9da0e","html_url":"https://github.com/NiGhTTraX/strong-mock","commit_stats":{"total_commits":812,"total_committers":8,"mean_commits":101.5,"dds":"0.39039408866995073","last_synced_commit":"d31de93b4e370abc7ace62bb182e6aa829ac0d64"},"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NiGhTTraX%2Fstrong-mock","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NiGhTTraX%2Fstrong-mock/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NiGhTTraX%2Fstrong-mock/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NiGhTTraX%2Fstrong-mock/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NiGhTTraX","download_url":"https://codeload.github.com/NiGhTTraX/strong-mock/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250157165,"owners_count":21384272,"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":["fake","mock","mocking","stub","tdd","testing","typescript"],"created_at":"2024-08-02T05:01:22.215Z","updated_at":"2025-04-24T19:31:08.150Z","avatar_url":"https://github.com/NiGhTTraX.png","language":"TypeScript","funding_links":["https://github.com/sponsors/NiGhTTraX"],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003c!--suppress HtmlDeprecatedAttribute --\u003e\n\u003cdiv align=\"center\"\u003e\n\u003ch1\u003e💪 strong-mock\u003c/h1\u003e\n\n\u003cp\u003eType safe mocking library for TypeScript\u003c/p\u003e\n\u003c/div\u003e\n\n```typescript\nimport { mock, when } from 'strong-mock';\n\ninterface Foo {\n  bar: (x: number) =\u003e string;\n}\n\nconst foo = mock\u003cFoo\u003e();\n\nwhen(() =\u003e foo.bar(23)).thenReturn('I am strong!');\n\nconsole.log(foo.bar(23)); // 'I am strong!'\n```\n\n----\n\n![Build Status](https://github.com/NiGhTTraX/strong-mock/workflows/Tests/badge.svg) [![codecov](https://codecov.io/gh/NiGhTTraX/strong-mock/branch/master/graph/badge.svg)](https://codecov.io/gh/NiGhTTraX/strong-mock) ![npm type definitions](https://img.shields.io/npm/types/strong-mock.svg)\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n**Table of Contents**\n\n- [Features](#features)\n  - [Type safety](#type-safety)\n  - [Matchers](#matchers)\n  - [Awesome error messages](#awesome-error-messages)\n  - [Works with Promises and Errors](#works-with-promises-and-errors)\n- [Installation](#installation)\n- [API](#api)\n  - [Mock](#mock)\n    - [Mocking types and interfaces](#mocking-types-and-interfaces)\n    - [Mocking functions](#mocking-functions)\n  - [When](#when)\n    - [Setting expectations](#setting-expectations)\n    - [Setting multiple expectations](#setting-multiple-expectations)\n    - [Matchers](#matchers-1)\n    - [Custom matchers](#custom-matchers)\n  - [Then](#then)\n    - [Setting invocation count expectations](#setting-invocation-count-expectations)\n    - [Returning promises](#returning-promises)\n    - [Throwing errors](#throwing-errors)\n  - [Verify](#verify)\n    - [Verifying expectations](#verifying-expectations)\n  - [Reset](#reset)\n    - [Resetting expectations](#resetting-expectations)\n- [Mock options](#mock-options)\n  - [Unexpected property return value](#unexpected-property-return-value)\n  - [Exact params](#exact-params)\n  - [Concrete matcher](#concrete-matcher)\n- [FAQ](#faq)\n  - [Why do I have to set all expectations first?](#why-do-i-have-to-set-all-expectations-first)\n  - [Why do I have to set a return value even if it's `undefined`?](#why-do-i-have-to-set-a-return-value-even-if-its-undefined)\n  - [Why do I get a `Didn't expect mock to be called` error?](#why-do-i-get-a-didnt-expect-mock-to-be-called-error)\n  - [Can I partially mock a concrete implementation?](#can-i-partially-mock-a-concrete-implementation)\n  - [How do I set expectations on setters?](#how-do-i-set-expectations-on-setters)\n  - [How do I provide a function for the mock to call?](#how-do-i-provide-a-function-for-the-mock-to-call)\n  - [Can I spread or enumerate a mock?](#can-i-spread-or-enumerate-a-mock)\n  - [Why does `typeof mock()` return `function`?](#why-does-typeof-mock-return-function)\n  - [How can I ignore `undefined` keys when setting expectations on objects?](#how-can-i-ignore-undefined-keys-when-setting-expectations-on-objects)\n  - [How can I verify order of calls?](#how-can-i-verify-order-of-calls)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Features\n\n### Type safety\n\nThe mocks will share the same types as your production code, and you can safely refactor in an IDE knowing that all usages will be updated.\n\n![Renaming production code and test code](media/rename-refactor.gif)\n\n### Matchers\n\nYou can use matchers to partially match values, or create complex expectations, while still maintaining type safety.\n\n![Type safe matchers](media/type-safe-matchers.png)\n\n### Awesome error messages\n\nFailed expectations will print a visual diff, and even integrate with the IDE.\n\n```typescript\nimport { mock, when } from 'strong-mock';\n\nconst fn = mock\u003c(pos: { x: number; y: number }) =\u003e boolean\u003e();\n\nwhen(() =\u003e\n  fn(\n    It.containsObject({\n      x: It.isNumber(),\n      y: It.matches\u003cnumber\u003e((y) =\u003e y \u003e 0)\n    })\n  )\n).thenReturn(true);\n\nfn({ x: 1, y: -1 });\n```\n\n![Test output from the IDE showing details about a failed mock expectation](media/error-messages.png)\n\n### Works with Promises and Errors\n\n```typescript\nimport { mock, when } from 'strong-mock';\n\nconst fn = mock\u003c(id: number) =\u003e Promise\u003cstring\u003e\u003e();\n\nwhen(() =\u003e fn(42)).thenResolve('foo');\nwhen(() =\u003e fn(-1)).thenReject('oops');\n\nconsole.log(await fn(42)); // foo\n\ntry {\n  await fn(-1);\n} catch (e) {\n  console.log(e.message); // oops\n}\n```\n\n## Installation\n\n```shell\nnpm i -D strong-mock\n```\n\n```shell\nyarn add -D strong-mock\n```\n\n```shell\npnpm add -D strong-mock\n```\n\n## API\n\n### Mock\n\n#### Mocking types and interfaces\n\nPass in the type or interface to the generic argument of `mock`:\n\n```typescript\ninterface Foo {\n  bar: (x: number) =\u003e string;\n  baz: number;\n}\n\nconst foo = mock\u003cFoo\u003e();\n\nwhen(() =\u003e foo.bar(23)).thenReturn('awesome');\nwhen(() =\u003e foo.baz).thenReturn(100);\n\nconsole.log(foo.bar(23)); // 'awesome'\nconsole.log(foo.baz); // 100\n```\n\n#### Mocking functions\n\nYou can also mock function types:\n\n```typescript\ntype Fn = (x: number) =\u003e number;\n\nconst fn = mock\u003cFn\u003e();\n\nwhen(() =\u003e fn(1)).thenReturn(2);\n\nconsole.log(fn(1)); // 2\n```\n\n### When\n\n#### Setting expectations\n\nExpectations are set by calling the mock inside a `when` callback and setting a return value.\n\n```typescript\nwhen(() =\u003e foo.bar(23)).thenReturn('awesome');\n```\n\n#### Setting multiple expectations\n\nYou can set as many expectations as you want by calling `when` multiple times. If you have multiple expectations with the same arguments they will be consumed in the order they were created.\n\n```typescript\nwhen(() =\u003e foo.bar(23)).thenReturn('awesome');\nwhen(() =\u003e foo.bar(23)).thenReturn('even more awesome');\n\nconsole.log(foo.bar(23)); // awesome\nconsole.log(foo.bar(23)); // even more awesome\n```\n\n#### Matchers\n\nSometimes you're not interested in specifying all the arguments in an expectation. Maybe they've been covered in another test, maybe they're hard to specify e.g. callbacks, or maybe you want to match just a property from an argument.\n\n```typescript\nconst fn = mock\u003c\n  (x: number, data: { values: number[]; labels: string[] }) =\u003e string\n\u003e();\n\nwhen(() =\u003e fn(\n  It.isAny(),\n  It.containsObject({ values: [1, 2, 3] })\n)).thenReturn('matched!');\n\nconsole.log(fn(\n  123, \n  { values: [1, 2, 3], labels: ['a', 'b', 'c'] })\n); // 'matched!'\n```\n\nYou can mix matchers with concrete arguments:\n\n```typescript\nwhen(() =\u003e fn(42, It.isPlainObject())).thenReturn('matched');\n```\n\nAvailable matchers:\n- `deepEquals` - the default, uses deep equality,\n- `is` - uses `Object.is` for comparison,\n- `isAny` - matches anything,\n- `isNumber` - matches any number,\n- `isString` - matches any string, can search for substrings and patterns,\n- `isArray` - matches any array, can search for subsets,\n- `isPlainObject` - matches any plain object,\n- `containsObject` - recursively matches a subset of an object,\n- `willCapture` - matches anything and [stores](#custom-matchers) the received value,\n- `matches` - [build your own matcher](#custom-matchers).\n\nThe following table illustrates the differences between the equality matchers:\n\n| expected           | actual               | `It.is`   | `It.deepEquals` | `It.deepEquals({ strict: false })` |\n|--------------------|----------------------|-----------|-----------------|------------------------------------|\n| `\"foo\"`            | `\"foo\"`              | equal     | equal           | equal                              |\n| `{ foo: \"bar\" }`   | `{ foo: \"bar\" }`     | not equal | equal           | equal                              |\n| `{ }`              | `{ foo: undefined }` | not equal | not equal       | equal                              |\n| `new (class {})()` | `new (class {})()`   | not equal | not equal       | equal                              |\n\nSome matchers, like `containsObject` and `isArray` support nesting matchers:\n\n```typescript\nIt.containsObject({\n  foo: It.isString()\n})\n\nIt.isArray([\n  It.containsObject({\n    foo: It.isString(/foo/)\n  })\n])\n```\n\n#### Custom matchers\n\n`It.willCapture` will match any value and store it, so you can access it outside an expectation. This could be useful to capture a callback and then test it separately.\n\n```ts\ntype Cb = (value: number) =\u003e number;\n\nconst fn = mock\u003c(cb: Cb) =\u003e number\u003e();\n\nconst matcher = It.willCapture\u003cCb\u003e();\nwhen(() =\u003e fn(matcher)).thenReturn(42);\n\nconsole.log(fn(23, (x) =\u003e x + 1)); // 42\nconsole.log(matcher.value?.(3)); // 4\n```\n\nWith `It.matches` you can create arbitrarily complex and type safe matchers:\n\n```typescript\nconst fn = mock\u003c(x: number, y: string) =\u003e string\u003e();\n\nwhen(() =\u003e fn(\n  It.matches(x =\u003e x \u003e 0),\n  It.matches(y =\u003e y.startsWith('foo'))\n)).thenReturn('matched');\n```\n\nThe types are automatically inferred, but you can also specify them explicitly through the generic parameter, which is useful if you want to create reusable matchers:\n\n```typescript\nconst startsWith = (expected: string) =\u003e It.matches\u003cstring\u003e(\n  actual =\u003e actual.startsWith(expected)\n);\n\nwhen(() =\u003e fn(42, startsWith('foo'))).thenReturn('matched');\n\nfn(42, 'foobar') // 'matched'\n```\n\nYou can also customize how the matcher is printed in error messages, and how the diff is printed:\n\n```typescript\nconst closeTo = (expected: number, precision = 0.01) =\u003e It.matches\u003cnumber\u003e(\n  actual =\u003e Math.abs(expected - actual) \u003c= precision,\n  {\n    toString: () =\u003e `closeTo(${expected}, ${precision})`,\n    getDiff: (actual) =\u003e {\n      const diff = Math.abs(expected - actual);\n      const sign = diff \u003c 0 ? '-' : '+';\n      \n      return {\n        actual: `${actual} (${sign}${diff})`,\n        expected: `${expected} ±${precision}`,\n      };\n    }\n  }\n);\n\nwhen(() =\u003e fn(closeTo(1), 'foo')).thenReturn('matched');\n\nfn(2, 'foo');\n```\n\n![Error message for custom matcher](media/custom-matcher-error.png)\n\n### Then\n\n#### Setting invocation count expectations\n\nBy default, each call is expected to be made only once. You can expect a call to be made multiple times by using the invocation count helpers `between`, `atLeast`, `times`, `anyTimes` etc.:\n\n```typescript\nconst fn = mock\u003c(x: number) =\u003e number\u003e();\n\nwhen(() =\u003e fn(1)).thenReturn(1).between(2, 3);\n\nconsole.log(fn(1)); // 1\nconsole.log(fn(1)); // 1\nconsole.log(fn(1)); // 1\nconsole.log(fn(1)); // throws because the expectation is finished\n```\n\nYou'll notice there is no `never()` helper - if you expect a call to not be made simply don't set an expectation on it and the mock will throw if the call happens.\n\n#### Returning promises\n\nIf you're mocking something that returns a promise then you'll be able to use the `thenResolve` promise helper to set the return value.\n\n```typescript\ntype Fn = (x: number) =\u003e Promise\u003cnumber\u003e;\n\nconst fn = mock\u003cFn\u003e();\n\nwhen(() =\u003e fn(1)).thenResolve(42);\n\nconsole.log(await fn(1)); // 42\n```\n\nYou can also use `thenReturn` with a Promise value:\n\n```typescript\nwhen(() =\u003e fn(1)).thenReturn(Promise.resolve(42));\n```\n\n#### Throwing errors\n\nUse `thenThrow` or `thenReject` to throw an `Error` instance. You can customize the error message, or even pass a derived class.\n\n```typescript\ntype Fn = (x: number) =\u003e void;\ntype FnWithPromise = (x: number) =\u003e Promise\u003cvoid\u003e;\n\nclass MyError extends Error {}\n\nconst fn = mock\u003cFn\u003e();\nconst fnWithPromise = mock\u003cFnWithPromise\u003e();\n\n// All of these will throw an Error instance.\nwhen(() =\u003e fn(1)).thenThrow();\nwhen(() =\u003e fn(2)).thenThrow(MyError);\nwhen(() =\u003e fnWithPromise(1)).thenReject('oops');\n```\n\n### Verify\n\n#### Verifying expectations\n\nCalling `verify(myMock)` will make sure that all expectations set on the mock have been met, and that no additional calls have been made.\n\n```typescript\nconst fn = mock\u003c(x: number) =\u003e number\u003e();\n\nwhen(() =\u003e fn(1)).thenReturn(1).between(2, 10);\n\nverify(fn); // throws UnmetExpectations\n```\n\nIt will also throw if any unexpected calls happened that were maybe caught in the code under test.\n\n```typescript\nconst fn = mock\u003c() =\u003e void\u003e();\n\ntry {\n  fn(); // throws because the call is unexpected\n} catch(e) {\n  // your code might transition to an error state here\n}\n\nverify(fn); // throws UnexpectedCalls\n```\n\nIt is recommended that you call `verify()` on your mocks at the end of every test. This will make sure you don't have any unused expectations in your tests and that your code did not silently catch any of the errors that are thrown when an unexpected call happens. You can use `verifyAll()` to check all existing mocks.\n\n```typescript\nafterEach(() =\u003e {\n  verifyAll();\n});\n```\n\n![verify error](media/verify.png)\n\n### Reset\n\n#### Resetting expectations\n\nYou can remove all expectations from a mock by using the `reset()` method:\n\n```typescript\nconst fn = mock\u003c(x: number) =\u003e number\u003e();\n\nwhen(() =\u003e fn(1)).thenReturn(1);\n\nreset(fn);\n\nfn(1); // throws\n```\n\nIf you create common mocks that are shared by multiple tests you should reset them before each test. You can use `resetAll()` to reset all existing mocks.\n\n```typescript\nbeforeEach(() =\u003e {\n  resetAll();\n});\n```\n\n## Mock options\n\nThe following options can be set per mock, or globally with `setDefaults`.\n\n```typescript\nimport { mock, when, setDefaults } from 'strong-mock';\n\nsetDefaults({\n  exactParams: true\n});\n\n// Uses the new default.\nconst superStrictMock = mock\u003c() =\u003e void\u003e();\n// Overrides the default.\nconst strictMock = mock\u003c() =\u003e void\u003e({ exactParams: false });\n```\n\n### Unexpected property return value\n\nYou can control what happens whenever an unexpected property is accessed, or an unexpected call is made.\n\n```typescript\nimport { mock, when, UnexpectedProperty } from 'strong-mock';\n\ntype Foo = {\n  bar: (value: number) =\u003e number;\n}\n\n// This is the default.\nconst callsThrow = mock\u003cFoo\u003e({\n  unexpectedProperty: UnexpectedProperty.CALL_THROW\n});\n\n// Accessing properties with no expectations is fine.\ncallsThrow.bar;\n// Throws \"Didn't expect bar(42) to be called\".\ncallsThrow.bar(42);\n\nconst propertiesThrow = mock\u003cFoo\u003e({\n  unexpectedProperty: UnexpectedProperty.THROW\n});\n\n// Throws \"Didn't expect property bar to be accessed\".\npropertiesThrow.bar;\n// Throws \"Didn't expect property bar to be accessed\".\npropertiesThrow.bar(42);\n```\n\n### Exact params\n\nBy default, function/method expectations will allow more arguments to be received than expected. Since the expectations are type safe, the TypeScript compiler will never allow expecting less arguments than required. Unspecified optional arguments will be considered ignored, as if they've been replaced with [matchers](#matchers-1).\n\n```typescript\nimport { mock } from 'strong-mock';\n\nconst fn = mock\u003c(value?: number) =\u003e number\u003e();\n\nwhen(() =\u003e fn()).thenReturn(42).twice();\n\n// Since the expectation doesn't expect any arguments,\n// both of the following are fine\nconsole.log(fn()); // 42\nconsole.log(fn(1)); // 42\n```\n\nIf you're not using TypeScript, or you want to be super strict, you can set `exactParams: true`.\n\n```typescript\nimport { mock } from 'strong-mock';\n\nconst fn = mock\u003c(optionalValue?: number) =\u003e number\u003e({\n  exactParams: true\n});\n\nwhen(() =\u003e fn()).thenReturn(42).twice();\n\nconsole.log(fn()); // 42\nconsole.log(fn(1)); // throws\n```\n\n### Concrete matcher\n\nYou can configure the [matcher](#matchers-1) that will be used in expectations with concrete values e.g. `42` or `{ foo: \"bar\" }`. This matcher can always be overwritten inside an expectation with another matcher.\n\n```typescript\nimport { mock, when, It } from 'strong-mock';\n\n// Use strict equality instead of deep equality.\nconst fn = mock\u003c(x: number[], y: string) =\u003e boolean\u003e({\n  concreteMatcher: It.is\n});\nwhen(() =\u003e fn([1, 2, 3], 'foo')).thenReturn(true);\n\nfn([1, 2, 3], 'foo'); // throws because different array instances\n\nconst arr = [1, 2, 3];\n// The matcher will only apply to non-matcher arguments.\nwhen(() =\u003e fn(arr, It.isString())).thenReturn(true);\nconsole.log(fn(arr, 'any string')); // true\n```\n\n## FAQ\n\n### Why do I have to set all expectations first?\n\nThis library is different from other mocking/spying libraries you might have used before such as [sinon](https://sinonjs.org) or [jest](https://jestjs.io/docs/en/mock-functions). Whereas those libraries are focused on recording calls to the mocks and always returning something, strong-mock requires you to set your expectations upfront. If a call happens that is not expected the mock will throw an error.\n\nThis design decision has a few reasons behind it. First, it forces you to be aware of what your code needs from its dependencies. Spying libraries encourage checking those needs at the end of the test after the code has already called the mocks. This can lead to tests missing dependency calls that just happen to not throw any error at runtime with the dummy values that the spies return.\n\nSecondly, it will highlight potential design problems such as violations of the SOLID principles. If you find yourself duplicating expectations between tests and passing dummy values to them because your test is not concerned with them, then you might want to look into splitting the code to only depend on things it really needs.\n\n### Why do I have to set a return value even if it's `undefined`?\n\nTo make side effects explicit and to prevent future refactoring headaches. If you had just `when(() =\u003e fn())`, and you later changed `fn()` to return a `number`, then your expectation would become incorrect and the compiler couldn't check that for you.\n\n### Why do I get a `Didn't expect mock to be called` error?\n\nThis error happens when your code under test calls a mock that didn't have a matching expectation. It could be that the arguments received didn't match the ones set in the expectation (see [matchers](#matchers-1)), or the call was made more than the allowed number of times (see [invocation count expectations](#setting-invocation-count-expectations)).\n\nIn rare cases, the code under test may try to inspect the mock by accessing special properties on it. For instance, wrapping a mock in `Promise.resolve()` will try to access a `.then` property on it. strong-mock returns stub values for most of these, but if you find another one feel free to [open an issue](https://github.com/NiGhTTraX/strong-mock/issues) with a minimal reproduction.\n\nUnfortunately, not all of these cases can be covered with stub values, and you may have to slightly adjust your code to work around this issue.\n\n### Can I partially mock a concrete implementation?\n\nNo, passing a concrete implementation to `mock()` will be the same as passing a type: all properties will be mocked, and you have to set expectations on the ones that will be accessed.\n\n### How do I set expectations on setters?\n\nYou currently can't do that. Please use a normal method instead e.g. `setFoo()` vs `set foo()`.\n\n### How do I provide a function for the mock to call?\n\nThere is no `thenCall()` method because it can't be safely typed - the type for `thenReturn()` is inferred from the return type in `when`, meaning that the required type would be the return value for the function, not the function itself. However, we can leverage this by setting an expectation on the function property instead:\n\n```typescript\ninterface Foo {\n  bar: (x: number) =\u003e string;\n}\n\nconst foo = mock\u003cFoo\u003e();\n\nwhen(() =\u003e foo.bar).thenReturn(x =\u003e `called ${x}`);\n\nconsole.log(foo.bar(23)); // 'called 23'\n```\n\nThe function in `thenReturn()` will be type checked against the actual interface, so you can make sure you're passing in an implementation that makes sense. Moreover, refactoring the interface will also refactor the expectation (in a capable IDE).\n\n### Can I spread or enumerate a mock?\n\nYes, and you will only get the properties that have expectations on them.\n\n```typescript\nconst foo = mock\u003c{ bar: number; baz: number }\u003e();\nwhen(() =\u003e foo.bar).thenReturn(42);\n\nconsole.log(Object.keys(foo)); // ['bar']\n\nconst foo2 = { ...foo };\n\nconsole.log(foo2.bar); // 42\nconsole.log(foo2.baz); // undefined\n```\n\n### Why does `typeof mock()` return `function`?\n\nAll mocks and methods on them are functions in order to intercept function calls.\n\n### How can I ignore `undefined` keys when setting expectations on objects?\n\nUse the `It.deepEquals` matcher explicitly inside `when` and pass `{ strict: false }`:\n\n```ts\nconst fn = mock\u003c(x: { foo: string, bar?: string }) =\u003e boolean\u003e();\n\nwhen(() =\u003e fn(\n  It.deepEquals({ foo: \"bar\" }, { strict: false }))\n).thenReturn(true);\n\nfn({ foo: \"bar\", baz: undefined }) === true\n```\n\nYou can set this behavior to be the default by configuring the [concrete matcher](#concrete-matcher).\n\n```ts\nsetDefaults({\n  concreteMatcher: (expected) =\u003e It.deepEquals(expected, { strict: false })\n});\n```\n\n### How can I verify order of calls?\n\n`when()` expectations can be satisfied in any order. If your code under test depends on a specific order of execution, consider redesigning it to remove the coupling before the different calls.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNiGhTTraX%2Fstrong-mock","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FNiGhTTraX%2Fstrong-mock","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FNiGhTTraX%2Fstrong-mock/lists"}