Reputation: 23
I have a very basic Angular template driven form with a single field which is required. A validation message is displayed if the field is invalid, which is the case when the component is first loaded as the field is required but empty. The code runs as expected when viewed in the application and the validation message is displayed.
When testing the component via a Jasmine unit test the validation message is not picked up and the test fails.
I am confident that the logic to look for the validation message is working, because if I remove the *ngIf directive on the message DIV then the test passes.
I have tried the following:
Template:
<form #form="ngForm">
<label>First name:</label>
<input #firstName="ngModel"
type="text"
name="firstName"
[(ngModel)]="firstNameText"
required />
<div class="validation-error" *ngIf="firstName.invalid">
Please enter a valid first name
</div>
</form>
Component class:
import { Component } from '@angular/core';
@Component({
selector: 'app-person-form',
templateUrl: './person-form.component.html'
})
export class PersonFormComponent {
public firstNameText: string;
}
Jasmine test spec:
import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing';
import { PersonFormComponent } from './person-form.component';
import { FormsModule } from '@angular/forms';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
describe('PersonFormComponent', () => {
let fixture: ComponentFixture<PersonFormComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ FormsModule ],
declarations: [ PersonFormComponent ]
});
fixture = TestBed.createComponent(PersonFormComponent);
fixture.detectChanges();
});
it('should show a validation error if the first name was touched but left empty', () => {
let firstNameValidationError: DebugElement;
// try to get a handle to the validation message (should exist as form is invalid):
firstNameValidationError = fixture.debugElement.query(By.css('.validation-error'));
// the validation error should be found:
expect(firstNameValidationError).toBeTruthy();
});
});
Upvotes: 1
Views: 5670
Reputation: 23
The complete revised test is as follows, thanks to Amit Chigadani for solving this:
import { ComponentFixture, TestBed, fakeAsync } from '@angular/core/testing';
import { PersonFormComponent } from './person-form.component';
import { FormsModule } from '@angular/forms';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
describe('PersonFormComponent', () => {
let fixture: ComponentFixture<PersonFormComponent>;
beforeEach(async() => {
TestBed.configureTestingModule({
imports: [ FormsModule ],
declarations: [ PersonFormComponent ]
});
fixture = TestBed.createComponent(PersonFormComponent);
fixture.detectChanges();
});
it('should show a validation error if the first name was touched but left empty', () => {
let firstNameValidationError: DebugElement;
fixture.detectChanges(); // run change detection
// try to get a handle to the validation message (should exist as form is invalid):
firstNameValidationError = fixture.debugElement.query(By.css('.validation-error'));
// the validation error should be found:
expect(firstNameValidationError).toBeTruthy();
});
});
Upvotes: 1
Reputation: 29705
Component initialization should always be done in a async
block
beforeEach(async() => {
TestBed.configureTestingModule({
imports: [ FormsModule ],
declarations: [ PersonFormComponent ]
});
fixture = TestBed.createComponent(PersonFormComponent);
fixture.detectChanges();
});
Also you may need to run change detection once again after the component is initialised
it('should show a validation error if the first name was touched but left empty', () => {
let firstNameValidationError: DebugElement;
fixture.detectChanges(); // run change detection
firstNameValidationError = fixture.debugElement.query(By.css('.validation-error'));
// the validation error should be found:
expect(firstNameValidationError).toBeTruthy();
});
Upvotes: 1
Reputation: 2265
Add these lines at the beginning of the test
let component = fixture.componentInstance;
component.firstNameText = '';
fixture.detectChanges();
and after this, set some name to the firstNameText as below
component.firstNameText = 'test';
At this point, you should expect the error to be falsy.
Upvotes: 0