如何使用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
相关产品推荐
相关产品推荐

