1

I have following test. It fails and appears that the spyOn is not mocking the service correctly or may be I don't understand it. I put a console in the component method and could see it when test runs, shouldn't the actual method be not called when I am spying on it? I thought may be it's due to api taking sometime, so tried fakeAsync, flush and tick etc. but none worked.

describe('AppComponent', () => {
  let service: any;
  let fixture: ComponentFixture<AppComponent>;
  let component: AppComponent;
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [RouterTestingModule, HttpClientTestingModule],
      declarations: [AppComponent],
      providers: [PatientdataService],
    }).compileComponents();

    service = TestBed.inject(PatientdataService);
    fixture = TestBed.createComponent(AppComponent);
    component = fixture.componentInstance;
  });

  it('should call getPatient from service', () => {      

    const dataSpy = spyOn(component, 'loadPatientData');
    const patientSpy = spyOn(service, 'getPatientValues').and.returnValue(of([]));
    const medSpy = spyOn(service, 'getMedicationValues').and.returnValue(of([]));

    component.getPatientDetails();

    expect(dataSpy).toHaveBeenCalledTimes(1);
    expect(patientSpy).toHaveBeenCalledTimes(1);
    expect(medSpy).toHaveBeenCalledTimes(1);
  }); 
});

Following is the component method it's trying to test -

getPatientDetails() {
    this.service.getPatientValues().subscribe({
      next: (data) => {
        this.loadPatientData(JSON.parse(data));    
        this.service.getMedicationValues().subscribe({
          next: (data) => {
            this.loadMedicationData(JSON.parse(data));    
            this.service.getConditionsValues().subscribe({
              next: (data) => {
              ...
              ...

This is the error I get -

Error: Expected spy loadPatientData to have been called once. It was called 0 times.
            at <Jasmine>
            at UserContext.<anonymous> (src/app/app.component.spec.ts:41:21)
            at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:372:1)
            at ProxyZoneSpec.onInvoke (node_modules/zone.js/fesm2015/zone-testing.js:287:1)
        Error: Expected spy getMedicationValues to have been called once. It was called 0 times.
            at <Jasmine>
            at UserContext.<anonymous> (src/app/app.component.spec.ts:43:20)
            at _ZoneDelegate.invoke (node_modules/zone.js/fesm2015/zone.js:372:1)
            at ProxyZoneSpec.onInvoke (node_modules/zone.js/fesm2015/zone-testing.js:287:1)
a p
  • 1,121
  • 6
  • 26
  • 51

1 Answers1

1

If you try to parse JSON that isn't valid you'll get runtime exception Unexpected end of JSON input, I suspect that's what's happening here

// You're returning of([])
// So data is [], which isn't valid 
// for JSON.parse
this.loadPatientData(JSON.parse(data))

If this is how your code should behave, and isn't a mistake, then try using of(JSON.stringify([]))

The reason the code is invoked is because you use returnValue for getPatientValues - if you don't use that then the function won't be invoked - but none of the other functions would be called after that either

Drenai
  • 11,315
  • 9
  • 48
  • 82
  • I do see that error and the problem is that the actual response from the backend is indeed a string with \ attached to all the keys and values, something like `"{\"resourceType\":\"Patient\"}"` and reasons unknown to me. Could you please help as why even after spyOn, actual code is executed? Can't we just mock so that it bypasses the whole that is updating data like `loadPatientData`. – a p Jun 15 '22 at 07:15
  • Okay, sure, will do. My question was though to understand as why the code is getting invoked. Upvoted. – a p Jun 15 '22 at 07:22
  • 1
    Oh right, I'll add to this answer – Drenai Jun 15 '22 at 07:25