How to unit test unsubscribe function in angular How to unit test unsubscribe function in angular angular angular

How to unit test unsubscribe function in angular


I had exactly the same problem, here's my solution:

component.ts:

private subscription: Subscription;//...ngOnInit(): void {    this.subscription = this.route.paramMap.subscribe((paramMap: ParamMap) => {        // ...    });}ngOnDestroy(): void {    this.subscription.unsubscribe();}

component.spec.ts:

let dataMock;let storeMock: Store;let storeStub: {    select: Function,    dispatch: Function};let paramMapMock: ParamMap;let paramMapSubscription: Subscription;let paramMapObservable: Observable<ParamMap>;let activatedRouteMock: ActivatedRoute;let activatedRouteStub: {    paramMap: Observable<ParamMap>;};beforeEach(async(() => {    dataMock = { /* some test data */ };    storeStub = {        select: (fn: Function) => of((id: string) => dataMock),        dispatch: jasmine.createSpy('dispatch')    };    paramMapMock = {        keys: [],        has: jasmine.createSpy('has'),        get: jasmine.createSpy('get'),        getAll: jasmine.createSpy('getAll')    };    paramMapSubscription = new Subscription();    paramMapObservable = new Observable<ParamMap>();    spyOn(paramMapSubscription, 'unsubscribe').and.callThrough();    spyOn(paramMapObservable, 'subscribe').and.callFake((fn: Function): Subscription => {        fn(paramMapMock);        return paramMapSubscription;    });    activatedRouteStub = {        paramMap: paramMapObservable    };    TestBed.configureTestingModule({       // ...       providers: [           { provide: Store, useValue: storeStub },           { provide: ActivatedRoute, useValue: activatedRouteStub }       ]    })    .compileComponents();}));// ...it('unsubscribes when destoryed', () => {    fixture.detectChanges();    component.ngOnDestroy();    expect(paramMapSubscription.unsubscribe).toHaveBeenCalled();});

This works for me, I hope it will for you too !


Does this look good to you ?

component.mySubscription = new Subscription();spyOn(component.mySubscription, 'unsubscribe');component.ngOnDestroy();expect(component.mySubscription.unsubscribe).toHaveBeenCalledTimes(1);


I figure out a way to make it work.

First of all, I do not create a subscription instance for each subscription, I usually use only one instance of subscription and add into as many subscriptions I need by using me method 'add' that implements a teardownLogic and allows child subscriptions.

private subscriptions: Subscription; //...ngOnInit(): void {  this.mySubscription.add(    this.store      .select(mySelector)      .subscribe((value: any) => console.log(value))  );}ngOnDestroy(): void {  this.subscriptions.unsubscribe();}

By doing that, in my tests I can rely on the Subscriptions prototype and detects theunsubscribe method calls. In that case after I call the ngOnDestroy.

const spy = spyOn(Subscription.prototype, 'unsubscribe');component.ngOnDestroy();expect(spy).toHaveBeenCalledTimes(1);