web-dev-qa-db-ja.com

Angular2カスタムバリデーターディレクティブをユニットテストする方法は?

入力フィールド用の非常にシンプルなカスタムバリデーターを作成しました。

import { Directive } from '@angular/core';
import { AbstractControl, NG_VALIDATORS } from '@angular/forms';

function numberValidator(c: AbstractControl) {
    if (!c.value) return null;
    return new RegExp('^[1-9][0-9]{6,9}$').test(c.value) ? null : {
        validateNumber: {
            valid: false
        }
    }
}

@Directive({
    selector: '[number-validator]',
    providers: [
        { provide: NG_VALIDATORS, multi: true, useValue: numberValidator }
    ]
})
export class NumberValidator {

}

このバリデーターを単体テストしたいと思います。 Angular2ページで 属性ディレクティブのテスト を読みましたが、変更されるCSSまたはHTMLはありません。このバリデーターを単体テストするにはどうすればよいですか?

11
Robin Dijkhof

簡単な方法で実行したい場合(すべてのロジックはバリデーター関数内にあるので、私はそうします)、バリデーター関数をテストするだけです。コントロールを渡すだけです

expect(numberValidator(new FormControl('123456'))).toEqual({
  'validateNumber': { 'valid': false }
});
expect(numberValidator(new FormControl('123456789'))).toEqual(null);

「使用されている」ときに本当にテストしたい場合は、少し面倒になります。これらは通常私が取るステップです

  1. ディレクティブを使用するダミーコンポーネントを作成する
  2. テストベッド構成をセットアップする
  3. テストするコンポーネントを作成します。
  4. ネイティブ入力要素を取得し、それに無効な入力イベントを送出します
  5. NgFormを保持するインジェクターを取得する
  6. フォームの失敗を確認します
  7. 有効な入力を入力し、それが通過することを確認してください。

バリデーターメソッドをテストするだけの場合と比較すると、多くの点があります。しかし、ここはとにかくです;-)お楽しみください!

import { Component, Directive } from '@angular/core';
import { TestBed, async } from '@angular/core/testing';
import { dispatchEvent } from '@angular/platform-browser/testing/browser_util';
import { By } from '@angular/platform-browser';
import { FormsModule, NG_VALIDATORS, AbstractControl,
         NgForm, FormControl } from '@angular/forms';

function numberValidator(c: AbstractControl) {
  if (!c.value) return null;
  return new RegExp('^[1-9][0-9]{6,9}$').test(c.value) ? null : {
    validateNumber: {
      valid: false
    }
  };
}

@Directive({
  selector: '[number-validator]',
  providers: [
    { provide: NG_VALIDATORS, multi: true, useValue: numberValidator }
  ]
})
export class NumberValidator {
}

@Component({
  template: `
    <form>
      <input name="number" type="text" ngModel number-validator />
    </form>
  `
})
class TestComponent {
}

describe('component: TestComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [ FormsModule ],
      declarations: [TestComponent, NumberValidator]
    });
  });

  it('should validate (easy)', () => {
    expect(numberValidator(new FormControl('123'))).toEqual({
      'validateNumber': { 'valid': false }
    });
    expect(numberValidator(new FormControl('123456789'))).toEqual(null);
  });

  it('should validate (tedious)', async(() => {
    let fixture = TestBed.createComponent(TestComponent);
    let comp = fixture.componentInstance;
    let debug = fixture.debugElement;
    let input = debug.query(By.css('[name=number]'));

    fixture.detectChanges();
    fixture.whenStable().then(() => {
      input.nativeElement.value = '123';
      dispatchEvent(input.nativeElement, 'input');
      fixture.detectChanges();

      let form: NgForm = debug.children[0].injector.get(NgForm);
      let control = form.control.get('number');

      // just to show a few different ways we can check validity
      expect(control.hasError('validateNumber')).toBe(true);
      expect(control.valid).toBe(false);
      expect(form.control.valid).toEqual(false);
      expect(form.control.hasError('validateNumber', ['number'])).toEqual(true);

      input.nativeElement.value = '123456789';
      dispatchEvent(input.nativeElement, 'input');
      fixture.detectChanges();

      expect(form.control.valid).toEqual(true);
    });
  }));
});
20
Paul Samsotha