Angular Test Input Text

By Arvind Rai, 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.

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

The TestBed configures and initializes environment for unit testing. The TestBed instantiates required component and services for testing.
TestBed.configureTestingModule({
  imports: [FormsModule],
  declarations: [PersonComponent]
}); 
In the above code, we have imported 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

The ComponentFixture is the fixture for debugging and testing a component. It is instantiated using TestBed.
let fixture: ComponentFixture<PersonComponent>;
fixture = TestBed.createComponent(PersonComponent); 
To create component object using ComponentFixture, it provides componentInstance property.
let component: PersonComponent;
component = fixture.componentInstance; 
To access HTML element from HTML template, the ComponentFixture provides debugElement and nativeElement.
const hostElement = fixture.nativeElement;
const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); 
In 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 
We can use it as following in our test code.
const hostElement = fixture.debugElement.nativeElement;
const nameInput: HTMLInputElement = hostElement.querySelector('#nameId'); 
Now find some of ComponentFixture methods used in our example.
detectChanges(): Triggers a change detection cycle for component.
fixture.detectChanges(); 
whenStable(): Gives a 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 using NgModel 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;    
} 
person.component-1.html
<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> 
A test file is named after component file name by suffixing .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');
    });
  });
}); 
The 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 }
  ]
}); 
Now find the test file using 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 with FormControl.
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();
} 
person.component-2.html
<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> 
Find the test file.
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');
    });
  });
}); 
Find the test file using 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.
Angular Test Input Text

7. References

Angular Testing
JASMINE Test

8. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us