【问题标题】:Angular2 how to unit test a custom validator directive?Angular2如何对自定义验证器指令进行单元测试?
【发布时间】:2017-02-18 20:19:43
【问题描述】:

我为输入字段编写了一个非常简单的自定义验证器:

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 页面上阅读了Test an attribute directive,但没有 css 或 html 发生变化。如何对这个验证器进行单元测试?

【问题讨论】:

    标签: unit-testing angular karma-jasmine angular2-forms angular2-testing


    【解决方案1】:

    如果你想用简单的方法(我会这样做,因为所有逻辑都在验证器函数中),只是测试验证器函数。只需将控件传递给它

    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);
        });
      }));
    });
    

    【讨论】:

    • 当我尝试第二种方法时。我没有找到 ngForm 的提供者。我确信这应该是我的错误。你知道这可能是什么问题吗?
    • 获取NgForm 的更好方法是使用debug.query(By.directive(NgForm))。我只是在查看 Angular 源代码测试,以找到我在上面的帖子中所做的方式。但是使用By.directive 可能是更好的方法。
    猜你喜欢
    • 2015-01-23
    • 1970-01-01
    • 2016-09-13
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    相关资源
    最近更新 更多