简体   繁体   中英

Testing RxJS observable that tracks the last emitted value (no complete signal)?

I did some searching, but was unable to find a simple answer to my use-case. I apologize in advance if there already exists a sufficiently similar question on SO.

I have an observable, myObservable , that continuously streams a value from a store (ie it represents the state of the store). I want to test, with Jest, that my observable is able to correctly update when changes happen to the store.

// i.e. every time the value changes, an event is emitted by myObservable
myObservable.subscribe(x => console.log(x))

So what I really want to do is something like the following:

await myStore.set(0)
// insert here: check that `myObservable` stream is a 0
await myStore.set(5)
// insert here: check that `myObservable` stream is a 5

Basically I need a way to "tap" in to myObservable at any point in time to see what value was last emitted. Sorry if this is a bit of a n00b question.

I am not pretty sure if it's an efficient way. But you can try this out.

This code is in Jasmine, I hope it would be somewhat similar in Jest.

fit('Should test observable with store', fakeAsync(() => {
  const testData = [1, 2, 3, 4];
  let index = 0;

  myObservable.subscribe(t => {
    expect(t).toBe(testData[index]);
  });

  testData.forEach(td => {
    myStore.set(td)
    tick(100);
    index++;
  });
}));

This solution creates a subscription to receive expected values, perform assertion and end the test.

Though slightly long, it seems idiomatic to me and should be able to scale as your app's reactive needs grow.

import { from, Observable, of } from 'rxjs'
import { concatMap, finalize, take, tap, toArray } from 'rxjs/operators'

// sample "definitions" to make the example compile
// replace "myObservable", "myStore" with actual code for expected result
const myObservable: Observable<number> = of(123)
const myStore: {
  set: (number) => Promise
} = null as any

describe('my test', () => {
  it('is an example', done => {
    // configure observable to assert emitted values
    myObservable.pipe(
      // this subscription will complete after emitting 2 values
      take(2),
      // put all the values into a single array
      toArray(),
      // assert the values (that has been converted to array)
      tap(vals => expect(vals).toBe([0, 5]),
      // this will ensure the test does not 'hang' on observable error
      finalize(() => {
        // test will fail if assertion did not happen
        expect.assertions(1)
        done()
      })
    ).subscribe()

    // --- pick preferred way to execute - "set store value"
    // option 1: set 0 then set 5 (using observables)
    from(myStore.set(0)).pipe(
      concatMap(() => myStore.set(5))
    ).subscribe()

    // option 2: set 0 then set 5 (using promises)
    myStore.set(0).then(() =>
      myStore.set(5)
    )
  })
})

Good luck!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM