【问题标题】:How to unit test validation message in Angular template driven forms如何在 Angular 模板驱动的表单中对验证消息进行单元测试
【发布时间】:2019-06-29 10:59:14
【问题描述】:

我有一个非常基本的 Angular 模板驱动表单,其中包含一个必填字段。如果该字段无效,则会显示一条验证消息,这是首次加载组件时的情况,因为该字段是必需的但为空。在应用程序中查看时代码按预期运行并显示验证消息。

当通过 Jasmine 单元测试测试组件时,验证消息不会被拾取并且测试失败。

我确信查找验证消息的逻辑正在运行,因为如果我删除消息 DIV 上的 *ngIf 指令,则测试通过。

我尝试了以下方法:

  • 将 BrowserModule 导入到测试规范中
  • 在 fakeAsync() 块中运行测试

模板:

<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>

组件类:

import { Component } from '@angular/core';

@Component({
  selector: 'app-person-form',
  templateUrl: './person-form.component.html'
})
export class PersonFormComponent  {
  public firstNameText: string;
}

茉莉花测试规范:

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();
  });
});

【问题讨论】:

  • 您是否尝试将值设置为firstName,然后运行fixture.detectChanges 来更新您的绑定?
  • 是的,但这本身并不能解决问题。我在下面发布了解决方案,基本上我需要在 async() 块内执行组件初始化并运行额外的 fixture.detectChanges。感谢您抽出宝贵时间回复我的问题,非常感谢。

标签: angular unit-testing jasmine angular-forms


【解决方案1】:

组件初始化应始终在 async 块中完成

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
    firstNameValidationError = fixture.debugElement.query(By.css('.validation-error'));

    // the validation error should be found:
    expect(firstNameValidationError).toBeTruthy();
});

【讨论】:

  • 嗨@amit-chigadani,感谢您花时间回答我的问题,您的解决方案已经解决了问题!我将发布修订后的规范,以便其他人受益。我仍在试图弄清楚为什么附加的 fixture.detectChanges() 会产生如此大的差异,因为它是每个之前的最后一个命令,我们在测试中所做的只是在再次调用运行更改检测之前声明一个变量。
【解决方案2】:

完整的修改测试如下,感谢Amit Chigadani解决了这个问题:

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();
  });
});

【讨论】:

    【解决方案3】:

    在测试的开头添加这些行

     let component = fixture.componentInstance;
        component.firstNameText = '';
        fixture.detectChanges();
    

    在此之后,为 firstNameText 设置一些名称,如下所示

    component.firstNameText = 'test';
    

    此时,您应该认为错误是虚假的。

    【讨论】:

    • 嗨 Dileepkumar,感谢您抽出宝贵时间回答我的问题,我尝试了您的建议,但第一次测试仍然失败(“真实”测试)。 Amit 指出我应该在异步块中进行组件初始化,这解决了问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-24
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    相关资源
    最近更新 更多