{"id":19486217,"url":"https://github.com/textbook/rxjest","last_synced_at":"2026-05-13T08:08:58.969Z","repository":{"id":60148339,"uuid":"541289557","full_name":"textbook/rxjest","owner":"textbook","description":"Jest matchers for working with RxJS observables","archived":false,"fork":false,"pushed_at":"2023-12-14T15:37:43.000Z","size":971,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-05T07:51:34.807Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/textbook.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,"publiccode":null,"codemeta":null}},"created_at":"2022-09-25T19:41:10.000Z","updated_at":"2022-09-25T20:18:05.000Z","dependencies_parsed_at":"2025-02-25T18:35:20.644Z","dependency_job_id":"f5e4096b-3ffd-4038-bae4-d87023431abf","html_url":"https://github.com/textbook/rxjest","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/textbook/rxjest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textbook%2Frxjest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textbook%2Frxjest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textbook%2Frxjest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textbook%2Frxjest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/textbook","download_url":"https://codeload.github.com/textbook/rxjest/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textbook%2Frxjest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32973375,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T06:31:55.726Z","status":"ssl_error","status_checked_at":"2026-05-13T06:31:51.336Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":[],"created_at":"2024-11-10T20:35:41.360Z","updated_at":"2026-05-13T08:08:58.945Z","avatar_url":"https://github.com/textbook.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RxJeSt\n\n[![Node.js CI](https://github.com/textbook/rxjest/actions/workflows/push.yml/badge.svg)](https://github.com/textbook/rxjest/actions/workflows/push.yml)\n[![NPM](https://img.shields.io/npm/v/rxjest?color=blue\u0026logo=npm)](https://www.npmjs.com/package/rxjest)\n\n[Jest] matchers for working with [RxJS] observables.\n\n## Usage\n\nAdd the matchers to Jest by importing this package in a [setup file]:\n\n```js\n// jest.config.js\nmodule.exports = {\n  // ...\n  \"setupFilesAfterEnv\": [\n    \"\u003crootDir\u003e/setupTests.js\"\n  ]\n}\n```\n```js\n// setupTests.js\nimport \"rxjest\";  // or require(\"rxjest\");\n```\n\n### Matchers\n\nOnce added, the following matchers will be available:\n\n#### `.toEmit`\n\n`.toEmit` checks that the supplied observable emits the specified value at some point before completing:\n\n```js\nit(\"asserts that a matching value was emitted\", async () =\u003e {\n    await expect(from([\"foo\", \"bar\", \"baz\"])).toEmit(\"bar\", { within: 25 });\n});\n```\n\n**Note** that this is an asynchronous matcher that needs to be `await`ed or `return`ed.\n\nThis matcher takes an optional second argument, an object containing the following options:\n\n- `within` - the time, in ms, to wait to see if the expected value is (or is not) emitted\n\nThis matcher has the following failure cases:\n\n- If the observable completes without a matching value being emitted, the test fails (and shows the values that _were_\n    emitted, to aid in debugging):\n\n    ```none\n      ● extending Jest › failing examples for docs › shows emitted values\n    \n        expect(observable$).toEmit(value) // deep equality\n    \n        Expected value: \"qux\"\n        Emitted values: [\"foo\", \"bar\", \"baz\"]\n    \n          34 |      fdescribe(\"failing examples for docs\", () =\u003e {\n          35 |              it(\"shows emitted values\", async () =\u003e {\n        \u003e 36 |                      await expect(from([\"foo\", \"bar\", \"baz\"])).toEmit(\"qux\");\n             |                                                                ^\n          37 |              });\n          38 |\n          39 |              it(\"passes errors to Jest\", async () =\u003e {\n    \n          at Object.\u003canonymous\u003e (src/index.test.ts:36:46)\n    ```\n\n- If the observable errors, the error is propagated to the test and reported by Jest:\n\n    ```none\n      ● extending Jest › failing examples for docs › passes errors to Jest\n    \n        oh no!\n    \n          38 |\n          39 |              it(\"passes errors to Jest\", async () =\u003e {\n        \u003e 40 |                      await expect(throwError(() =\u003e new Error(\"oh no!\"))).toEmit(expect.anything());\n             |                                                    ^\n          41 |              });\n          42 |\n          43 |              it(\"times out\", async () =\u003e {\n    \n          at src/index.test.ts:40:34\n          at src/matchers.ts:25:11\n          at emittedUnless (src/matchers.ts:23:9)\n          at Object.toEmit (src/matchers.ts:9:24)\n          at Object.\u003canonymous\u003e (src/index.test.ts:40:56)\n    ```\n\n- If the observable neither emits a matching value nor completes within the timeout, the test times out:\n\n    ```none\n      ● extending Jest › failing examples for docs › times out\n\n        thrown: \"Exceeded timeout of 100 ms for a test.\n        Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test.\"\n\n          51 |              });\n          52 |\n      \u003e   53 |              it(\"times out\", async () =\u003e {\n             |              ^\n          54 |                      await expect(new Observable()).toEmit(123);\n          55 |              }, 100);\n          56 |\n\n          at src/index.test.ts:53:3\n          at src/index.test.ts:44:11\n          at Object.\u003canonymous\u003e (src/index.test.ts:5:1)\n    ```\n\n#### `.toError`\n\n`.toError` checks that the supplied observable errors rather than completing:\n\n```js\nit(\"asserts that the observable errors\", async () =\u003e {\n    await expect(throwError(() =\u003e new Error(\"oh no!\"))).toError();\n});\n```\n\n**Note** that this is an asynchronous matcher that needs to be `await`ed or `return`ed.\n\nThis matcher takes an optional argument, an object containing the following options:\n\n- `within` - the time, in ms, to wait to see if the observable errors (or does not)\n\nThis matcher has the following failure cases:\n\n- If the observable completes without an error, that is shown explicitly:\n\n    ```none\n      ● extending Jest › failing examples for docs › reports expected errors not received\n\n        expect(observable$).toError()\n\n        Observable completed without error\n\n          60 |\n          61 |              it(\"reports expected errors not received\", async () =\u003e {\n        \u003e 62 |                      await expect(from([])).toError();\n             |                                             ^\n          63 |              });\n          64 |      });\n          65 | });\n\n          at Object.\u003canonymous\u003e (src/index.test.ts:62:27)\n    ```\n\n- If an unexpected error is thrown, it is shown in the output:\n\n    ```none\n      ● extending Jest › failing examples for docs › reports unexpected errors\n\n        expect(observable$).not.toError()\n\n        Expected value: not [Error: oh no!]\n\n          56 |\n          57 |              it(\"reports unexpected errors\", async () =\u003e {\n        \u003e 58 |                      await expect(throwError(() =\u003e new Error(\"oh no!\"))).not.toError();\n             |                                                                              ^\n          59 |              });\n          60 |\n          61 |              it(\"reports expected errors not received\", async () =\u003e {\n\n          at Object.\u003canonymous\u003e (src/index.test.ts:58:60)\n    ```\n\n- If the observable does not error within the timeout, the test times out (see example above)\n\n#### `.toErrorWith`\n\n`.toErrorWith` checks that the supplied observable errors with a matching message rather than completing:\n\n```js\nit(\"asserts that the observable errors\", async () =\u003e {\n    await expect(throwError(() =\u003e new Error(\"oh no!\"))).toErrorWith(/^oh no!$/);\n});\n```\n\n**Note** that this is an asynchronous matcher that needs to be `await`ed or `return`ed.\n\nThis matcher has the following failure cases:\n\n- If the observable completes without an error, that is shown explicitly:\n\n    ```none\n      ● extending Jest › failing examples for docs › reports matching errors not received\n\n        expect(observable$).toErrorWith(expected)\n\n        Expected pattern: /whoops/\n\n        Observable completed without error\n\n          90 |\n          91 |              it(\"reports matching errors not received\", async () =\u003e {\n        \u003e 92 |                      await expect(from([])).toErrorWith(/whoops/);\n             |                                             ^\n          93 |              });\n          94 |\n          95 |              it(\"reports mismatched errors received\", async () =\u003e {\n\n          at Object.\u003canonymous\u003e (src/index.test.ts:92:27)\n    ```\n\n- If an unexpected error is thrown, it is shown in the output:\n\n    ```none\n      ● extending Jest › failing examples for docs › reports mismatched errors received\n\n        expect(observable$).toErrorWith(expected)\n\n        Expected pattern: /whoops/\n        Received message: \"oh no!\"\n\n          94 |\n          95 |              it(\"reports mismatched errors received\", async () =\u003e {\n      \u003e   96 |                      await expect(throwError(() =\u003e new Error(\"oh no!\"))).toErrorWith(/whoops/);\n             |                                                                          ^\n          97 |              });\n          98 |\n          99 |              it(\"reports matched errors unexpectedly received\", async () =\u003e {\n\n          at Object.\u003canonymous\u003e (src/index.test.ts:96:56)\n    ```\n\n- If an unexpected match is received it is shown:\n\n    ```none\n      ● extending Jest › failing examples for docs › reports matched errors unexpectedly received\n\n        expect(observable$).not.toErrorWith(expected)\n\n        Expected pattern: not /oh no/\n        Received message: \"oh no!\"\n\n           98 |\n           99 |             it(\"reports matched errors unexpectedly received\", async () =\u003e {\n        \u003e 100 |                     await expect(throwError(() =\u003e new Error(\"oh no!\"))).not.toErrorWith(/oh no/);\n              |                                                                             ^\n          101 |             });\n          102 |     });\n          103 | });\n\n          at Object.\u003canonymous\u003e (src/index.test.ts:100:60)\n    ```\n\n### Version support\n\n- **Jest**: tested against v27, v28 and v29 (see `peerDependencies` field in `package.json`)\n- **Node**: tested against v14, v16 and v18 (see `engines` field in `package.json`)\n- **RxJS**: tested against v6 and v7 (see `peerDependencies` field in `package.json`)\n\n### Linting\n\nIf you're using the Jest plugin for ESLint and have [`jest/valid-expect`][valid-expect] enabled, you can configure it\nto understand that the matchers are asynchronous as follows:\n\n```json5\n{\n  // ...\n  \"rules\": {\n    // ...\n    \"jest/valid-expect\": [\n      \"error\",\n      {\n        \"asyncMatchers\": [\n          \"toEmit\",\n          \"toError\",\n          \"toErrorWith\"\n        ]\n      }\n    ]\n  }\n}\n```\n\n## Development\n\nYou can [fork and clone] this repository to work on it. Once you've cloned the code locally, install the dependencies\nwith `npm ci` then check everything is installed and running correctly with `npm run ship`.\n\n### Scripts\n\nThe following convenience scripts are provided for development and can be run with `npm run \u003cscript\u003e`:\n\n- `build`: Transpile the source code from `src/` to `lib/`\n- `e2e`: Test the package at an E2E level using `bin/e2e.sh`\n  - The script takes an argument specifying the version to download from NPM and test or `local` to test the current\n    code (e.g. `npm run e2e -- x.y.z`)\n  - When testing the local package, use the `--build` flag to rebuild and repack the package (i.e.\n    `npm run e2e -- local --build`)\n  - The version of Jest installed in the example package can be overridden from the default (v29) using the\n    `JEST_VERSION` environment variable\n  - The version of RxJS installed in the example package can be overridden from the default (v7) using the\n    `RXJS_VERSION` environment variable\n- `lint`: Check the code style with ESLint\n- `ship`: Lint, then run low-level tests, then run high-level tests\n- `test`: Test the source code at a unit and integration level using Jest\n\n### Testing\n\nThere are three levels of testing:\n\n- **E2E**: the highest level is provided by actually using RxJeSt in an example package. The tests used here are\n  in `demo.js` (which is copied into the example package and renamed by `bin/e2e.sh`).\n- **Integration**: `index.test.js` uses the matchers in an actual Jest context, but is still importing source code\n  rather than using the transpiled package\n- **Unit**: the lowest level of tests are in `src/matchers/\u003cmatcher\u003e.test.ts`. These can check more granular details of\n  e.g. failing test messages by directly invoking the matcher functions with a context equivalent to what Jest provides\n  as `this` (the context can be created with `createContext` from `src/matchers/testUtils.ts`).\n\n[fork and clone]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks\n[jest]: https://jestjs.io/\n[rxjs]: https://rxjs.dev/\n[setup file]: https://jestjs.io/docs/configuration#setupfilesafterenv-array\n[valid-expect]: https://github.com/jest-community/eslint-plugin-jest/blob/main/docs/rules/valid-expect.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftextbook%2Frxjest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftextbook%2Frxjest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftextbook%2Frxjest/lists"}