1

I am writing unit test for my Angular 6 project. However, I encounter a problem. I want to test a button with click function called, but the test file always shows me this error.

The following are my code:

HTML:

<div>
 <button (click)="onButtonClick(1)"><button>
 <button (click)="onButtonClick(2)"><button>
 <button (click)="onButtonClick(3)"><button>
</div>

comp.ts:

onButtonClick(key: number) {
  do something
}

spec.ts

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

import { PanelButtonsComponent } from './panel-buttons.component';
import { By } from "@angular/platform-browser";

describe('PanelButtonsComponent', () => {
let component: PanelButtonsComponent;
let fixture: ComponentFixture<PanelButtonsComponent>;

beforeEach(async(() => {
  TestBed.configureTestingModule({
    declarations: [PanelButtonsComponent]
  })
    .compileComponents();
}));

beforeEach(() => {
  fixture = TestBed.createComponent(PanelButtonsComponent);
  component = fixture.componentInstance;
  fixture.detectChanges();
});



it("should call onButtonClick ", fakeAsync(() => {
  const onClickMock = spyOn(component, 'onButtonClick');

 fixture.debugElement.query(By.css('button')).triggerEventHandler('click', null);
  expect(onClickMock).toHaveBeenCalled();
}));


});

Test Result:

Expected spy onButtonClick to have been called.

Any suggestion to correct it? Thank you

Update

I have refer another article, and follow the code:

it('should', async(() => {
  spyOn(component, 'onButtonClick');

  let button = 
  fixture.debugElement.nativeElement.querySelector('button');
  button.click();

  fixture.whenStable().then(() => {
    expect(component.onButtonClick).toHaveBeenCalled();
  })
}));

The test case can not pass too.

UPDATE 2:

In my html, there are two kind of click function will be called, so this will cause the error

<div>
 <button (click)="onButtonClick(1)"><button>
 <button (click)="onButtonClick(2)"><button>
 <button (click)="onButtonClick(3)"><button>
 <button (click)="onResetClick()"><button>
</div>
Raymond Yeh
  • 255
  • 2
  • 6
  • 23

1 Answers1

1

I think this is the solution for my question.

At the beginning, there are different kind of functions will be called after click button.

<div>
 <button (click)="onButtonClick(1)"><button>
 <button (click)="onButtonClick(2)"><button>
 <button (click)="onButtonClick(3)"><button>
 <button (click)="onResetClick()"><button>

Because of this, the testing will cause error.

it("should call onButtonClick ", fakeAsync(() => {
  const onClickMock = spyOn(component, 'onButtonClick');

 fixture.debugElement.query(By.css('button')).triggerEventHandler('click', null);
  expect(onClickMock).toHaveBeenCalled();
}));

Expected spy onButtonClick to have been called.


So, the correct way to pass the testing should written like following:

Add class name to HTML

<div>
 <button (click)="onButtonClick(1)" class="normalBtn"><button>
 <button (click)="onButtonClick(2)" class="normalBtn"><button>
 <button (click)="onButtonClick(3)" class="normalBtn"><button>
 <button (click)="onResetClick()" class="restBtn"><button>
</div>

And then, modify the test case:

it('should call onButtonClick', fakeAsync(() => {
    fixture.detectChanges();
    spyOn(component, 'onButtonClick');
    let btn = fixture.debugElement.queryAll(By.css('.normalBtn'));
    for (let i = 0; i < btn.length; i++) {
      btn[i].triggerEventHandler('click', null);
    }

    tick(); // simulates the passage of time until all pending asynchronous activities finish
    fixture.detectChanges();
    expect(component.onButtonClick).toHaveBeenCalled();
  }));

  it("should call onResetClick ", fakeAsync(() => {
    fixture.detectChanges();
    spyOn(component, 'onResetClick');
    let btn = fixture.debugElement.query(By.css('.resetBtn'));
    btn.triggerEventHandler('click', null);
    tick(); // simulates the passage of time until all pending asynchronous activities finish
    fixture.detectChanges();
    expect(component.onResetClick).toHaveBeenCalled();
  }));
Raymond Yeh
  • 255
  • 2
  • 6
  • 23