{"id":16682569,"url":"https://github.com/jchip/run-verify","last_synced_at":"2025-06-24T21:03:39.314Z","repository":{"id":66137389,"uuid":"173659497","full_name":"jchip/run-verify","owner":"jchip","description":"Proper test verifications","archived":false,"fork":false,"pushed_at":"2025-06-09T00:09:49.000Z","size":37,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-06-09T01:18:39.027Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jchip.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2019-03-04T02:26:29.000Z","updated_at":"2025-06-09T00:09:52.000Z","dependencies_parsed_at":"2023-04-01T09:49:19.905Z","dependency_job_id":null,"html_url":"https://github.com/jchip/run-verify","commit_stats":{"total_commits":33,"total_committers":1,"mean_commits":33.0,"dds":0.0,"last_synced_commit":"ab591fe9732a0c70734e46f4efcfce2d6ba814b3"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/jchip/run-verify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchip%2Frun-verify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchip%2Frun-verify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchip%2Frun-verify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchip%2Frun-verify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jchip","download_url":"https://codeload.github.com/jchip/run-verify/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jchip%2Frun-verify/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261756524,"owners_count":23205146,"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-10-12T14:07:57.407Z","updated_at":"2025-06-24T21:03:39.289Z","avatar_url":"https://github.com/jchip.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# run-verify\n\nProper test verifications\n\n```bash\n$ npm install --save-dev run-verify\n```\n\n## Table of Content\n\n- [run-verify](#run-verify)\n  - [Table of Content](#table-of-content)\n  - [`expect` Test Verifications](#expect-test-verifications)\n    - [Verifying Events and `callbacks` without Promise](#verifying-events-and-callbacks-without-promise)\n    - [Verifying with Promisification](#verifying-with-promisification)\n    - [Verifying with run-verify](#verifying-with-run-verify)\n      - [Using `runVerify` with `done`](#using-runverify-with-done)\n      - [Using Promisified `asyncVerify`](#using-promisified-asyncverify)\n  - [Verifying Expected Failures](#verifying-expected-failures)\n    - [Verifying Failures with callbacks](#verifying-failures-with-callbacks)\n    - [Verifying Failures with Promise](#verifying-failures-with-promise)\n    - [Verifying Failures with `run-verify`](#verifying-failures-with-run-verify)\n- [`checkFunc`](#checkfunc)\n  - [0 Parameter](#0-parameter)\n  - [1 Parameter](#1-parameter)\n  - [2 Parameters](#2-parameters)\n- [APIs](#apis)\n  - [`runVerify`](#runverify)\n  - [`asyncVerify`](#asyncverify)\n  - [`runFinally`](#runfinally)\n  - [`runTimeout`](#runtimeout)\n  - [`runDefer`](#rundefer)\n  - [`wrapCheck`](#wrapcheck)\n  - [`wrapCheck` decorators and shortcuts](#wrapcheck-decorators-and-shortcuts)\n    - [`expectError`](#expecterror)\n    - [`expectErrorHas`](#expecterrorhas)\n    - [`expectErrorToBe`](#expecterrortobe)\n    - [`withCallback`](#withcallback)\n    - [`onFailVerify`](#onfailverify)\n  - [`wrapVerify`](#wrapverify)\n  - [`wrapAsyncVerify`](#wrapasyncverify)\n- [License](#license)\n\n- [run-verify](#run-verify)\n  - [Table of Content](#table-of-content)\n  - [`expect` Test Verifications](#expect-test-verifications)\n    - [Verifying Events and `callbacks` without Promise](#verifying-events-and-callbacks-without-promise)\n    - [Verifying with Promisification](#verifying-with-promisification)\n    - [Verifying with run-verify](#verifying-with-run-verify)\n      - [Using `runVerify` with `done`](#using-runverify-with-done)\n      - [Using Promisified `asyncVerify`](#using-promisified-asyncverify)\n  - [Verifying Expected Failures](#verifying-expected-failures)\n    - [Verifying Failures with callbacks](#verifying-failures-with-callbacks)\n    - [Verifying Failures with Promise](#verifying-failures-with-promise)\n    - [Verifying Failures with `run-verify`](#verifying-failures-with-run-verify)\n- [`checkFunc`](#checkfunc)\n  - [0 Parameter](#0-parameter)\n  - [1 Parameter](#1-parameter)\n  - [2 Parameters](#2-parameters)\n- [APIs](#apis)\n  - [`runVerify`](#runverify)\n  - [`asyncVerify`](#asyncverify)\n  - [`runFinally`](#runfinally)\n  - [`runTimeout`](#runtimeout)\n  - [`runDefer`](#rundefer)\n  - [`wrapCheck`](#wrapcheck)\n  - [`wrapCheck` decorators and shortcuts](#wrapcheck-decorators-and-shortcuts)\n    - [`expectError`](#expecterror)\n    - [`expectErrorHas`](#expecterrorhas)\n    - [`expectErrorToBe`](#expecterrortobe)\n    - [`withCallback`](#withcallback)\n    - [`onFailVerify`](#onfailverify)\n  - [`wrapVerify`](#wrapverify)\n  - [`wrapAsyncVerify`](#wrapasyncverify)\n- [License](#license)\n\n## `expect` Test Verifications\n\n### Verifying Events and `callbacks` without Promise\n\nFor test runner that doesn't have built-in `expect` utility, if not all code/libraries you use are promisified, then `expect` in a test that involves async events doesn't work well.\n\nFor example, the `expect` failure below would be out of band as an [UncaughtException] and the test runner can't catch and report it normally:\n\n```js\nit(\"should emit an event\", done =\u003e {\n  foo.on(\"event\", data =\u003e {\n    expect(data).to.equal(\"expected value\");\n    done();\n  });\n});\n```\n\n\u003e test runners generally watch for uncaught errors, but it doesn't always work well and the stack trace may be all confusing.\n\nSee below for discussions on some common patterns for writing tests that need to verify results from async events and callbacks, and how run-verify helps with them.\n\nThe first and obvious solution is you need to enclose verifications in `try/catch`:\n\n```js\nit(\"should emit an event\", done =\u003e {\n  foo.on(\"event\", data =\u003e {\n    try {\n      expect(data).to.equal(\"expected value\");\n      done();\n    } catch (err) {\n      done(err);\n    }\n  });\n});\n```\n\nHowever, it gets very messy like callback hell when a test deals with multiple async events.\n\nEven with a test runner that takes a Promise as a return result, the same thing must be done:\n\n```js\nit(\"should emit an event\", () =\u003e {\n  return new Promise((resolve, reject) =\u003e {\n    foo.on(\"event\", data =\u003e {\n      try {\n        expect(data).to.equal(\"expected value\");\n        resolve();\n      } catch (err) {\n        reject(err);\n      }\n    });\n  });\n});\n```\n\n### Verifying with Promisification\n\nThe test verification can be written nicely with promisification like:\n\n```js\nconst promisifiedFooEvent() =\u003e new Promise(resolve =\u003e foo.on(\"event\", resolve));\n```\n\nSo the verification is now like this:\n\n```js\nit(\"should emit an event\", done =\u003e {\n  return promisifiedFooEvent()\n    .then(data =\u003e {\n      expect(data).to.equal(\"expected value\");\n    })\n    .then(done)\n    .catch(done);\n});\n```\n\nThe `.then(done).catch(done)` can be avoided if the test runner takes a Promise as return result:\n\n```js\nit(\"should emit an event\", () =\u003e {\n  return promisifiedFooEvent().then(data =\u003e {\n    expect(data).to.equal(\"expected value\");\n  });\n});\n```\n\nIt's even nicer if `async/await` is supported:\n\n```js\nit(\"should emit an event\", async () =\u003e {\n  const data = await promisifiedFooEvent();\n  expect(data).to.equal(\"expected value\");\n});\n```\n\n### Verifying with run-verify\n\nBut if you prefer not to wrap with promisification or facing a complex scenario, **run-verify** always allows you to write test verification nicely:\n\n#### Using `runVerify` with `done`\n\nUsing `runVerify` if you are using the `done` callback from the test runner:\n\n```js\nconst { runVerify } = require(\"run-verify\");\n\nit(\"should emit an event\", done =\u003e {\n  runVerify(\n    next =\u003e foo.on(\"event\", next),\n    data =\u003e expect(data).to.equal(\"expected value\"),\n    done\n  );\n});\n```\n\n#### Using Promisified `asyncVerify`\n\nUsing `asyncVerify` if you are returning a Promise to the test runner:\n\n```js\nconst { asyncVerify } = require(\"run-verify\");\n\nit(\"should emit an event\", () =\u003e {\n  return asyncVerify(\n    next =\u003e foo.on(\"event\", next),\n    data =\u003e expect(data).to.equal(\"expected value\")\n  );\n});\n```\n\n## Verifying Expected Failures\n\nWhen you need to verify that a function actually throws an error, you can do:\n\n```js\nit(\"should throw\", () =\u003e {\n  expect(() =\u003e foo(\"bad input\")).to.throw(\"bad input passed\");\n});\n```\n\nHowever, this gets a bit trickier for async functions which can invoke callback or reject with an error.\n\nSee below for some common patterns on how to verify async functions return errors and how **run-verify** helps.\n\n### Verifying Failures with callbacks\n\n```js\nit(\"should invoke callback with error\", done =\u003e {\n  foo(\"bad input\", err =\u003e {\n    if (err) {\n      try {\n        expect(err.message).includes(\"bad input passed\");\n        done();\n      } catch (err2) {\n        done(err2);\n      }\n    }\n  });\n});\n```\n\n### Verifying Failures with Promise\n\nFor promise it is tricky, but the pattern I commonly use is to have a `.catch` that saves the expect error and then verify it in a `.then`:\n\n```js\nit(\"should reject\", () =\u003e {\n  let error;\n  return promisifiedFoo(\"bad input\")\n    .catch(err =\u003e {\n      error = err;\n    })\n    .then(() =\u003e {\n      expect(error).to.exist;\n      expect(error.message).includes(\"bad input passed\");\n    });\n});\n```\n\nWith `async/await`, it can be done very nicely using `try/catch`:\n\n```js\nit(\"should reject\", async () =\u003e {\n  try {\n    await promisifiedFoo(\"bad input\");\n    throw new Error(\"expected rejection\");\n  } catch (err) {\n    expect(err.message).includes(\"bad input passed\");\n  }\n});\n```\n\n### Verifying Failures with `run-verify`\n\n`run-verify` has an [`expectError`](#expecterror) decorator to mark a [`checkFunc`](#checkfunc) is expecting to return or throw an error:\n\nExample that uses a `done` callback from the test runner:\n\n```js\nconst { expectError, runVerify } = require(\"run-verify\");\n\nit(\"should invoke callback with error\", done =\u003e {\n  runVerify(\n    expectError(next =\u003e foo(\"bad input\", next)),\n    err =\u003e expect(err.message).includes(\"bad input passed\"),\n    done\n  );\n});\n```\n\nExample that returns a Promise to the test runner:\n\n```js\nconst { expectError, asyncVerify } = require(\"run-verify\");\n\nit(\"should invoke callback with error\", () =\u003e {\n  return asyncVerify(\n    expectError(next =\u003e foo(\"bad input\", next)),\n    err =\u003e expect(err.message).includes(\"bad input passed\")\n  );\n});\n```\n\nExample when everything is promisified:\n\n```js\nconst { expectError, asyncVerify } = require(\"run-verify\");\n\nit(\"should invoke callback with error\", () =\u003e {\n  return asyncVerify(\n    expectError(() =\u003e promisifiedFoo(\"bad input\")),\n    err =\u003e expect(err.message).includes(\"bad input passed\")\n  );\n});\n```\n\n# `checkFunc`\n\n`runVerify` takes a list of functions as [`checkFunc`](#checkfunc) to be invoked serially to run the test verification.\n\nEach [`checkFunc`](#checkfunc) can take 0, 1, or 2 parameters.\n\n### 0 Parameter\n\n```js\n() =\u003e {};\n```\n\n- Assume to be a sync function\n- But if it's intended to be async, then it should return a Promise\n  - The Promise's resolved value is passed to next [`checkFunc`](#checkfunc).\n\n### 1 Parameter\n\n```js\n(next | result) =\u003e {};\n```\n\nWith only 1 parameter, it gets ambiguous whether it wants a `next` callback or a sync/Promise function taking a result.\n\n`runVerify` does the following to disambiguate the [`checkFunc`](#checkfunc)'s single parameter:\n\n- It's expected to be the `next` callback if:\n  - the parameter name starts with one of the following:\n    - `next`, `cb`, `callback`, or `done`\n    - The name check is case insensitive\n  - The function is decorated with the [withCallback](#withcallback) decorator\n- Otherwise it's expected to take the result from previous [`checkFunc`](#checkfunc)\n  - And its behavior is treated the same as the [0 parameter checkFunc](#0-parameter)\n- A native `AsyncFunction` is always expected to take the result and returns a Promise.\n\nie:\n\n```js\nasync result =\u003e {};\n```\n\n### 2 Parameters\n\n```js\n(result, next) =\u003e {};\n```\n\nThis is always treated as an async function taking the `result` and a `next` callback:\n\n- `result` - result from previous [`checkFunc`](#checkfunc)\n- `next` - callback to invoke the next [`checkFunc`](#checkfunc)\n\n# APIs\n\n## `runVerify`\n\n```js\nrunVerify(...checkFuncs, done);\n```\n\nThe main API, params:\n\n| name         | description                                                         |\n| ------------ | ------------------------------------------------------------------- |\n| `checkFuncs` | variadic list of functions to invoke to run tests and verifications |\n| `done`       | `done(err, result)` callback after verification is done or failed   |\n\n- See details about [checkFunc](#checkfunc).\n\nEach [`checkFunc`](#checkfunc) is invoked serially, with the result from one passed to the next, depending on its parameters.\n\n`done` is invoked at the end, but if any [`checkFunc`](#checkfunc) fails, then `done` is invoked immediately with the error.\n\n## `asyncVerify`\n\n```js\nasyncVerify(...checkFuncs);\n```\n\nThe promisified version of [runVerify](#runverify). Returns a Promise.\n\n\u003e Make sure no `done` callback is passed as the last parameter.\n\n## `runFinally`\n\n```js\nrunFinally(finallyFunc);\n```\n\nCreate a callback that's always called.\n\n- The `finally` callback can return a Promise.\n- If any of them throws or rejects, then `done` is called with the error.\n- They can appear in any order and there can be multiple of them.\n\nie:\n\n```js\nrunVerify(\n  runFinally(() =\u003e {}),\n  () =\u003e {\n    // test code\n    return \"foo\";\n  },\n  runFinally(() =\u003e return promiseCleanup()),\n  result =\u003e {\n    // expect result === \"foo\n  },\n  done\n)\n```\n\n## `runTimeout`\n\n```js\nrunTimeout(ms);\n```\n\nSet a timeout in `ms` milliseconds for the test.\n\nYou can have multiple of these but only the last one has effect.\n\nexample:\n\n```js\nconst { asyncVerify, runTimeout } = require(\"run-verify\");\n\nit(\"should verify events\", () =\u003e {\n  return asyncVerify(\n    runTimeout(50),\n    next =\u003e foo.on(\"event1\", msg =\u003e next(null, msg)),\n    msg =\u003e expect(msg).equal(\"ok\"),\n    runTimeout(20),\n    next =\u003e bar.on(\"event2\", msg =\u003e next(null, msg)),\n    msg =\u003e expect(msg).equal(\"done\")\n  );\n});\n```\n\n## `runDefer`\n\n```js\nrunDefer([ms]);\n```\n\nCreate a defer object for waiting on events.\n\n- `ms` - optional timeout in `ms` milliseconds for this defer.\n\nReturns: the defer object with these methods:\n\n- `resolve(result)` - resolve the defer object: `resolve(\"OK\")`.\n- `reject(error)` - reject with error: `reject(new Error(\"fail\"))`.\n- `wait([ms])` - Wait for the defer object.\n- `clear()` - Put resolved defer back into pending status.\n\nNOTES:\n\n\u003e - All registered `defer` must resolve for the test to complete.\n\u003e - Any rejection not waited on will fail the test immediately.\n\u003e - You can decorate `wait` with [expectError](#expecterror).\n\nexample:\n\nExplicitly wait on the defer objects:\n\n```js\nconst { asyncVerify, runDefer } = require(\"run-verify\");\n\nit(\"should verify events\", () =\u003e {\n  const defer = runDefer();\n  const defer2 = runDefer();\n\n  return asyncVerify(\n    () =\u003e foo.on(\"event1\", msg =\u003e defer.resolve(msg)),\n    // explicitly wait for defer before continuing with the test\n    defer.wait(50),\n    msg =\u003e expect(msg).equal(\"ok\"),\n    () =\u003e bar.on(\"event2\", msg =\u003e defer2.resolve(msg)),\n    // explicitly wait for defer before continuing with the test\n    defer2.wait(20),\n    msg =\u003e expect(msg).equal(\"done\")\n  );\n});\n```\n\nJust put defer anywhere as long as they resolve:\n\n```js\nconst { asyncVerify, runDefer } = require(\"run-verify\");\n\nit(\"should verify events\", () =\u003e {\n  const defer = runDefer();\n  const defer2 = runDefer();\n\n  return asyncVerify(\n    // just telling runVerify that there are two defer events that must\n    // resolve for the test to finish, but you can't verify on their results.\n    defer,\n    defer2,\n    () =\u003e foo.on(\"event1\", msg =\u003e defer.resolve(msg)),\n    () =\u003e bar.on(\"event2\", msg =\u003e defer2.resolve(msg))\n  );\n});\n```\n\n## `wrapCheck`\n\n```js\nwrapCheck(checkFunc);\n```\n\nWrap a [`checkFunc`](#checkfunc) with these decorators:\n\n- [`expectError`](#expecterror), [`expectErrorHas`](#expecterrorhas), [`expectErrorToBe`](#expecterrortobe)\n- [`withCallback`](#withcallback)\n- [`onFailVerify`](#onfailverify)\n\nFor example:\n\n```js\nrunVerify(wrapCheck(next =\u003e foo(\"bad input\", next)).expectError.withCallback, done);\n```\n\n## `wrapCheck` decorators and shortcuts\n\n### `expectError`\n\n```js\nexpectError(checkFunc);\n```\n\nShortcut for:\n\n```js\nwrapCheck(checkFunc).expectError;\n```\n\nDecorate a [`checkFunc`](#checkfunc) expecting to throw or return `Error`. Its error will be passed to the next [`checkFunc`](#checkfunc).\n\nThis uses [wrapCheck](#wrapcheck) internally so [withCallback](#withcallback) is also available after:\n\n```js\nexpectError(() =\u003e {}).withCallback;\n```\n\n### `expectErrorHas`\n\n```js\nexpectErrorHas(checkFunc, msg);\n```\n\nShortcut for:\n\n```js\nwrapCheck(checkFunc).expectErrorHas(msg);\n```\n\nDecorate a [`checkFunc`](#checkfunc) expecting to throw or return `Error` with message containing `msg`. Its error will be passed to the next [`checkFunc`](#checkfunc).\n\n### `expectErrorToBe`\n\n```js\nexpectErrorToBe(checkFunc, msg);\n```\n\nShortcut for:\n\n```js\nwrapCheck(checkFunc).expectErrorToBe(msg);\n```\n\nDecorate a [`checkFunc`](#checkfunc) expecting to throw or return `Error` with message to be `msg`. Its error will be passed to the next `checkFunc`.\n\n### `withCallback`\n\n```js\nwithCallback(checkFunc);\n```\n\nShortcut for:\n\n```js\nwrapCheck(checkFunc).withCallback;\n```\n\nDecorate a [`checkFunc`](#checkfunc) that takes a single parameter to expect a `next` callback for that parameter.\n\nThis uses [wrapCheck](#wrapcheck) internally so [expectError](#expecterror) is also available after:\n\n```js\nwithCallback(() =\u003e {}).expectError;\n```\n\n### `onFailVerify`\n\n```js\nonFailVerify(checkFunc);\n```\n\nShortcut for:\n\n```js\nwrapCheck(checkFunc).onFailVerify;\n```\n\nDecorate a [`checkFunc`](#checkfunc) that will be called with `err` if the `checkFunc` right before it failed.\n\nIt's skipped if the `checkFunc` right before it passed.\n\n- Its returned value will be ignored.\n- Any exceptions from it will be caught and used as the new error for failing the test.\n\nExample:\n\n```js\nreturn asyncVerify(\n  () =\u003e {\n    throw new Error(\"oops\");\n  },\n  onFailVerify(err =\u003e {\n    console.log(\"test failed with\", err);\n  })\n);\n```\n\n## `wrapVerify`\n\n```js\nwrapVerify(...checkFuncs, done);\n```\n\n- Returns a function that wraps [`runVerify`](#runverify).\n- The new function takes a single parameter and pass it to the first `checkFunc`.\n\n## `wrapAsyncVerify`\n\n```js\nwrapAsyncVerify(...checkFuncs);\n```\n\nThe promisified version of [`wrapVerify`](#wrapverify)\n\n# License\n\nLicensed under the [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0)\n\n---\n\n[uncaughtexception]: https://nodejs.org/api/process.html#process_event_uncaughtexception\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjchip%2Frun-verify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjchip%2Frun-verify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjchip%2Frun-verify/lists"}