2

Suppose i have a service named testService with a function getData in it. Also i have a component ( say A ) into which the service is injected.

export class A implements OnInit,OnDestroy{
    saveObj;

    constructor(public service:testService){

    }

    ngOnDestroy(){
      if(this.saveObj) this.saveObj.unsubscribe();
    }

    ngOnInit(){
        this.saveObj = this.service.getData.subscribe(res => {
            this.func(res);
        },
        err => {
            console.log("Error Occured");
            this.saveObj.unsubscribe();
        });
    }

    private func(result: any){
        // Some code
    }
}

Now i am doing unit testing for this component. The problem is in some cases , it throws an error:

Uncaught TypeError: _this.saveObj.unsubscribe is not a function thrown

Code snippet of spec.ts:

// testServiceStub is just a mock of testService. 

beforeEach(async(()=>{
    testServiceStub = jasmine.createSpyObj(['getData']);

    TestBed.configureTestingModule({
        declarations : [A],
        schemas : [NO_ERRORS_SCHEMA],
        providers : [
            { provide : testService, useValue: testServiceStub }
        ]
    }).compileComponents();
}))

beforeEach(async(()=>{
    fixture = TestBed.createComponent(A);
    component = fixture.componentInstance;
}))

it('checks whether error is handled or not',()=>{
    spyOn(console,'log');
    testServiceStub.getData.and.returnValue(throwError({status:404})); 
    fixture.detectChanges();
    expect(console.log).toHaveBeenCalled(); // shows the TypeError
})


it('checks whether value is handled or not',()=>{
    testServiceStub.getData.and.returnValue(of(mockData)); // some mock data
    fixture.detectChanges();
    expect(component.func).toHaveBeenCalled();  // also shows the TypeError
})

I also referred this link unsubscribe is not a function on an observable . But the problem is it also works in some cases and no error is shown.

Please help me figure out the reason and possible scenarios.

UPD: Added onDestroy lifecycle hook

KL_KISNE_DEKHA_HAI
  • 649
  • 11
  • 26
  • Please do null check before you unsubscribe the subscriptions. And also this can be done within `ngOnDestroy` lifecycle method – Amit Chigadani May 11 '20 at 09:14
  • Hello Amit, i added it still the error remains. Can you tell me why this error comes at all? and also when it would work without fail? – KL_KISNE_DEKHA_HAI May 11 '20 at 09:20
  • @RahulChowdhury I already gave an answer about Subscriptions and how to properly unsubscribe from observables on destroy. Please try my explained approach with Subject and takeUntil here --> https://stackoverflow.com/questions/57355066/how-to-implement-behavior-subject-using-service-in-angular-8/57355485#57355485 – sagat May 11 '20 at 14:26
  • Tell me if it worked for you. – sagat May 11 '20 at 14:26
  • @RahulChowdhury As mentioned in the above comment, you are trying to access the subscription variable before it is assigned with the `Subscription` object. For the first time, it would give you error, hence it is recommended to add null check. In your case it safe to kill the subscriptions in `ngOnDestroy` hook. – Amit Chigadani May 11 '20 at 17:56
  • Also you should be adding null check within error callback if you still wish to use that. But I would say it is not required to unsubscribe within error callback. – Amit Chigadani May 11 '20 at 18:06
  • Can you explain a bit more "you are trying to access the subscription variable before it is assigned with the Subscription object". Also check if my final code is the way you wanted it or not? Also please help me to improve my answer if there are any flaws. – KL_KISNE_DEKHA_HAI May 11 '20 at 19:10
  • Is this working? – Gourav Garg May 12 '20 at 05:32
  • Yes it is. But I wanted to know what @Amit meant by that line... that's all. – KL_KISNE_DEKHA_HAI May 12 '20 at 06:23
  • 1
    @RahulChowdhury I have added a small [demo](https://stackblitz.com/edit/sub-destroy-within-self?file=src/app/app.component.ts). Hope that should clear your doubts. Check the console logs where the first sub is undefined. – Amit Chigadani May 12 '20 at 06:35
  • 2
    Yes thank you. It cleared what you said. Mind checking the code which i wrote in the answer? is it fine? – KL_KISNE_DEKHA_HAI May 12 '20 at 07:45
  • Hello @Amit, can you help me with this? https://stackoverflow.com/questions/62095430/callback-and-testing-highcharts – KL_KISNE_DEKHA_HAI May 30 '20 at 09:10

1 Answers1

2

As suggested by @Amit Chigadani

export class A implements OnInit,OnDestroy{
    saveObj: Subscription ;

    constructor(public service:testService){

    }

    ngOnDestroy(){
      if(this.saveObj) 
             this.saveObj.unsubscribe();
    }

    ngOnInit(){
        this.saveObj = this.service.getData.subscribe(res => {
            this.func(res);
        },
        err => {
            console.log("Error Occured");
        });
    }

    private func(result: any){
        // Some code
    }
}
KL_KISNE_DEKHA_HAI
  • 649
  • 11
  • 26