Arjun Singh
Arjun Singh

Reputation: 132

Error: Expected spy create to have been called

I'm writing unit test cases in angular 7 for a Component with async service and getting this error:

Error: Expected spy create to have been called once. It was called 0 times.

Here is my Component:

export class RegistrationComponent implements OnInit {
    
   submitRegistrationForm() {
        if (this.profileForm.invalid) {
          this.validateAllFields(this.profileForm);
        } else {
          // send a http request to save this data
          this.guestUserService.create(this.profileForm.value).subscribe(
            result => {
              if (result) {
                console.log('result', result);
                this.router.navigate(['/login']);
              }
            },
            error => {
              console.log('error', error);
            });
        }
  }

Unit test case:

  describe('RegistrationComponent', () => {
      let component: RegistrationComponent;
      let fixture: ComponentFixture<RegistrationComponent>;
      let myService;
      let mySpy;
    
      beforeEach(async(() => {
    
        TestBed.configureTestingModule({
          declarations: [RegistrationComponent],
          imports: [ ],
          providers: [
            { provide: GuestUserService, useValue: new MyServiceStub() }]
        })
          .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(RegistrationComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });

 it('should submit Registration Form', async(inject([Router], (router) => {
    myService = TestBed.get(GuestUserService);
    mySpy = spyOn(myService, 'create');
    spyOn(router, 'navigate');
    spyOn(component, 'submitRegistrationForm');


component.profileForm.controls['firstName'].setValue('Arjun');
    component.profileForm.controls['lastName'].setValue('Singh');
    component.profileForm.controls['password'].setValue('12345678');
    component.profileForm.controls['confirmPassword'].setValue('12345678');
    component.submitRegistrationForm();

    expect(component.profileForm.invalid).toBe(false);

    expect(component.submitRegistrationForm).toHaveBeenCalled();

    expect(myService).toBeDefined();
    expect(mySpy).toBeDefined();
    expect(mySpy).toHaveBeenCalledTimes(1); // Getting error is this
    expect(router.navigate).toHaveBeenCalled();
  })
  ));

I tried to move the spy deceleration in beforeEach but still its giving the same error.

how to fix this error?

Thanks!

Upvotes: 4

Views: 72758

Answers (2)

Vishal Hasnani
Vishal Hasnani

Reputation: 728

The spyOn will help you to setup how the function should react when it's being called upon in your tests. Basically it's Jasmines way of creating mocks.

In your case you have defined what the test should do when the service function is being called, which is callThrough. The problem is that you also need to act on the service function (or the scope function which calls your service method) in order to trigger the spyOn which will callThrough.

it('load snapshot',function(){

  //setup
  spyOn(MyService, 'loadSomething').and.callThrough(); //statement 2

  //act

  //either call the scope function which uses the service 
  //$scope.yourServiceCallFunction();

  //or call the service function directly
  MyService.loadSomething(1); //this will callThrough

});

Here's an simple test where we will mock the response of the spyOn to a string

it('test loadSomething',function(){

  //setup
  spyOn(MyService, 'loadSomething').and.returnValue('Mocked');

  //act
  var val = MyService.loadSomething(1);

  //check
  expect(val).toEqual('Mocked');
});

Upvotes: 9

user11665152
user11665152

Reputation:

Expected spy create to have been called is not an Error but a failed test.

This is happening because you haven't use callThrough(); on your spyOn either.

 it('should submit Registration Form', async(inject([Router], (router) => {

    myService = TestBed.get(GuestUserService);
    mySpy = spyOn(myService, 'create').and.callThrough(); //callThrough()

    spyOn(router, 'navigate');

    spyOn(component, 'submitRegistrationForm').and.callThrough(); //callThrough()


    component.submitRegistrationForm();

    expect(component.profileForm.invalid).toBe(false);

    expect(component.submitRegistrationForm).toHaveBeenCalled();

    expect(myService).toBeDefined();
    expect(mySpy).toBeDefined();
    expect(mySpy).toHaveBeenCalledTimes(1); 
    expect(router.navigate).toHaveBeenCalled();
  })
  ));

Upvotes: 23

Related Questions