Angular 2 自定义验证单元测试

Angular 2 Custom validation unit testing

我正在编写自定义 angular(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,或者我如何检查 valid/invalid(自定义验证)输入字段。

您需要做的是获得带有 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@whosebug.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@whosebug.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

以上最佳答案对我不起作用,但我能够通过以下方式测试我的自定义验证器:

const associateRateControl = component.distributionSettingsForm.controls['associateRate'];
associateRateControl.setValue('plus ultra');
fixture.detectChanges();
expect(component.distributionSettingsForm.hasError('noCatalog')).toEqual(true);

关于该主题的另一个 heads-up。 我认为是正确的并且非常有帮助,但事实上您不需要导入任何库。我们可以使用 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();
});