Angular 单元测试表单验证
Posted
技术标签:
【中文标题】Angular 单元测试表单验证【英文标题】:Angular unit testing form validation 【发布时间】:2019-12-18 19:16:42 【问题描述】:我正在学习 Angular 8,并且正在使用 Karma 进行单元测试。我创建了一个可以正常工作的基本注册表单,但我在测试中遇到了问题。
在测试时我遇到了 2 次失败
RegisterComponent > 表单应该是有效的 错误:预期验证器返回 Promise 或 Observable。
和
RegisterComponent > 应该调用 onSubmit 方法 错误: : 预期是间谍,但得到了 FormGroup( 验证器:函数,asyncValidator:null,_onCollectionChange:函数,原始:真,触摸:假,_onDisabledChange:[],控件:对象(名称:FormControl(验证器:函数,asyncValidator:null,_onCollectionChange:函数,原始:true,touched:false,_onDisabledChange:[函数],_onChange:[函数],_pendingValue:'',值:'',状态:'INVALID',错误:对象( required: true ), valueChanges: EventEmitter( _isScalar: false, 观察者: [ ], closed: false, isStopped: false, hasError: false, throwedError: null, __isAsync: false ), statusChanges: EventEmitter( _isScalar: false , 观察者: [ ], 关闭: false, isStopped: false, hasError: false, throwError: null, __isAsync: false ), _parent: ), 电子邮件: FormControl( validator: Function, asyncValidator: Function, _onCollectionChange: Function,原始:真,触摸:假,_onDisabledChange:[功能],_onChange:[功能],_pendingValue:'',值e:'' .... 用法:expect().toHaveBeenCalledTimes()
register.component.ts
import ActivatedRoute, Router from '@angular/router';
import Component, OnInit from '@angular/core';
import FormBuilder, FormGroup, Validators from '@angular/forms';
import AuthenticationService from '@/_services';
import MustMatch from '@/_helpers/validators';
@Component(
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.scss']
)
@Component( templateUrl: 'register.component.html' )
export class RegisterComponent implements OnInit
registerForm: FormGroup;
submitted = false;
returnUrl: string;
error = '';
constructor(
private formBuilder: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private authenticationService: AuthenticationService
)
if (this.authenticationService.currentUserValue)
this.router.navigate(['/']);
ngOnInit()
this.registerForm = this.formBuilder.group(
name: ['', Validators.required],
email: ['', Validators.required, Validators.email],
phone: ['', Validators.required],
password: ['', Validators.required, Validators.minLength(6)],
confirmPassword: ['', Validators.required],
,
validator: MustMatch('password', 'confirmPassword')
);
this.returnUrl = this.route.snapshot.queryParams.returnUrl || '/';
get f()
return this.registerForm.controls;
onSubmit()
this.submitted = true;
if (this.registerForm.invalid)
return;
this.submitted = false;
register.component.spec.ts
import async, ComponentFixture, TestBed from '@angular/core/testing';
import By from '@angular/platform-browser';
import ReactiveFormsModule, FormsModule from '@angular/forms';
import RegisterComponent from './register.component';
import ActivatedRoute, Router from '@angular/router';
import HttpClientTestingModule from '@angular/common/http/testing';
import DebugElement from '@angular/core';
describe('RegisterComponent', () =>
let component: RegisterComponent;
let fixture: ComponentFixture<RegisterComponent>;
let de: DebugElement;
let el: HTMLElement;
const fakeActivatedRoute =
snapshot:
queryParams:
returnUrl: '/'
;
const routerSpy = jasmine.createSpyObj('Router', ['navigate']);
beforeEach(async(() =>
TestBed.configureTestingModule(
imports: [ReactiveFormsModule, FormsModule, HttpClientTestingModule],
declarations: [RegisterComponent],
providers: [
provide: Router, useValue: routerSpy ,
provide: ActivatedRoute, useFactory: () => fakeActivatedRoute
]
).compileComponents().then(() =>
fixture = TestBed.createComponent(RegisterComponent);
component = fixture.componentInstance;
component.ngOnInit();
fixture.detectChanges();
de = fixture.debugElement.query(By.css('form'));
el = de.nativeElement;
);
));
beforeEach(() =>
fixture = TestBed.createComponent(RegisterComponent);
component = fixture.componentInstance;
component.ngOnInit();
fixture.detectChanges();
);
it('form invalid when empty', () =>
component.registerForm.controls.name.setValue('');
component.registerForm.controls.email.setValue('');
component.registerForm.controls.phone.setValue('');
component.registerForm.controls.password.setValue('');
component.registerForm.controls.confirmPassword.setValue('');
expect(component.registerForm.valid).toBeFalsy();
);
it('username field validity', () =>
const name = component.registerForm.controls.name;
expect(name.valid).toBeFalsy();
name.setValue('');
expect(name.hasError('required')).toBeTruthy();
);
it('email field validity', () =>
const email = component.registerForm.controls.email;
expect(email.valid).toBeFalsy();
email.setValue('');
expect(email.hasError('required')).toBeTruthy();
);
it('phone field validity', () =>
const phone = component.registerForm.controls.phone;
expect(phone.valid).toBeFalsy();
phone.setValue('');
expect(phone.hasError('required')).toBeTruthy();
);
it('password field validity', () =>
const password = component.registerForm.controls.password;
expect(password.valid).toBeFalsy();
password.setValue('');
expect(password.hasError('required')).toBeTruthy();
);
it('confirmPassword field validity', () =>
const confirmPassword = component.registerForm.controls.confirmPassword;
expect(confirmPassword.valid).toBeFalsy();
confirmPassword.setValue('');
expect(confirmPassword.hasError('required')).toBeTruthy();
);
it('should set submitted to true', () =>
component.onSubmit();
expect(component.submitted).toBeTruthy();
);
it('should call onSubmit method', () =>
spyOn(component, 'onSubmit');
el = fixture.debugElement.query(By.css('button')).nativeElement;
el.click();
expect(component.registerForm).toHaveBeenCalledTimes(1);
);
it('form should be valid', () =>
component.registerForm.controls.name.setValue('sasd');
component.registerForm.controls.email.setValue('sadasd@asd.com');
component.registerForm.controls.phone.setValue('132456789');
component.registerForm.controls.password.setValue('qwerty');
component.registerForm.controls.confirmPassword.setValue('qwerty');
expect(component.registerForm.valid).toBeTruthy();
);
);
我似乎无法理解导致此问题的原因。已经为此阅读了几个文档和教程,但它似乎不起作用。
【问题讨论】:
【参考方案1】:Error: Expected validator to return Promise or Observable.
这意味着您错误地添加了多个验证器。 而不是这个:
this.registerForm = this.formBuilder.group(
name: ['', Validators.required],
email: ['', Validators.required, Validators.email],
phone: ['', Validators.required],
password: ['', Validators.required, Validators.minLength(6)],
confirmPassword: ['', Validators.required],
试试这个:
this.registerForm = this.formBuilder.group(
name: ['', Validators.required],
email: ['', [Validators.required, Validators.email]],
phone: ['', Validators.required],
password: ['', [Validators.required, Validators.minLength(6)]],
confirmPassword: ['', Validators.required],
注意如何在一个数组中提供多个验证器,而不仅仅是逗号分隔。
对于你的第二个错误,你想调用
expect(component.onSubmit).toHaveBeenCalledTimes(1);
代替
expect(component.registerForm).toHaveBeenCalledTimes(1);
【讨论】:
【参考方案2】:expect(component.onSubmit).toHaveBeenCalledTimes(1)
在下面的代码中替换上面的行,因为你想检查 onSubmit 方法而不是 component.registerForm
it('should call onSubmit method', () =>
spyOn(component, 'onSubmit');
el = fixture.debugElement.query(By.css('button')).nativeElement;
el.click();
expect(component.registerForm).toHaveBeenCalledTimes(1);
);
【讨论】:
以上是关于Angular 单元测试表单验证的主要内容,如果未能解决你的问题,请参考以下文章