{"id":13847212,"url":"https://github.com/tinylibs/tinyspy","last_synced_at":"2025-05-13T19:11:48.743Z","repository":{"id":37096349,"uuid":"437544823","full_name":"tinylibs/tinyspy","owner":"tinylibs","description":"🕵🏻‍♂️ minimal fork of nanospy, with more features ","archived":false,"fork":false,"pushed_at":"2025-04-17T10:20:44.000Z","size":516,"stargazers_count":593,"open_issues_count":1,"forks_count":29,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-12T21:05:01.339Z","etag":null,"topics":["hacktoberfest","jest","spy","test","tinylibs","vite","vitest"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/tinyspy","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/tinylibs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"open_collective":"vitest","github":["sheremet-va","aslemammad"]}},"created_at":"2021-12-12T12:53:15.000Z","updated_at":"2025-05-12T18:41:26.000Z","dependencies_parsed_at":"2022-06-24T13:17:03.086Z","dependency_job_id":"808545d7-698d-495e-9163-c13d1a237706","html_url":"https://github.com/tinylibs/tinyspy","commit_stats":{"total_commits":193,"total_committers":16,"mean_commits":12.0625,"dds":"0.47150259067357514","last_synced_commit":"0168f34151588ff7d1c1c50788fe3326769c6630"},"previous_names":["aslemammad/tinyspy"],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyspy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyspy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyspy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinylibs%2Ftinyspy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinylibs","download_url":"https://codeload.github.com/tinylibs/tinyspy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254010811,"owners_count":21998993,"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":["hacktoberfest","jest","spy","test","tinylibs","vite","vitest"],"created_at":"2024-08-04T18:01:13.415Z","updated_at":"2025-05-13T19:11:48.721Z","avatar_url":"https://github.com/tinylibs.png","language":"TypeScript","funding_links":["https://opencollective.com/vitest","https://github.com/sponsors/sheremet-va","https://github.com/sponsors/aslemammad"],"categories":["TypeScript","Projects Using Vue.js"],"sub_categories":["Open Source"],"readme":"# tinyspy\n\n\u003e minimal fork of nanospy, with more features 🕵🏻‍♂️\n\nA `10KB` package for minimal and easy testing with no dependencies.\nThis package was created for having a tiny spy library to use in `vitest`, but it can also be used in `jest` and other test environments.\n\n_In case you need more tiny libraries like tinypool or tinyspy, please consider submitting an [RFC](https://github.com/tinylibs/rfcs)_\n\n## Installing\n\n```bash\n// with npm\n$ npm install -D tinyspy\n\n// with pnpm\n$ pnpm install -D tinyspy\n\n// with yarn\n$ yarn install -D tinyspy\n```\n\n## Usage\n\n### spy\n\nSimplest usage would be:\n\n```js\nconst fn = (n) =\u003e n + '!'\nconst spied = spy(fn)\n\nspied('a')\n\nconsole.log(spied.called) // true\nconsole.log(spied.callCount) // 1\nconsole.log(spied.calls) // [['a']]\nconsole.log(spied.results) // [['ok', 'a!']]\nconsole.log(spied.returns) // ['a!']\n```\n\nYou can reset calls, returns, called and callCount with `reset` function:\n\n```js\nconst spied = spy((n) =\u003e n + '!')\n\nspied('a')\n\nconsole.log(spied.called) // true\nconsole.log(spied.callCount) // 1\nconsole.log(spied.calls) // [['a']]\nconsole.log(spied.returns) // ['a!']\n\nspied.reset()\n\nconsole.log(spied.called) // false\nconsole.log(spied.callCount) // 0\nconsole.log(spied.calls) // []\nconsole.log(spied.returns) // []\n```\n\nSince 3.0, tinyspy doesn't unwrap the Promise in `returns` and `results` anymore, so you need to await it manually:\n\n```js\nconst spied = spy(async (n) =\u003e n + '!')\n\nconst promise = spied('a')\n\nconsole.log(spied.called) // true\nconsole.log(spied.results) // ['ok', Promise\u003c'a!'\u003e]\n\nawait promise\n\nconsole.log(spied.results) // ['ok', Promise\u003c'a!'\u003e]\n\nconsole.log(await spied.returns[0]) // 'a!'\n```\n\n\u003e [!WARNING]\n\u003e This also means the function that returned a Promise will always have result type `'ok'` even if the Promise rejected\n\nTinyspy 3.0 still exposes resolved values on `resolves` property:\n\n```js\nconst spied = spy(async (n) =\u003e n + '!')\n\nconst promise = spied('a')\n\nconsole.log(spied.called) // true\nconsole.log(spied.resolves) // [] \u003c- not resolved yet\n\nawait promise\n\nconsole.log(spied.resolves) // ['ok', 'a!']\n```\n\n### spyOn\n\n\u003e All `spy` methods are available on `spyOn`.\n\nYou can spy on an object's method or setter/getter with `spyOn` function.\n\n```js\nlet apples = 0\nconst obj = {\n  getApples: () =\u003e 13,\n}\n\nconst spy = spyOn(obj, 'getApples', () =\u003e apples)\napples = 1\n\nconsole.log(obj.getApples()) // prints 1\n\nconsole.log(spy.called) // true\nconsole.log(spy.returns) // [1]\n```\n\n```js\nlet apples = 0\nlet fakedApples = 0\nconst obj = {\n  get apples() {\n    return apples\n  },\n  set apples(count) {\n    apples = count\n  },\n}\n\nconst spyGetter = spyOn(obj, { getter: 'apples' }, () =\u003e fakedApples)\nconst spySetter = spyOn(obj, { setter: 'apples' }, (count) =\u003e {\n  fakedApples = count\n})\n\nobj.apples = 1\n\nconsole.log(spySetter.called) // true\nconsole.log(spySetter.calls) // [[1]]\n\nconsole.log(obj.apples) // 1\nconsole.log(fakedApples) // 1\nconsole.log(apples) // 0\n\nconsole.log(spyGetter.called) // true\nconsole.log(spyGetter.returns) // [1]\n```\n\nYou can reassign mocked function and restore mock to its original implementation with `restore` method:\n\n```js\nconst obj = {\n  fn: (n) =\u003e n + '!',\n}\nconst spied = spyOn(obj, 'fn').willCall((n) =\u003e n + '.')\n\nobj.fn('a')\n\nconsole.log(spied.returns) // ['a.']\n\nspied.restore()\n\nobj.fn('a')\n\nconsole.log(spied.returns) // ['a!']\n```\n\nYou can even make an attribute into a dynamic getter!\n\n```js\nlet apples = 0\nconst obj = {\n  apples: 13,\n}\n\nconst spy = spyOn(obj, { getter: 'apples' }, () =\u003e apples)\n\napples = 1\n\nconsole.log(obj.apples) // prints 1\n```\n\nYou can restore spied function to its original value with `restore` method:\n\n```js\nlet apples = 0\nconst obj = {\n  getApples: () =\u003e 13,\n}\n\nconst spy = spyOn(obj, 'getApples', () =\u003e apples)\n\nconsole.log(obj.getApples()) // 0\n\nobj.restore()\n\nconsole.log(obj.getApples()) // 13\n```\n\n## Authors\n\n| \u003ca href=\"https://github.com/Aslemammad\"\u003e \u003cimg width='150' src=\"https://avatars.githubusercontent.com/u/37929992?v=4\" /\u003e\u003cbr\u003e Mohammad Bagher \u003c/a\u003e | \u003ca href=\"https://github.com/sheremet-va\"\u003e \u003cimg width='150' src=\"https://avatars.githubusercontent.com/u/16173870?v=4\" /\u003e\u003cbr\u003e Vladimir \u003c/a\u003e |\n| ------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |\n\n## Sponsors\n\nYour sponsorship can make a huge difference in continuing our work in open source!\n\n### Vladimir sponsors\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://cdn.jsdelivr.net/gh/sheremet-va/static/sponsors.svg\"\u003e\n    \u003cimg src='https://cdn.jsdelivr.net/gh/sheremet-va/static/sponsors.svg'/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n### Mohammad sponsors\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://cdn.jsdelivr.net/gh/aslemammad/static/sponsors.svg\"\u003e\n    \u003cimg src='https://cdn.jsdelivr.net/gh/aslemammad/static/sponsors.svg'/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinylibs%2Ftinyspy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinylibs%2Ftinyspy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinylibs%2Ftinyspy/lists"}