Angular 2 自定义验证单元测试
Posted
技术标签:
【中文标题】Angular 2 自定义验证单元测试【英文标题】:Angular 2 Custom validation unit testing 【发布时间】:2017-02-16 00:38:15 【问题描述】:我正在编写自定义角度(Angular 2.0.0)验证,遵循本指南https://angular.io/docs/ts/latest/cookbook/form-validation.html#!#custom-validation。
@Directive(
selector: '[ngModel][emailValidator]',
providers: [provide: NG_VALIDATORS, useExisting: EmailValidatorDirective, multi: true]
)
export class EmailValidatorDirective implements Validator
现在我正在尝试将单元测试添加到我的自定义验证指令中。
beforeEach(() =>
fixture = TestBed.createComponent(EmailComponent);
component = fixture.componentInstance;
de = fixture.debugElement;
el = de.nativeElement;
component = de.componentInstance;
emailField = de.query(By.css('input')).nativeElement;
);
我正在访问所有这些对象,但没有人知道我输入的有效性的任何信息。有谁知道如何在单元测试中访问我的输入的 NgControl,或者我如何检查有效/无效(自定义验证)输入字段。
【问题讨论】:
【参考方案1】:您需要做的是获取具有NgForm
的注射器。我花了一段时间才弄清楚。我以为你可以从 debugElement
那里得到它,但看起来你需要从它的孩子那里得到它1。
let form: NgForm = fixture.debugElement.children[0].injector.get(NgForm);
您可以从表单组中获取单独的控件
let emailControl = form.control.get('email');
expect(emailControl.valid).toBe(true);
或者您可以只检查表单中的特定错误
expect(form.control.hasError('emailInvalid', ['email'])).toBe(true);
下面是完整的测试
import Component, forwardRef, Directive from '@angular/core';
import TestBed, getTestBed, async from '@angular/core/testing';
import FormsModule, NG_VALIDATORS, Validator, AbstractControl, NgForm from '@angular/forms';
import dispatchEvent from '@angular/platform-browser/testing/browser_util';
import By from '@angular/platform-browser';
@Directive(
selector: '[ngModel][validEmail]',
providers: [
provide: NG_VALIDATORS,
useExisting: forwardRef(() => EmailValidatorDirective),
multi: true
]
)
class EmailValidatorDirective implements Validator
validate(c: AbstractControl): [key: string]: any
if (c.value !== 'peeskillet@***.com')
return notPeeskillet: true ;
return null;
@Component(
template: `
<form>
<input name="email" [ngModel]="email" validEmail />
</form>
`
)
class TestComponent
email;
describe('component: TestComponent', () =>
beforeEach(() =>
TestBed.configureTestingModule(
imports: [FormsModule],
declarations: [TestComponent, EmailValidatorDirective]
);
);
it('should validate', async(() =>
let fixture = TestBed.createComponent(TestComponent);
let comp = fixture.componentInstance;
let debug = fixture.debugElement;
let input = debug.query(By.css('[name=email]'));
fixture.detectChanges();
fixture.whenStable().then(() =>
input.nativeElement.value = 'bad@email.com';
dispatchEvent(input.nativeElement, 'input');
fixture.detectChanges();
let form: NgForm = debug.children[0].injector.get(NgForm);
let control = form.control.get('email');
expect(control.hasError('notPeeskillet')).toBe(true);
expect(form.control.valid).toEqual(false);
expect(form.control.hasError('notPeeskillet', ['email'])).toEqual(true);
input.nativeElement.value = 'peeskillet@***.com';
dispatchEvent(input.nativeElement, 'input');
fixture.detectChanges();
expect(control.hasError('notPeeskillet')).toBe(false);
expect(form.control.valid).toEqual(true);
expect(form.control.hasError('notPeeskillet', ['email'])).toEqual(false);
);
));
);
1 - Found it in the source code tests
【讨论】:
browser_util
已移至import dispatchEvent from '@angular/platform-browser/testing/src/browser_util';
改用内置的 dispatch 事件【参考方案2】:
上述最佳答案对我不起作用,但我能够通过以下方式测试我的自定义验证器:
const associateRateControl = component.distributionSettingsForm.controls['associateRate'];
associateRateControl.setValue('plus ultra');
fixture.detectChanges();
expect(component.distributionSettingsForm.hasError('noCatalog')).toEqual(true);
【讨论】:
【参考方案3】:关于该主题的另一个提示。
Paul Samsotha answer 我认为是正确的并且非常有帮助,但是 TBH 你不需要导入任何库。我们可以使用nativeElement
dispatchEvent
,让我们的生活更轻松。
beforeEach(() =>
const input = fixture.debugElement.query(By.css("input")).nativeElement;
fixture.detectChanges();
input.value = "test";
input.dispatchEvent(new Event("input"));
fixture.detectChanges();
);
it("should display the password strength indicator", () =>
const form = fixture.componentInstance.myMarvelousForm;
expect(form.dirty).toBeTruthy();
);
【讨论】:
以上是关于Angular 2 自定义验证单元测试的主要内容,如果未能解决你的问题,请参考以下文章