angulartypescriptjasminekarma-runner

Unit test failing: How do I properly select and click a components button


I have a unit test here:

fit('should call getImageByID upon submit when a search id is present', () => {
    spyOn(component, 'getImageById');
    component.searchId = '1';
    submit = fixture.debugElement.query(By.css('#getimagebyid')).nativeElement;
    submit.click();
    expect(component.getImageById).toHaveBeenCalled();
  });

The unit test is failing as the expect is not met (The method is not being executed), what am I missing? Here is the component method not being triggered:

getImageById() {
        this.imageAPIService.getImage(this.searchId).subscribe(res => {
            this.response.id = (res as any).id;
            this.response.image = (res as any).image;
        });
    }

and the html for the component:

<h4>Browse Images</h4>
<div class="row">
    <img *ngIf="response.id != null" [src]="response.image[0].url" height="200">
</div>
<div class="row">
    <input [(ngModel)]="searchId" type="text">
    <button class="btn btn-block btn-primary" id="getimagebyid" [disabled]="!searchId" (click)="getImageById(searchId)">Search</button>
</div>

Solution

  • You are almost there, but you will need to wait for the click event to be processed before checking if the method has been called.

    1) The most direct way to do it is to call detectChanges() to explicitly activate change detection.

    it('clicking on settings icon will trigger openModal method', () => {
      spyOn(component, 'getImageById');
      component.searchId = '1';
      submit = fixture.debugElement.query(By.css('#getimagebyid')).nativeElement;
      submit.click();
      fixture.detectChanges();
      expect(component.getImageById).toHaveBeenCalled();
      });
    

    2) Alternatively, you may use automatic change detection on your .spec file.

     import { ComponentFixtureAutoDetect, . . . . } from '@angular/core/testing';
    .
    .
    TestBed.configureTestingModule({
      declarations: [ BannerComponent ],
      providers: [
        { provide: ComponentFixtureAutoDetect, useValue: true }
      ]
    });
    

    3) Handle it by using the async() functionality to handle the asynchronous button clicking event. This is followed by calling .whenStable(), which returns the promise.

    import { async, . . . . } from '@angular/core/testing';
    .
    .
    it('clicking on settings icon will trigger openModal method', async(() => {
      spyOn(component, 'getImageById');
      component.searchId = '1';
      submit = fixture.debugElement.query(By.css('#getimagebyid')).nativeElement;
      submit.click();
    
      fixture.whenStable().then(() => {
        expect(component.getImageById).toHaveBeenCalled();
      });
    }));