Angular Test Input Text
April 02, 2020
This page will walk through Angular unit test for HTML input text field. Angular provides ComponentFixture
to test and debug component. To configure testing module, Angular provides TestBed
. To test HTML input text field, we will create Angular application in which we will create input texts using NgModel
and FormControl
binding. In our test cases, we will verify that the data entered into input text is assigned to component property using property binding and the value of this component property is added in DOM to display on UI. Now we will discuss complete example in detail step-by-step.
Contents
1. Technologies Used
Find the technologies being used in our example.1. Angular 9.0.2
2. Node.js 12.5.0
3. Jasmine Core 3.5.0
4. Karma 4.3.0
2. Configure Testing Module with TestBed
TheTestBed
configures and initializes environment for unit testing. The TestBed
instantiates required component and services for testing.
TestBed.configureTestingModule({ imports: [FormsModule], declarations: [PersonComponent] });
FormsModule
and has declared our component that need to be tested. Importing FormsModule
will enable us to test HTML fields which are using ngModel
property binding.
If we want to test reactive form such as testing input text with
FormControl
binding, we need to import ReactiveFormsModule
as following.
TestBed.configureTestingModule({ imports: [ReactiveFormsModule], declarations: [PersonComponent] });
3. ComponentFixture
TheComponentFixture
is the fixture for debugging and testing a component. It is instantiated using TestBed
.
let fixture: ComponentFixture<PersonComponent>; fixture = TestBed.createComponent(PersonComponent);
ComponentFixture
, it provides componentInstance
property.
let component: PersonComponent; component = fixture.componentInstance;
ComponentFixture
provides
debugElement
and nativeElement
.
const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId');
querySelector
we can pass element id or element type. Element id is passed prefixed with # .
The
debugElement
returns DebugElement
object. In ComponentFixture
, the nativeElement
is the convenience method for
fixture.debugElement.nativeElement
const hostElement = fixture.debugElement.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId');
ComponentFixture
methods used in our example.
detectChanges(): Triggers a change detection cycle for component.
fixture.detectChanges();
Promise
that resolves when the fixture is stable.
fixture.whenStable().then(val => { ------ expect(displayAge.textContent).toBe('20'); });
4. Unit Test for Input Text with NgModel
In our example we have two components, one is usingNgModel
to bind input text and another is using FormControl
to bind input text.
Find the component with
NgModel
.
person.component-1.ts
import { Component } from '@angular/core'; @Component({ selector: 'app-person-1', templateUrl: 'person.component-1.html' }) export class PersonComponent1 { personName: string; personAge: number; }
<h3>ngModel Demo</h3> <p>Name: <input [(ngModel)]="personName" id="nameId"> </p> <p>Age: <input [(ngModel)]="personAge" id="ageId"> </p> <div id="disName">{{personName}}</div> <div id="disAge">{{personAge}}</div>
.spec
. Find the test file.
person.component-1.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PersonComponent1 } from './person.component-1'; import { FormsModule } from '@angular/forms'; describe('PersonComponent1', () => { let component: PersonComponent1; let fixture: ComponentFixture<PersonComponent1>; beforeEach(() => { TestBed.configureTestingModule({ imports: [FormsModule], declarations: [PersonComponent1] }); fixture = TestBed.createComponent(PersonComponent1); component = fixture.componentInstance; }); it('should bind input text value to Component property', () => { const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); const ageInput: HTMLInputElement = hostElement.querySelector('#ageId'); fixture.detectChanges(); nameInput.value = 'Amit Shah'; ageInput.value = '20'; nameInput.dispatchEvent(new Event('input')); ageInput.dispatchEvent(new Event('input')); expect(component.personName).toBe('Amit Shah'); expect(component.personAge.toString()).toBe('20'); }); it('should perform display binding in HTML template', () => { const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); const ageInput: HTMLInputElement = hostElement.querySelector('#ageId'); const displayName: HTMLInputElement = hostElement.querySelector('#disName'); const displayAge: HTMLInputElement = hostElement.querySelector('#disAge'); fixture.detectChanges(); fixture.whenStable().then(val => { nameInput.value = 'Amit Shah'; ageInput.value = '20'; nameInput.dispatchEvent(new Event('input')); ageInput.dispatchEvent(new Event('input')); fixture.detectChanges(); expect(displayName.textContent).toBe('Amit Shah'); expect(displayAge.textContent).toBe('20'); }); }); });
dispatchEvent()
method dispatches a DOM event so that Angular acknowledges input value change.
We can configure
ComponentFixtureAutoDetect
in test module instead of using detectChanges()
method. The ComponentFixtureAutoDetect
is configured as following.
TestBed.configureTestingModule({ ------ providers: [ { provide: ComponentFixtureAutoDetect, useValue: true } ] });
ComponentFixtureAutoDetect
.
person.component-1.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixtureAutoDetect } from '@angular/core/testing'; import { PersonComponent1 } from './person.component-1'; import { FormsModule } from '@angular/forms'; describe('PersonComponent1', () => { let component: PersonComponent1; let fixture: ComponentFixture<PersonComponent1>; beforeEach(() => { TestBed.configureTestingModule({ imports: [FormsModule], declarations: [PersonComponent1], providers: [ { provide: ComponentFixtureAutoDetect, useValue: true } ] }); fixture = TestBed.createComponent(PersonComponent1); component = fixture.componentInstance; }); it('should bind input text value to Component property', () => { const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); const ageInput: HTMLInputElement = hostElement.querySelector('#ageId'); nameInput.value = 'Amit Shah'; ageInput.value = '20'; nameInput.dispatchEvent(new Event('input')); ageInput.dispatchEvent(new Event('input')); expect(component.personName).toBe('Amit Shah'); expect(component.personAge.toString()).toBe('20'); }); it('should perform display binding in HTML template', () => { const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); const ageInput: HTMLInputElement = hostElement.querySelector('#ageId'); const displayName: HTMLInputElement = hostElement.querySelector('#disName'); const displayAge: HTMLInputElement = hostElement.querySelector('#disAge'); nameInput.value = 'Amit Shah'; ageInput.value = '20'; nameInput.dispatchEvent(new Event('input')); ageInput.dispatchEvent(new Event('input')); fixture.detectChanges(); expect(displayName.textContent).toBe('Amit Shah'); expect(displayAge.textContent).toBe('20'); }); });
5. Unit Test for Input Text with FormControl
Find the component withFormControl
.
person.component-2.ts
import { Component } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ selector: 'app-person-2', templateUrl: 'person.component-2.html' }) export class PersonComponent2 { personName = new FormControl(); personAge = new FormControl(); }
<h3>formControl Demo</h3> <p>Name: <input [formControl]="personName" id="nameId"> </p> <p>Age: <input [formControl]="personAge" id="ageId"> </p> <div id="disName">{{personName.value}}</div> <div id="disAge">{{personAge.value}}</div>
person.component-2.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PersonComponent2 } from './person.component-2'; import { ReactiveFormsModule } from '@angular/forms'; describe('PersonComponent2', () => { let component: PersonComponent2; let fixture: ComponentFixture<PersonComponent2>; beforeEach(() => { TestBed.configureTestingModule({ imports: [ReactiveFormsModule], declarations: [PersonComponent2] }); fixture = TestBed.createComponent(PersonComponent2); component = fixture.componentInstance; }); it('should bind input text value to Component property', () => { const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); const ageInput: HTMLInputElement = hostElement.querySelector('#ageId'); fixture.detectChanges(); nameInput.value = 'Amit Shah'; ageInput.value = '20'; nameInput.dispatchEvent(new Event('input')); ageInput.dispatchEvent(new Event('input')); expect(component.personName.value).toBe('Amit Shah'); expect(component.personAge.value.toString()).toBe('20'); }); it('should perform display binding in HTML template', () => { const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); const ageInput: HTMLInputElement = hostElement.querySelector('#ageId'); const displayName: HTMLInputElement = hostElement.querySelector('#disName'); const displayAge: HTMLInputElement = hostElement.querySelector('#disAge'); fixture.detectChanges(); fixture.whenStable().then(val => { nameInput.value = 'Amit Shah'; ageInput.value = '20'; nameInput.dispatchEvent(new Event('input')); ageInput.dispatchEvent(new Event('input')); fixture.detectChanges(); expect(displayName.textContent).toBe('Amit Shah'); expect(displayAge.textContent).toBe('20'); }); }); });
ComponentFixtureAutoDetect
.
person.component-2.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixtureAutoDetect } from '@angular/core/testing'; import { PersonComponent2 } from './person.component-2'; import { ReactiveFormsModule } from '@angular/forms'; describe('PersonComponent2', () => { let component: PersonComponent2; let fixture: ComponentFixture<PersonComponent2>; beforeEach(() => { TestBed.configureTestingModule({ imports: [ReactiveFormsModule], declarations: [PersonComponent2], providers: [ { provide: ComponentFixtureAutoDetect, useValue: true } ] }); fixture = TestBed.createComponent(PersonComponent2); component = fixture.componentInstance; }); it('should bind input text value to Component property', () => { const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); const ageInput: HTMLInputElement = hostElement.querySelector('#ageId'); nameInput.value = 'Amit Shah'; ageInput.value = '20'; nameInput.dispatchEvent(new Event('input')); ageInput.dispatchEvent(new Event('input')); expect(component.personName.value).toBe('Amit Shah'); expect(component.personAge.value.toString()).toBe('20'); }); it('should perform display binding in HTML template', () => { const hostElement = fixture.nativeElement; const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); const ageInput: HTMLInputElement = hostElement.querySelector('#ageId'); const displayName: HTMLInputElement = hostElement.querySelector('#disName'); const displayAge: HTMLInputElement = hostElement.querySelector('#disAge'); nameInput.value = 'Amit Shah'; ageInput.value = '20'; nameInput.dispatchEvent(new Event('input')); ageInput.dispatchEvent(new Event('input')); expect(displayName.textContent).toBe('Amit Shah'); expect(displayAge.textContent).toBe('20'); }); });
6. 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.

7. References
Angular TestingJASMINE Test