Angular Test Button Click

By Arvind Rai, August 01, 2020
This page will walk through Angular unit test example for button click. For click event we can use triggerEventHandler method of Angular DebugElement class. We can also call native JavaScript click method of button. On click of button, we call a component method and it is possible that our component method has other dependencies to execute. So to test that method, we should use Jasmine spyOn to create a stub for the component method. To create asynchronous test function, we can use Angular async or fakeAsync method.
Now let us discuss the Angular test button click step-by-step with complete example.

1. Technologies Used

Find the technologies being used in our example.
1. Angular 10.0.0
2. Node.js 12.5.0
3. Jasmine Core 3.5.0
4. Karma 5.0.9

2. DebugElement.triggerEventHandler()

The triggerEventHandler can raise any data-bound event by its event name. Find the method syntax from Angular doc.
triggerEventHandler(eventName: string, eventObj: any): void 
The first argument is the event name to trigger and the second argument is the event object passed to handler.
Find the sample code.
const buttonElement = fixture.debugElement.query(By.css('.send-button'));
buttonElement.triggerEventHandler('click', null); 

3. Button Click Test for Property Binding

For button click test we have created a component that have three button.
person.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-person',
  template: `
      <button (click)="setName()" class="set-button">Set</button>
      <p>{{personName}}</p>

      <button (click)="sendData()" class="send-button">Send</button>

      <button (click)="editPerson(101)" class="edit-button">Edit</button>
  `
})
export class PersonComponent {
  personName: string;
  setName() {
    this.personName = 'Mahesh';
  }  
  sendData() {
    console.log('---sendData---');
    //Call Service to send data over HTTP
  }
  editPerson(id: number) {
    console.log('---editPerson---', id);
    //Call Service to send data over HTTP
  }  
} 
We are creating three test scenarios.
1. On click of Set button, we are calling a function that sets a value to a component property. We will test that button is clicked and value is set to property and bound to HTML.
2. On click of Send button, we are calling a function. We will test that function is called.
3. On click of Edit button, we are calling a function with arguments. We will test that function is called.

Here we will create unit test for case 1 i.e. on click of Set button, we are calling a function that sets a value to a component property.

person.component.spec.ts
import { ComponentFixture, TestBed, async } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { PersonComponent } from './person.component';

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

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [PersonComponent]
    });
    fixture = TestBed.createComponent(PersonComponent);
    component = fixture.componentInstance;
  });

  it('should click Set button', async(() => {
    fixture.detectChanges();
    let buttonElement = fixture.debugElement.query(By.css('.set-button'));
    let p = fixture.debugElement.nativeElement.querySelector('p');

    buttonElement.triggerEventHandler('click', null);
    fixture.detectChanges();

    fixture.whenStable().then(() => {
      expect(component.personName).toBe('Mahesh');
      expect(p.textContent).toBe('Mahesh');
    });
  }));
}); 
async: The async is the Angular testing API to create asynchronous test function which will automatically complete when all asynchronous calls within this test function are done.
whenStable: The whenStable is the method of ComponentFixture. The whenStable gives Promise that resolves when the fixture is stable.
detectChanges: The detectChanges triggers a change detection cycle for the component.

In the above code to trigger click event, we can also call native element click method with following code changes.
let buttonElement = fixture.debugElement.nativeElement.querySelector('.set-button');
buttonElement.click(); 
Find the test function.
it('should click Set button', async(() => {
  fixture.detectChanges();
  let buttonElement = fixture.debugElement.nativeElement.querySelector('.set-button');
  let p = fixture.debugElement.nativeElement.querySelector('p');

  buttonElement.click();
  fixture.detectChanges();

  fixture.whenStable().then(() => {
    expect(component.personName).toBe('Mahesh');
    expect(p.textContent).toBe('Mahesh');
  });
})); 

4. Jasmine spyOn()

The spyOn is a Jasmine API that spies the given function of given object. The spyOn accepts two parameters as following.
spyOn(someObj, 'functionName'); 
When we call the given function, it will not actually run.
someObj.functionName(); 
The functionName() will not run in real means. Using spyOn for the functions are useful where our functions have dependencies to execute, such as calling HTTP request. We can bypass these dependencies and test our method to be called.
If we want to pass some arguments and return value we can do as following.
spyOn(someObj, 'functionName').withArgs(10, 20, 30).and.returnValue(50);
someObj.functionName(10, 20, 30); // returns 50 
If we want to log on console or write other code for fake execution, we can write spyOn as following.
spyOn(someObj, 'functionName').and.callFake(function(){
   console.log('functionName called.');
   return 'result';
}); 

5. Button Click Test to Call Function using async

Here we will write a test case for Send button on click of which the sendData() method of component will be called. We will use spyOn for sendData() method so that it should not be called in real but as a stub. Jasmine handles spying on the method and later by calling toHaveBeenCalled() we test if it is called or not on button click. The toHaveBeenCalled() can only be called on spy object. Here we use async and whenStable() function.
it('should click Send button with async', async(() => {
  let buttonElement = fixture.debugElement.query(By.css('.send-button'));
    
  spyOn(component, 'sendData');
  //Trigger click event after spyOn
  buttonElement.triggerEventHandler('click', null);

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

6. Button Click Test to Call Function using fakeAsync

The fakeAsync is the Angular testing API that wraps a test function in a fake asynchronous test zone. The tick() simulates the asynchronous passage of time.
Find the button click test code to call a component method.
it('should click Send button with fakeAsync', fakeAsync(() => {
  let buttonElement = fixture.debugElement.query(By.css('.send-button'));
    
  spyOn(component, 'sendData');
  //Trigger click event after spyOn
  buttonElement.triggerEventHandler('click', null);
    
  tick();
  expect(component.sendData).toHaveBeenCalled();
})); 

Now we will test Edit button of our component. On click of Edit button, we are calling a function with arguments. We will test that function is called.
it('should click Edit button', fakeAsync(() => {
  let buttonElement = fixture.debugElement.query(By.css('.edit-button'));
    
  spyOn(component, 'editPerson');
  //Trigger click event after spyOn
  buttonElement.triggerEventHandler('click', null);
    
  tick();
  expect(component.editPerson).toHaveBeenCalled();
})); 

7. Complete Test Example

Find the complete code of our unit test in our demo application.
person.component.spec.ts
import { ComponentFixture, TestBed, async, fakeAsync, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { PersonComponent } from './person.component';

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

  beforeEach(() => {
    TestBed.configureTestingModule({
      declarations: [PersonComponent]
    });
    fixture = TestBed.createComponent(PersonComponent);
    component = fixture.componentInstance;
  });

  it('should click Set button', async(() => {
    fixture.detectChanges();
    let buttonElement = fixture.debugElement.query(By.css('.set-button'));
    let p = fixture.debugElement.nativeElement.querySelector('p');

    buttonElement.triggerEventHandler('click', null);
    fixture.detectChanges();

    fixture.whenStable().then(() => {
      expect(component.personName).toBe('Mahesh');
      expect(p.textContent).toBe('Mahesh');
    });
  }));

  it('should click Send button with async', async(() => {
    let buttonElement = fixture.debugElement.query(By.css('.send-button'));
    
    spyOn(component, 'sendData');
    //Trigger click event after spyOn
    buttonElement.triggerEventHandler('click', null);

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

  it('should click Send button with fakeAsync', fakeAsync(() => {
    let buttonElement = fixture.debugElement.query(By.css('.send-button'));
    
    spyOn(component, 'sendData');
    //Trigger click event after spyOn
    buttonElement.triggerEventHandler('click', null);
    
    tick();
    expect(component.sendData).toHaveBeenCalled();
  }));   

  it('should click Edit button', fakeAsync(() => {
    let buttonElement = fixture.debugElement.query(By.css('.edit-button'));
    
    spyOn(component, 'editPerson');
    //Trigger click event after spyOn
    buttonElement.triggerEventHandler('click', null);
    
    tick();
    expect(component.editPerson).toHaveBeenCalled();
  }));  
}); 

8. Run Test Cases

To run the test cases, find the steps.
1. Install Angular CLI using link.
2. Download source code using download link given below on this page.
3. Use downloaded src in your Angular CLI application.
4. Run ng test using command prompt. Test result can be seen on command prompt as well as on browser.
5. A chrome for test result will open automatically or we can also use the URL http://localhost:9876/
Find the test result print screen.
Angular Test Button Click

9. References

Basics of testing components
ComponentFixture
Jasmine Spy

10. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us