Search code examples
angularunit-testingjasmine

Angular Testing - createSpyObj method not called


I have one Angular component and one service. In the component I have a method which calls one method of the service. At the component test I try to create a mock for the service, then when I call the method of the component I would like to check if the service method was called from the component.

The component:

export class TestComponent {

  constructor(private testService: TestService) {}

  edit(): void {
    this.testService.getCase('id').subscribe(console.log);
  }
}

The service:

@Injectable({
  providedIn: 'root'
})
export class TestService {

  constructor(
    private http: HttpClient,
  ) { }

  getCase(id: string): Observable<any> {
    return this.http.get<any>(`url`);
  }
}

And the test:

describe('TestComponent', () => {
  let component: TestComponent;
  let fixture: ComponentFixture<TestComponent>;
  const testServiceMock = jasmine.createSpyObj('TestService', ['getCase']);
  
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ TestComponent ],
      providers: [
        { provide: TestService, useValue: testServiceMock },
      ]
    })
      .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('expect service has been called', () => {
    spyOn(component, 'edit');
    component.edit();
    expect(component.edit).toHaveBeenCalledTimes(1);
    expect(testServiceMock.getCase).toHaveBeenCalled();
  });
});

This line is constantly failing:
expect(testServiceMock.getCase).toHaveBeenCalled();

TestComponent expect service has been called FAILED Error: Expected spy TestService.getCase to have been called.


Solution

  • You need to delegate calls to actual implementation:

    spyOn(component, 'edit').and.callThrough();
    

    https://jasmine.github.io/2.0/introduction#section-Spies:_%3Ccode%3Eand.callThrough%3C/code%3E