10

Let's say I have an Angular Component which defines an Observable myObs$ as one of its properties.

In one test, given certain conditions, I want to test that myObs$ does not notify. In the logic there are some delays involved, so the test must be asynchronous.

I am using Jasmine.

So far I have been able to craft this solution:

it('async test', done => {
    let dataEmitted;
    myObs$
    .pipe(
      tap(data => dataEmitted = data),
    )
    .subscribe();
    setTimeout(() => {
      if (dataEmitted) {
        done.fail('should not emit');
      } else {
        done();
      }
    }, 1000);
  });

But I am far from happy with it. I have to rely on setTimeout to perform the checks and call the done function.

Any suggestions on how to perform such tests properly? Synchronous solutions do not work since there is intrinsic asynchronicity in the logic.

SuleymanSah
  • 17,153
  • 5
  • 33
  • 54
Picci
  • 16,775
  • 13
  • 70
  • 113

2 Answers2

20

If it's asynchronous logic that based on setTimeout/debounceTime and so forth, you can use fakeAsync() function to test it, this function will substitute all these asynchronous operations with synchronous ones, so it will be possible to test your logic since it's synchronous. Also you can use tick() to skip VM turns (and it happens also synchronously!). Using this solution you will have nice and clean, fast and reliable unit tests.

Code example

it('asynch test', fakeAsync(() => {
    let dataEmitted;
    myObs$.subscribe(data => dataEmitted = data);

    tick(1000);
    
    expect(dataEmitted).toBeUndefined();
}));

I suggest you also to check negative scenario, for example tick(2000) and check if it emits value. Hope that helps.

Amir Arbabian
  • 3,419
  • 1
  • 6
  • 12
1

Assuming that the Observable eventually completes, this can also be done with the conventional it function by using done():

it(
  'async test',
  (done: DoneFn) => {
    let emitted = false;
    myObs$
    .subscribe({
      next: () => emitted = true;
      complete: () => {
        expect(emitted).toBeFalse();
        done();
      }
    });
  }
);
Joseph Zabinski
  • 693
  • 4
  • 23