4 ways to test button click event handler in Angular unit testing
- Admin
- Dec 31, 2023
- Angular-test
In this tutorial, You learned unit testing button click event in Angular application.
You can see my previous about Angular button click event example
Let’s define an angular component - ButtonDemoComponent
for the button click event In this component, Button is displayed and on clicking the button, the Click event is called and displays the message to the UI element.
<div style="text-align:center">
<h1>Angular Button Click Event Example</h1>
<button (click)="clickEvent()">Click Me</button>
<h2>{{msg}}</h2>
</div>
Typescript component
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-button-demo",
templateUrl: "./button-demo.component.html",
styleUrls: ["./button-demo.component.scss"],
})
export class ButtonDemoComponent implements OnInit {
msg: string = "";
constructor() {}
ngOnInit(): void {}
clickEvent() {
this.msg = "Button is Clicked";
return this.msg;
}
}
There are multiple ways we can check events in Angular applications.
Button clicks an event, events are browser-based asynchronous. It can use with or without async
and fakeAscyn
functions.
First, get the instance of a component in beforeEach of the spec.ts file
import { TestBed, async, ComponentFixture, fakeAsync, tick } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { ButtonDemoComponent } from './button-demo.component';
describe('ButtonDemoComponent', () => {
let component: ButtonDemoComponent;
let fixture: ComponentFixture<ButtonDemoComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ButtonDemoComponent]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ButtonDemoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
Let’s see an example without asynchronous behavior.
Jasmine spyOn click event example in Angular
Jasmine API provides the spyOn
method to call methods of a class or components.
It uses to call methods with or without arguments to create a stub of the method.
Syntax
spyOn("instance", "method");
Here instance is a component or a class that we can get using TestBed.createComponent(ButtonDemoComponent) method. We can supply parameters as well as return types for the spyon method.
Here is a spyon example of how it is created for arguments and return type
spyOn(Calculator, "add")
.withArgs(1, 9)
.and.returnValue(10)
.withArgs(0, 1)
.and.returnValue(1)
.withArgs(undefined, undefined)
.and.returnValue(0);
We have created a spy or stub for an add
method.
It returns the possible values for executing add method with the Calculator. add() method. Add method does not add real logic, but we are defining what values are returned based on arguments.
Calculator.add(undefined,undefined) returns 0
Calculator.add(1,9) returns 10
Calculator.add(0,1) returns 1
The spyon
method is useful on a method when we have dependencies inside a method logic like subscribe and API calls. Let’s see step-by-step calls for buttons even
create a stub object using spyon on a given function - clickEvent
call actual function component.clickEvent() which not calls function but calls the stub object
get the button selector using By.css selector
Finally, jasmine matcher toHaveBeenCalled checked against the method is called or not.
it("Button click event using spyon", () => {
spyOn(component, "clickEvent");
component.clickEvent();
fixture.detectChanges();
let buton = fixture.debugElement
.query(By.css("button"))
.nativeElement.click();
expect(component.clickEvent).toHaveBeenCalled();
});
triggerEventHandler in unit testing angular
triggerEventHandler
is a function event available in DebugElement
in Angular testing.
It triggers an event by name on a DOM Object and the corresponding event handler calls on the native element.
When testing code, You have to call triggerEventHandler
after `detectChanges’ and before assertion.
it("button click event triggerEventHandler ", () => {
spyOn(component, "clickEvent"); // attach events to component with bining
let btn = fixture.debugElement.query(By.css("button"));
btn.triggerEventHandler("click", null);
fixture.detectChanges();
expect(component.clickEvent).toHaveBeenCalled();
});
Steps
- Create a stub object with the `spyon’ function
- get Button object using `DebugElement’ with By API
- call the event handler function with `triggerEventHandler’
- Finally, the Assert event handler function is called or not
toHaveBeenCalled()' in the
expect` function
async button click event testing example in Angular
In this approach, using the async function from Angular testing.
This helps to create an asynchronous function, inside it, all asynchronous functions are written and executed.
- create a stub object clickevent function
- get Button element and called using click event or triggerevent handler
- detectChanges executes detection change events for a component.
whenStable
function is defined inComponentFixture
which gives promise object. It waits for all tasks to be completed in ngZone, without using this, it calls immediately
it("button click event one way", async(() => {
spyOn(component, "clickEvent");
let button = fixture.debugElement.nativeElement.querySelector("button");
button.click(); // you can use btn.triggerEventHandler('click', null);
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.clickEvent).toHaveBeenCalled();
});
}));
fakeAsync with tick method in Angular
tick
method is defined in Angular testing API. It uses with fakeAync
only. It waits for time to finish all pending tasks fakeAsync is used to run the test code in an asynchronous test zone
import { fakeAsync, tick } from "@angular/core/testing";
Here is an example using fakeAsync and tick for button click event handler
it("button click event triggerEventHandler ", fakeAsync(() => {
fixture.detectChanges();
spyOn(component, "clickEvent"); //method attached to the click.
let btn = fixture.debugElement.query(By.css("button"));
btn.triggerEventHandler("click", null);
tick();
fixture.detectChanges();
expect(component.clickEvent).toHaveBeenCalled();
}));
Angular button click event hander complete example
Here is a complete testing code for button click event testing.
import {
TestBed,
async,
ComponentFixture,
fakeAsync,
tick,
} from "@angular/core/testing";
import { By } from "@angular/platform-browser";
import { ButtonDemoComponent } from "./button-demo.component";
describe("ButtonDemoComponent", () => {
let component: ButtonDemoComponent;
let fixture: ComponentFixture<ButtonDemoComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ButtonDemoComponent],
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ButtonDemoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it("should create", () => {
expect(component).toBeTruthy();
});
it("button click event one way", async(() => {
spyOn(component, "clickEvent");
let button = fixture.debugElement.nativeElement.querySelector("button");
button.click();
fixture.detectChanges();
fixture.whenStable().then(() => {
expect(component.clickEvent).toHaveBeenCalled();
});
}));
it("button click event triggerEventHandler ", fakeAsync(() => {
fixture.detectChanges();
spyOn(component, "clickEvent");
let btn = fixture.debugElement.query(By.css("button"));
btn.triggerEventHandler("click", null);
tick();
fixture.detectChanges();
expect(component.clickEvent).toHaveBeenCalled();
}));
it("button click event triggerEventHandler ", () => {
fixture.detectChanges();
spyOn(component, "clickEvent");
let btn = fixture.debugElement.query(By.css("button"));
btn.triggerEventHandler("click", null);
fixture.detectChanges();
expect(component.clickEvent).toHaveBeenCalled();
});
it("Button click event using spyon", () => {
spyOn(component, "clickEvent");
component.clickEvent();
fixture.detectChanges();
let buton = fixture.debugElement
.query(By.css("button"))
.nativeElement.click();
expect(component.clickEvent).toHaveBeenCalled();
});
});
Conclusion
You learned multiple ways to test the event handler for button click events in the Angular unit test
- spyon
- triggerEventHandler
- async and whenstable fixture
- fakeAync and tick methods