Search code examples
angulartestingjasmine

angular jasmine testing an spy with different arguments


I am learning the basics of testing and I am using a chat I developed with Angular and Firebase.

I have a method to authenticate the user based on different providers. The provider´s name will be passed as argument. It will call another method on a service which will make the logic.

authentication() will be called when we push a button, that way the button to log with google will call authentication('google') , the button to log wih facebook will be authentication ('facebook') and so on.

login.component.ts

 authenticate(provider:String){

    
      this._chat.login(provider).then(()=>{
      }).catch((error)=>{
        console.log ("something went wrong with the authenticate method", error);
      });
 
    
  }

To do the test, I created an spy on that method and I am trying to recreate the different clicks. When I make something like

spyOn(component, 'authenticate').withArgs('google');
buttonElement.click();
expect(component.authenticate).toHaveBeenCalledWith('google');

But when I make another test with a different parameter:

spyOn(component, 'authenticate').withArgs('facebook');
buttonElement.click();
expect(component.authenticate).toHaveBeenCalledWith('facebook');

It throws an error, since it seems it calls the parameter it called the first time:

enter image description here

I have been investigating and tried to use the solution proposed here but it doesn´t work.

As you can see in the following code, I am resetting the spy inside the beforeEach().

How can I use different parameters each time I use the spy and make it work? What else could be I doing wrong?

This is the whole spec code.

login.component.spec.ts

import { ComponentFixture, TestBed } from '@angular/core/testing';

import { LoginComponent } from './login.component';
import { ChatService } from '../../services/chat-service/chat.service';
import { DebugElement } from '@angular/core';
import { AngularFireModule } from '@angular/fire/compat';
import { environment } from 'src/environments/environment';
import { RouterTestingModule } from '@angular/router/testing';

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;
  let debugElement: DebugElement;
  let _chat:ChatService;
  let buttonElement:HTMLButtonElement;
  let spy1:any; 
   
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ LoginComponent ],
      imports:[RouterTestingModule,
        AngularFireModule.initializeApp(environment.firebase),
      ],
      providers: [ChatService]
    })
    .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent);
    debugElement = fixture.debugElement;
    _chat=debugElement.injector.get(ChatService);
    component = fixture.componentInstance;
    buttonElement = fixture.debugElement.nativeElement.querySelector('.button-login');
   spy1=spyOn(component, 'authenticate');

   spy1.calls.reset();


    
  });

  it('should click google button and call authenticate method with google', () => {

    spy1.withArgs('google');
    buttonElement.click();
    expect(component.authenticate).toHaveBeenCalledWith('google');
   
  });

  it('should click facebook button and call authenticate method with facebook', () => {

 
    spy1.withArgs("facebook"); 
    buttonElement.click();
    expect(component.authenticate).toHaveBeenCalledWith('facebook');
   
  });


  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

Solution

  • I don't understand what is controlling authenticate to be called with google or facebook, I am assuming they are different buttons.

    If that is the case, you need new references to the specific button elements.

    it('should click google button and call authenticate method with google', () => {
    
        spy1.withArgs('google');
        // get the google button element
        const googleButton = fixture.debugElement.query(By.css('button#google')).nativeElement;
        googleButton.click();
        expect(component.authenticate).toHaveBeenCalledWith('google');
       
      });
    
      it('should click facebook button and call authenticate method with facebook', () => {
    
     
        spy1.withArgs("facebook"); 
        const facebookButton = fixture.debugElement.query(By.css('button#facebook')).nativeElement;
        facebookButton.click();
        expect(component.authenticate).toHaveBeenCalledWith('facebook');
       
      });
    

    Make sure each button has a unique selector (id="facebook", id="google") or else By.css('.button-login') will find the first element it finds in the HTML matching .button-login.