{"id":19460014,"url":"https://github.com/fongandrew/call-next","last_synced_at":"2026-04-19T15:31:14.139Z","repository":{"id":57192978,"uuid":"98370391","full_name":"fongandrew/call-next","owner":"fongandrew","description":"Hook to interrupt asynchronous function flow for ease of testing","archived":false,"fork":false,"pushed_at":"2017-07-26T07:11:36.000Z","size":42,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2026-02-10T19:17:34.372Z","etag":null,"topics":["async","javascript","stub","testing","typescript","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/fongandrew.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-26T02:32:25.000Z","updated_at":"2017-10-13T23:06:25.000Z","dependencies_parsed_at":"2022-09-01T06:01:15.581Z","dependency_job_id":null,"html_url":"https://github.com/fongandrew/call-next","commit_stats":null,"previous_names":["esperco/call-next"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/fongandrew/call-next","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fongandrew%2Fcall-next","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fongandrew%2Fcall-next/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fongandrew%2Fcall-next/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fongandrew%2Fcall-next/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fongandrew","download_url":"https://codeload.github.com/fongandrew/call-next/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fongandrew%2Fcall-next/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32011905,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["async","javascript","stub","testing","typescript","unit-testing"],"created_at":"2024-11-10T17:35:15.466Z","updated_at":"2026-04-19T15:31:14.109Z","avatar_url":"https://github.com/fongandrew.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"call-next\n=========\n[![Build Status](https://travis-ci.org/esperco/call-next.svg?branch=master)](https://travis-ci.org/esperco/call-next)\n[![npm version](https://badge.fury.io/js/call-next.svg)](https://badge.fury.io/js/call-next)\n\nLibrary to help with asynchronous testing\n\nInstallation\n------------\n`npm install call-next --save` or `yarn add call-next`\n\nUsage\n-----\nSee [example/index.js](/example/index.js).\n\nRationale\n---------\nTesting asynchronous code with side effects (e.g. a function that makes an API\ncall and does something with the result) can be difficult. Stubbing specific\nfunctions in advance of a test may result in over-stubbing (e.g. stubbing all\nthe API calls the function under test ) or under-stubbing (e.g. forgetting to\nstub a particular API call, which triggers a side effect during testing).\n\nThis library is loosely inspired by how\n[Redux-Saga approaches testing](https://redux-saga.js.org/docs/advanced/Testing.html),\nwhich uses a combination of generators and declarative effects to let a test\n\"step\" through an otherwise asynchronous function and test that the right\nthings happen at each step. This library mimics that functionality for\nenvironments where generators are unavilable or where the mental overhead of\nusing something like Redux-Saga is undesirable.\n\nAPI\n---\n\n```ts\ncall\u003cF\u003e(fn: F): F\ncall\u003cF\u003e(context: any, fn: F): F\ncall\u003cF\u003e(context: any, name: string): context[name]\n```\nWraps an async function.\nFunction should return a promise. You can specify a context to bind to the\nfunction by providing the context as a first argument and the function or\nthe property name on the context as the second argument.\n\n---\n\n```ts\nwithStub((getCalls, next) =\u003e async { ... })\n```\nStubs the `call` function.\nReturns the return value of its callback (which should be a promise).\nCallback receives the `getCalls` and `next` functions (see below). These\nfunctions can also be imported directly from the `call-next` module.\n\n---\n\n```ts\ngetCalls(): Calls[]\ngetCalls(n: number): Call\n```\nReturns either a list of Call objects\n(if no argument is passed) or a single Call object if passed an index for the\ncall being examined. There should be one Call object for each invocation\nof the stubbed `call` in the last tick. A Call object comes with `resolve` and\n`reject` methods to resolve and reject the promise returned by the stubbed\n`call` method. It also contains a `cmd` property that declaratively describes\nhow it was called and can be deeply compared to an expected value:\n\n```ts\ninterface Cmd {\n  fn: Function;\n  args: any[];\n  context?: any; // If context is undefined, this property will not exist\n}\n```\n\n---\n\n```ts\nnext(): Promise\u003cvoid\u003e\n```\nJumps one tick forward and resets the value of getCalls.\n\n---\n\n```ts\nassertDone\u003cT\u003e(promise: Promise\u003cT\u003e): Promise\u003cT\u003e\n```\nReturns a promise that\nrejects if the given promise does not resolve in the next tick. Use this\nso that any async call that you forget to resolve doesn't cause our test\nto timeout.\n\n---\n\n```ts\nstub()\nunstub()\n```\nManually stub and unstub the `call` function. You may want to\nuse these functions in lieu of `withStub` if you want the stubbing to happen\nin your own setup and teardown functions.\n\n---\n\n```ts\nreset()\n```\nManually reset the value of `getCalls`\n\nProduction Builds\n-----------------\n`call-next` is a fairly small library to begin with, but if you want to remove\nthe stubbing functionality in a production or non-test build, you can alias\nthe `call-next` module to `call-next/lib/call` instead, which exposes the\n`call` function and nothing else.\n\nWith Webpack, you would modify your `webpack.config.js` like this:\n\n```js\nmodule.exports = {\n\n  /*\n    Your normal webpack config here\n  */\n\n  resolve: {\n    alias: process.env.NODE_ENV === \"production\" ? {\n      \"call-next\": \"./node_modules/call-next/lib/call.js\"\n    } : {}\n  }\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffongandrew%2Fcall-next","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffongandrew%2Fcall-next","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffongandrew%2Fcall-next/lists"}