You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Jest对Angular的ngx-formly表单验证进行单元测试

如何用Jest测试ngx-formly V5的自定义联动验证器?

问题背景

我正在使用ngx-formly V5生成包含输入框和复选框的表单,Formly配置如下:

field: FormlyFieldConfig = {
className: 'database-header',
validators: {
  validation: [
    { name: 'maxLengthIfExternal', options: { errorPath: 'name' } },
  ],
},
fieldGroup: [
  {
    className: 'align-left',
    key: 'name',
    type: 'input',
    defaultValue: '',

    templateOptions: {
      required: true,
      label: 'Database Name',
      pattern: HYPHEN_REGEX_PATTERN_VALIDATION,
      maxLength: 32,
    },
    validation: {
      messages: {
        pattern:
          'Allowed characters: a-z 0-9 -, must start with lower case letter and end with an alphanumeric character',
      },
    },
  },
  {
    key: 'external',
    type: 'checkbox',
    templateOptions: {
      label: 'External',
    },
  },
],
};

自定义验证器maxLengthIfExternal的逻辑是:当复选框external勾选时,输入框name的长度不能超过8个字符。现在需要用Jest编写单元测试,验证当输入框内容超过8字符且勾选复选框时,表单是否变为无效状态。

解决方案

1. 配置测试模块

首先在测试文件中导入必要的Angular模块,并注册自定义验证器:

import { Component } from '@angular/core';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { ReactiveFormsModule, FormGroup } from '@angular/forms';
import { FormlyModule, FormlyFieldConfig } from '@ngx-formly/core';
import { maxLengthIfExternal } from './path-to-your-validator';

// 临时测试组件
@Component({
  template: `
    <form [formGroup]="form">
      <formly-form [form]="form" [fields]="fields" [model]="model"></formly-form>
    </form>
  `,
})
class TestFormComponent {
  form = new FormGroup({});
  model = {};
  fields: FormlyFieldConfig[] = [yourFieldConfig]; // 替换为你定义的field变量
}

describe('maxLengthIfExternal Validator', () => {
  let fixture: ComponentFixture<TestFormComponent>;
  let component: TestFormComponent;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        ReactiveFormsModule,
        FormlyModule.forRoot({
          validators: [
            { name: 'maxLengthIfExternal', validation: maxLengthIfExternal },
          ],
        }),
      ],
      declarations: [TestFormComponent],
    }).compileComponents();

    fixture = TestBed.createComponent(TestFormComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });
});

2. 编写核心测试用例

在describe块中添加测试逻辑,模拟用户操作并验证验证器行为:

it('should invalidate form when external is checked and name length exceeds 8', () => {
  // 1. 设置name输入值为超过8字符的内容
  component.model.name = 'longdatabasename123';
  // 2. 勾选external复选框
  component.model.external = true;
  
  // 3. 触发表单验证
  component.form.get('name')?.setValue(component.model.name);
  component.form.get('external')?.setValue(component.model.external);
  component.form.updateValueAndValidity();
  
  // 4. 断言验证结果
  expect(component.form.invalid).toBe(true);
  expect(component.form.get('name')?.hasError('maxLengthIfExternal')).toBe(true);
});

it('should keep form valid when external is unchecked even if name length exceeds 8', () => {
  // 反向验证:未勾选external时,name超过8字符仍有效
  component.model.name = 'longdatabasename123';
  component.model.external = false;
  
  component.form.get('name')?.setValue(component.model.name);
  component.form.get('external')?.setValue(component.model.external);
  component.form.updateValueAndValidity();
  
  expect(component.form.valid).toBe(true);
  expect(component.form.get('name')?.hasError('maxLengthIfExternal')).toBe(false);
});

关键说明

  • 手动更新表单控件值后调用updateValueAndValidity(),确保验证器触发
  • 通过hasError('maxLengthIfExternal')直接验证目标控件是否存在预期错误
  • 增加反向测试用例,确保验证器仅在指定条件下生效

内容的提问来源于stack exchange,提问作者Sa Hagin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 21:15:43