【问题标题】:Test a Reactive Form field that has a custom validator in Angular在 Angular 中测试具有自定义验证器的响应式表单字段
【发布时间】:2019-03-13 16:57:32
【问题描述】:

我正在尝试在响应式表单上测试自定义验证字段的有效状态。

我的组件如下:

import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { ageRangeValidator } from './age-range-validator.directive';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'Reactive Forms';
  genders = ['Female', 'Male'];

  constructor(private fb: FormBuilder) { }

  userForm = this.fb.group({
    firstname: ['', [Validators.required, Validators.minLength(2)]],
    surname: ['', [Validators.required, Validators.minLength(2)]],
    address: this.fb.group({
      houseNo: [''],
      street: [''],
      city: [''],
      postcode: ['']
    }),
    // Section 1
    // age: [null, Validators.min(18)],
    // Section 2 - using a Custom validator
    age: [null, ageRangeValidator(18, 68)],
    gender: ['']
  });
}

ageRangeValidator 函数如下 - 这已经过全面测试并且可以工作:

import { AbstractControl, ValidatorFn } from '@angular/forms';

export function ageRangeValidator(min: number, max: number): ValidatorFn {
  return (control: AbstractControl): { [key: string]: boolean } | null => {
    if ((!isNaN(control.value) && control.value) && control.value > min && control.value < max) {
      return { 'ageRange': true };
    }
    return null;
  };
}

我对 App 组件进行了如下设置的测试,我在其中设置了年龄字段的值,然后测试它是否有效 - 测试返回有效性为 false:

import { TestBed, async, ComponentFixture } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { ReactiveFormsModule } from '@angular/forms';
import { DebugElement } from '@angular/core';

describe('AppComponent', () => {
  let fixture: ComponentFixture<AppComponent>;
  let app: AppComponent;


  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
      imports: [ReactiveFormsModule]
    }).compileComponents();

  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(AppComponent);
    app = fixture.debugElement.componentInstance;
    fixture.detectChanges();
  });
  
  describe(`Test the validity of the fields`, () => {
    it(`should return true if a value of 18 or more AND 68 or LESS is supplied (as string or number)`, () => {
      const age = app.userForm.controls['age'];
      age.setValue(42);
      expect(age.valid).toBeTruthy();
    });
  });

我希望该解决方案需要将 ageRangeValidator 函数以某种方式连接到测试组件,但我无法弄清楚如何 - 谁能建议我可以做到这一点的方法(如果可能的话)?

最终,我正在尝试测试表单的有效性,以确保在所有必填字段都有效时可以提交它。

【问题讨论】:

    标签: javascript angular unit-testing testing


    【解决方案1】:
    1. 使用 controls.get('age') 尽量避免直接访问控件
    2. 设置值后需要https://angular.io/api/core/testing/tick 才能运行验证过程

    【讨论】:

    • 感谢您的建议,我已经实现了第 1 点!能否请您扩展第 2 点 - 我已尝试将规范转换为 fakeAsync 并引入 tick(1000),但出现错误。我不确定我是否完全按照您的意思理解?
    • tick() (与 tick(0) 相同)必须足够,因为验证正在等待最接近的运行微任务的可能性。你能告诉我它显示的确切错误吗?
    • 再次感谢您的回复...我修改后的套件现在是:
    • describe('Test the validity of the fields', () =&gt; { it('should return true if a value of 18 or more AND 68 or LESS is supplied (as string or number)', fakeAsync(() =&gt; { const age = app.userForm.get('age'); age.setValue(42); tick(); age.updateValueAndValidity(); tick(); expect(age.valid).toBeTruthy(); })); });
    • Chrome 72.0.3626 (Mac OS X 10.14.3):执行 1 of 1 (1 FAILED) (0 secs / 0.269 secs) Chrome 72.0.3626 (Mac OS X 10.14.3) AppComponent Test如果提供 18 或更多 AND 68 或 LESS 的值(作为字符串或数字),则字段的有效性应返回 true 失败 预期 false 为真。在 UserContext. src/app/app.component.spec.ts:79:31) 在 UserContext. node_modules/zone.js/dist/zone-testing.js:1429:1) 在
    【解决方案2】:

    对于遇到此问题的其他人,如果您正确编写了自定义验证器,则不必做任何特别的事情。如果您收到参考错误,只需重新保存您的文件。将自定义验证器连接到响应式表单规范中没有什么特别需要做的事情,您甚至不必将其导入规范文件。

    【讨论】:

      猜你喜欢
      • 2017-08-28
      • 2022-01-23
      • 2018-09-19
      • 2020-10-16
      • 1970-01-01
      • 2018-07-14
      • 2019-10-10
      • 2021-06-24
      • 2020-01-13
      相关资源
      最近更新 更多