I wrote a very simple custom validator for an input field:
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 {}
I would like to unit test this validator. I read Test an attribute directive on the Angular2 page, but there is no css or html that changes. How can I unit test this validator?
Unit Test in Jasmine You use TestComponentBuilder as shown in the lined SO question/answer. Create a test component where the directive is used in the template and then get a reference to the directive from the created test component instance.
The CustomValidator control is a separate control from the input control it validates, which allows you to control where the validation message is displayed. Validation controls always perform validation on the server.
If you want to do it the easy way (which I would do, since all the logic is in the validator function), is just to test the validator function. Just pass a control to it
expect(numberValidator(new FormControl('123456'))).toEqual({ 'validateNumber': { 'valid': false } }); expect(numberValidator(new FormControl('123456789'))).toEqual(null);
If you really want to test it when "being used", then it gets a little tedious. These are usually the steps I take
NgForm
It's a lot compared to just testing the validator method. But here it is anyway ;-) Enjoy!
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); }); })); });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With