Skip to content

Instantly share code, notes, and snippets.

@jmcdo29
Last active September 20, 2024 09:28
Show Gist options
  • Save jmcdo29/f9d4d3effc2d55996341ce18fe0cb6d3 to your computer and use it in GitHub Desktop.
Save jmcdo29/f9d4d3effc2d55996341ce18fe0cb6d3 to your computer and use it in GitHub Desktop.
Testing Observables with Jest

I've run into trouble in the past with testing observables, so I figured I would make myself a gist to help myself remember, and to help others who find it.

Observables are rather tricky to test in general as they are made to be asynchronous and act like a stream, and up until recently it was acceptable to pass a next, error, and complete callback function, but now that method is bieng deprecated in favor of Observers. Fear not! An Observer is just like the three callbacks rolled into a signle object, plus other fields you would like to add :).

Say that we have the following Observable

const numbersArray = from([1,2,3,4,5]);

If we were to subscribe to this observable with a simple subscription and console.log

numbersArray.subscribe(value => console.log(value)).unsubscribe();

each value we would get the output

1
2
3
4
5

Now this is great and all, but we could instead give the subscribe function an observer like the following:

const numberObserver = {
  sum: 0
  next(value) {
    this.sum += value;
  },
  error(error) {
    throw error
  },
  complete() {
    console.log(this.sum);
  }
};

Now when we subscribe

numbersArray.subscribe(numberObserver).unsubscribe();

we get the sum of the values as the output

15

This is great to see how the Observer works and how to easily take advantage of the object. Now in a testing situation, like with Jest, you will want to call a callback function in your complete method to tell Jest that the test has finished. To still allow me to use pre-made observers, I create a factory-esque function that takes in the callback as a parameter. The function would look something like this:

const myObserver = (done) => {
  next(value) {
    //usually run your asserts here on single objects
  },
  error(error) {
    // throw the error so jest will fail
    throw error;
  },
  complete() {
    // call the callback to signify that the test is compelte
    done();
  }

If you are testing for an error specifically you can use the following as well:

const myErrorObserver = (done, errorObject) => {
  next(value) {
    throw new Error('Expected no value but got ' + value + ' instead.');
  },
  error(error) {
    expect(error).toEqual(errorObject);
  },
  complete() {
    done();
  }
};

You can always add more to the creation function to make your observers even more powerful while testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment