npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

rxjest

v0.7.2

Published

Jest matchers for working with RxJS observables

Downloads

16

Readme

RxJeSt

Node.js CI NPM

Jest matchers for working with RxJS observables.

Usage

Add the matchers to Jest by importing this package in a setup file:

// jest.config.js
module.exports = {
  // ...
  "setupFilesAfterEnv": [
    "<rootDir>/setupTests.js"
  ]
}
// setupTests.js
import "rxjest";  // or require("rxjest");

Matchers

Once added, the following matchers will be available:

.toEmit

.toEmit checks that the supplied observable emits the specified value at some point before completing:

it("asserts that a matching value was emitted", async () => {
    await expect(from(["foo", "bar", "baz"])).toEmit("bar", { within: 25 });
});

Note that this is an asynchronous matcher that needs to be awaited or returned.

This matcher takes an optional second argument, an object containing the following options:

  • within - the time, in ms, to wait to see if the expected value is (or is not) emitted

This matcher has the following failure cases:

  • If the observable completes without a matching value being emitted, the test fails (and shows the values that were emitted, to aid in debugging):

      ● extending Jest › failing examples for docs › shows emitted values
      
        expect(observable$).toEmit(value) // deep equality
      
        Expected value: "qux"
        Emitted values: ["foo", "bar", "baz"]
      
          34 |      fdescribe("failing examples for docs", () => {
          35 |              it("shows emitted values", async () => {
        > 36 |                      await expect(from(["foo", "bar", "baz"])).toEmit("qux");
             |                                                                ^
          37 |              });
          38 |
          39 |              it("passes errors to Jest", async () => {
      
          at Object.<anonymous> (src/index.test.ts:36:46)
  • If the observable errors, the error is propagated to the test and reported by Jest:

      ● extending Jest › failing examples for docs › passes errors to Jest
      
        oh no!
      
          38 |
          39 |              it("passes errors to Jest", async () => {
        > 40 |                      await expect(throwError(() => new Error("oh no!"))).toEmit(expect.anything());
             |                                                    ^
          41 |              });
          42 |
          43 |              it("times out", async () => {
      
          at src/index.test.ts:40:34
          at src/matchers.ts:25:11
          at emittedUnless (src/matchers.ts:23:9)
          at Object.toEmit (src/matchers.ts:9:24)
          at Object.<anonymous> (src/index.test.ts:40:56)
  • If the observable neither emits a matching value nor completes within the timeout, the test times out:

      ● extending Jest › failing examples for docs › times out
    
        thrown: "Exceeded timeout of 100 ms for a test.
        Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
    
          51 |              });
          52 |
      >   53 |              it("times out", async () => {
             |              ^
          54 |                      await expect(new Observable()).toEmit(123);
          55 |              }, 100);
          56 |
    
          at src/index.test.ts:53:3
          at src/index.test.ts:44:11
          at Object.<anonymous> (src/index.test.ts:5:1)

.toError

.toError checks that the supplied observable errors rather than completing:

it("asserts that the observable errors", async () => {
    await expect(throwError(() => new Error("oh no!"))).toError();
});

Note that this is an asynchronous matcher that needs to be awaited or returned.

This matcher takes an optional argument, an object containing the following options:

  • within - the time, in ms, to wait to see if the observable errors (or does not)

This matcher has the following failure cases:

  • If the observable completes without an error, that is shown explicitly:

      ● extending Jest › failing examples for docs › reports expected errors not received
    
        expect(observable$).toError()
    
        Observable completed without error
    
          60 |
          61 |              it("reports expected errors not received", async () => {
        > 62 |                      await expect(from([])).toError();
             |                                             ^
          63 |              });
          64 |      });
          65 | });
    
          at Object.<anonymous> (src/index.test.ts:62:27)
  • If an unexpected error is thrown, it is shown in the output:

      ● extending Jest › failing examples for docs › reports unexpected errors
    
        expect(observable$).not.toError()
    
        Expected value: not [Error: oh no!]
    
          56 |
          57 |              it("reports unexpected errors", async () => {
        > 58 |                      await expect(throwError(() => new Error("oh no!"))).not.toError();
             |                                                                              ^
          59 |              });
          60 |
          61 |              it("reports expected errors not received", async () => {
    
          at Object.<anonymous> (src/index.test.ts:58:60)
  • If the observable does not error within the timeout, the test times out (see example above)

.toErrorWith

.toErrorWith checks that the supplied observable errors with a matching message rather than completing:

it("asserts that the observable errors", async () => {
    await expect(throwError(() => new Error("oh no!"))).toErrorWith(/^oh no!$/);
});

Note that this is an asynchronous matcher that needs to be awaited or returned.

This matcher has the following failure cases:

  • If the observable completes without an error, that is shown explicitly:

      ● extending Jest › failing examples for docs › reports matching errors not received
    
        expect(observable$).toErrorWith(expected)
    
        Expected pattern: /whoops/
    
        Observable completed without error
    
          90 |
          91 |              it("reports matching errors not received", async () => {
        > 92 |                      await expect(from([])).toErrorWith(/whoops/);
             |                                             ^
          93 |              });
          94 |
          95 |              it("reports mismatched errors received", async () => {
    
          at Object.<anonymous> (src/index.test.ts:92:27)
  • If an unexpected error is thrown, it is shown in the output:

      ● extending Jest › failing examples for docs › reports mismatched errors received
    
        expect(observable$).toErrorWith(expected)
    
        Expected pattern: /whoops/
        Received message: "oh no!"
    
          94 |
          95 |              it("reports mismatched errors received", async () => {
      >   96 |                      await expect(throwError(() => new Error("oh no!"))).toErrorWith(/whoops/);
             |                                                                          ^
          97 |              });
          98 |
          99 |              it("reports matched errors unexpectedly received", async () => {
    
          at Object.<anonymous> (src/index.test.ts:96:56)
  • If an unexpected match is received it is shown:

      ● extending Jest › failing examples for docs › reports matched errors unexpectedly received
    
        expect(observable$).not.toErrorWith(expected)
    
        Expected pattern: not /oh no/
        Received message: "oh no!"
    
           98 |
           99 |             it("reports matched errors unexpectedly received", async () => {
        > 100 |                     await expect(throwError(() => new Error("oh no!"))).not.toErrorWith(/oh no/);
              |                                                                             ^
          101 |             });
          102 |     });
          103 | });
    
          at Object.<anonymous> (src/index.test.ts:100:60)

Version support

  • Jest: tested against v27, v28 and v29 (see peerDependencies field in package.json)
  • Node: tested against v14, v16 and v18 (see engines field in package.json)
  • RxJS: tested against v6 and v7 (see peerDependencies field in package.json)

Linting

If you're using the Jest plugin for ESLint and have jest/valid-expect enabled, you can configure it to understand that the matchers are asynchronous as follows:

{
  // ...
  "rules": {
    // ...
    "jest/valid-expect": [
      "error",
      {
        "asyncMatchers": [
          "toEmit",
          "toError",
          "toErrorWith"
        ]
      }
    ]
  }
}

Development

You can fork and clone this repository to work on it. Once you've cloned the code locally, install the dependencies with npm ci then check everything is installed and running correctly with npm run ship.

Scripts

The following convenience scripts are provided for development and can be run with npm run <script>:

  • build: Transpile the source code from src/ to lib/
  • e2e: Test the package at an E2E level using bin/e2e.sh
    • The script takes an argument specifying the version to download from NPM and test or local to test the current code (e.g. npm run e2e -- x.y.z)
    • When testing the local package, use the --build flag to rebuild and repack the package (i.e. npm run e2e -- local --build)
    • The version of Jest installed in the example package can be overridden from the default (v29) using the JEST_VERSION environment variable
    • The version of RxJS installed in the example package can be overridden from the default (v7) using the RXJS_VERSION environment variable
  • lint: Check the code style with ESLint
  • ship: Lint, then run low-level tests, then run high-level tests
  • test: Test the source code at a unit and integration level using Jest

Testing

There are three levels of testing:

  • E2E: the highest level is provided by actually using RxJeSt in an example package. The tests used here are in demo.js (which is copied into the example package and renamed by bin/e2e.sh).
  • Integration: index.test.js uses the matchers in an actual Jest context, but is still importing source code rather than using the transpiled package
  • Unit: the lowest level of tests are in src/matchers/<matcher>.test.ts. These can check more granular details of e.g. failing test messages by directly invoking the matcher functions with a context equivalent to what Jest provides as this (the context can be created with createContext from src/matchers/testUtils.ts).