Error: Expected spy create to have been called

33,957

Solution 1

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();
  })
  ));

Solution 2

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');
});
Share:
33,957

Related videos on Youtube

Arjun Singh
Author by

Arjun Singh

MEAN Stack Developer. JavaScript

Updated on April 03, 2020

Comments

  • Arjun Singh
    Arjun Singh about 4 years

    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!

    • user2216584
      user2216584 almost 5 years
      Can you change your line showing error like this and try - expect(myService .create).toHaveBeenCalledTimes(1);
    • The Head Rush
      The Head Rush almost 5 years
      You need to either detectChanges or call done (after injecting it) after calling the method under test and before your expects.
    • Arjun Singh
      Arjun Singh almost 5 years
      Hello @user2216584, I have tried this expect(myService .create).toHaveBeenCalledTimes(1); but still getting the same error :(
    • Arjun Singh
      Arjun Singh almost 5 years
      Hi @TheHeadRush, fixture.detectChanges(); didn't worked as well.
    • user2216584
      user2216584 almost 5 years
      @ArjunSingh It appears that your component's else condition is not being executed. Put console.log in if and else condition and see what gets logs. By seeing your test case it appears that your component's this.profileForm is invalid and because of that your submitRegistrationForm method's else condition is not being executed. Are you sure that else condition of submitRegistrationForm is called? put logs and check.
    • Arjun Singh
      Arjun Singh almost 5 years
      @user2216584, No profileForm values are set and getting this.profileForm.invalid as false i.e else condition needs to be executed. Updated the test case.
  • Bidisha Das
    Bidisha Das over 2 years
    Thank you for this. It works wonder with form controls.