6

I have an effect that returns an EMPTY Observable in one case. I am trying to test this case, but I cant seem to figure out how to test EMPTY Observable? My code is as follows:

The effect:

   effect$ = createEffect(() =>
    this.actions$.pipe(
      ofType(someAction),
      mergeMap(([action]) => {
        if (someCondition) {
          return EMPTY <-- this is what I am trying to test
        }
        return someServiceCall.pipe(
          map((offers) => //dispatch some action,
          catchError((error: string) => // dispatch another action),
        )
      }),
    ),
  )

This is my unit test attempt, but it fails with

Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL).

Take into consideration that the condition is already fulfilled in the test:

  it('should return EMPTY when ...', (done) => {
    actions$ = of(someAction)
    effects.effect$.subscribe((res) => {
      expect(res).toEqual(never)
      done()
    })
  })

I can make it work if the return is of(null) instead of EMPTY. But I would really like to know how to test this case.

Lossan
  • 411
  • 1
  • 8
  • 16
  • Is `EMPTY` `undefined`? Does `expect(res).toBe(undefined)` work? – Ashish Ranjan Feb 23 '21 at 11:34
  • @AshishRanjan `EMPTY` is `of(never)`. When trying your suggestion it also fails with `Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)` – Lossan Feb 23 '21 at 11:40
  • I was reading about EMPTY, NEVER, so they do not emit anything at all. EMPTY terminates and NEVER doesn't even terminate. This means, maybe you can check the complete callback in case you are using EMPTY – Ashish Ranjan Feb 23 '21 at 11:57

2 Answers2

10

It seems that we have a specific operation in RxJs that checks if an observable is empty. The operation is isEmpty()

it('should return EMPTY when ...', (done) => {
    actions$ = of(someAction)
    effects.effect$.pipe(isEmpty()).subscribe( (res) => {
                                               expect(res).toEqual(true)
                                               done()
                                              });

res will be true only if observable does return with empty

Panagiotis Bougioukos
  • 15,955
  • 2
  • 30
  • 47
2

EMPTY doesn't emit anything, but terminates. So, no success callback would be called but the complete callback would be triggered for it.

If it suits your testing, maybe you can check the complete callback.

Pardon my less understanding of tests, but here I am unable to put appropriate assert statement. So, I followed this approach, please tweak, change as required, only intention is to check if complete cb is called.

 it('should return EMPTY when ...', (done) => {
    actions$ = of(someAction)
    const success = () => {};
    const error = () => {};
    const complete = () => {};

    effects.getShopOffersInTimeRange$.subscribe(success, error, complete);

    setTimeout(() => {
      expect(complete).toHaveBeenCalled();
      done();
    });
  });

Have not tested the code, hope it works.

Ashish Ranjan
  • 12,760
  • 5
  • 27
  • 51
  • The same `Error: Timeout` is issued. I think since `EMPTY` doesn't emit anything, then the `subscribe` is never triggered. – Lossan Feb 23 '21 at 12:43
  • @Lossan: Timeout should not happen in this case, coz, setTimeout will eventually call `done()`. And EMPTY doesn't emit, yes. But terminates. https://stackblitz.com/edit/rxjs-bhppxx?devtoolsheight=60 – Ashish Ranjan Feb 23 '21 at 13:28