'Karma tests: Cancelling of Subscription in finalize does not work

I have this scenario: there is a service taking data from BE. Every call of this service (its method) is subscribed and this subscription is saved to Subscription object, so it can be unsubscribed at any time.

There is also a finalize operator to cancel the subscription when the service call and all its subsequences are done.

In 'real world' everything works fine - finalize works as expected - cancel subscription after everything is done, problem is testing part. If I expect the subscription to be null, the test fails, because the subscription is not cancelled, even if finalize was called (proved by debugging). And what is even more unclear to me, there is a flag isLoading, which is set before getting data and reset in finalize and this is reset both in real world and in tests.

// test.component.ts

currentRequestSubscription: Subscription;
isLoading: bool;

setData(): void {
  this.isLoading = true;
  this.currentRequestSubscription = this.dataService.getData().pipe(
    finalize(() => {      
      this.currentRequestSubscription.unsubscribe();
      this.currentRequestSubscription = null;
      this.isLoading = false;
    }
  ).subscribe((value) => {
    // process value
  });
}

// test.component.spec.ts

spyOn(dataService, 'getData').and.returnValue(of(new Data));

component.setData();
      
expect(component.currentRequestSubscription).toBe(null); // this fails
expect(component.isLoading).toBe(false);                 // this succeeds

So, what is behind this? Why is one variable reset in finalize truly reset and the other is not? Is there any way how to handle this correctly?



Solution 1:[1]

The setData is asynchronous method, and in your test case you invoke method and then immediately checking for the specific condition as of it is synchronous method.

use component.setData(false); with await

await component.setData(false);

expect(eleComponent.currentRequestSubscription).toBe(null); // this fails
expect(eleComponent.isLoading).toBeFalsy;                 // this succeeds

Note - If the above solution doesn't work, you place your expect within the setTimeOut or you can use timer for passage of time.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 random