How to test if returned Observable is EMPTY
Asked Answered
B

3

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.

Bakker answered 23/2, 2021 at 11:28 Comment(3)
Is EMPTY undefined? Does expect(res).toBe(undefined) work?Quickly
@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)Bakker
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 EMPTYQuickly
R
14

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

Randers answered 26/2, 2021 at 0:19 Comment(0)
Q
3

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.

Quickly answered 23/2, 2021 at 12:17 Comment(2)
The same Error: Timeout is issued. I think since EMPTY doesn't emit anything, then the subscribe is never triggered.Bakker
@Lossan: Timeout should not happen in this case, coz, setTimeout will eventually call done(). And EMPTY doesn't emit, yes. But terminates. stackblitz.com/edit/rxjs-bhppxx?devtoolsheight=60Quickly
N
0

Testing for emptiness can be done by combining isEmpty with lastValueFrom in one line:

it('should return EMPTY when ...', async () => {
    expect(await lastValueFrom(effects.effect$.pipe(isEmpty())).toBeTruthy();
})

This avoids any callback functions like done and setTimeout.

Nissa answered 14/11, 2023 at 14:46 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.