Search code examples
angulartypescriptjasmineangular-test

Jasmine Unit Case for component method which has subscription returns undefined and always fails


My component has the following method:

get(): void {
  this.service.get().subscribe((res) => {
    this.response = res;
  });
}

I have the following test case for it:

it('should get content ', () => {
  const currentObject = {};

  spyOn(service, 'get').and.returnValue(of(currentObject));

  component.get();

  fixture.detectChanges();
  expect(component.response).toEqual(currentObject);

});

The result is always:

Expected undefined to equal Object({ }).

There are plenty of similar questions regarding this here but for someone reason none of those work for me.


Solution

  • I am thinking this could be due to the asynchronous nature of the code where .subscribe happens after your expect.

    Try this to debug:

    get(): void {
      this.service.get().subscribe((res) => {
        // !! add this log and ensure you see it first
        console.log('[get] This should happen first');
        this.response = res;
      });
    }
    
    // Test
    it('should get content ', () => {
      const currentObject = {};
    
      spyOn(service, 'get').and.returnValue(of(currentObject));
    
      component.get();
    
      fixture.detectChanges();
      // !! add this log and ensure you see it last
      console.log('[test] This should happen last');
      expect(component.response).toEqual(currentObject);
    
    });
    

    Make sure you see This should happen first before This should happen last.

    I think a potential way to fix it is maybe using fakeAsync/tick.

    // wrap callback function in fakeAsync
    it('should get content ', fakeAsync(() => {
      const currentObject = {};
    
      spyOn(service, 'get').and.returnValue(of(currentObject));
    
      component.get();
    
      fixture.detectChanges();
      // call tick() here to ensure the asynchronous subscribe runs before the expect
      tick();
      expect(component.response).toEqual(currentObject);
    
    }));