Angular 单元测试表单验证

标签 angular forms unit-testing validation

我正在学习 angular 8,并且正在使用 Karma 进行单元测试。我创建了一个可以正常工作的基本注册表单,但我在测试中遇到了问题。

经过测试,我遇到了 2 次失败

RegisterComponent > form should be valid Error: Expected validator to return Promise or Observable.





RegisterComponent > should call onSubmit method Error: : Expected a spy, but got FormGroup({ validator: Function, asyncValidator: null, _onCollectionChange: Function, pristine: true, touched: false, _onDisabledChange: [ ], controls: Object({ name: FormControl({ validator: Function, asyncValidator: null, _onCollectionChange: Function, pristine: true, touched: false, _onDisabledChange: [ Function ], _onChange: [ Function ], _pendingValue: '', value: '', status: 'INVALID', errors: Object({ required: true }), valueChanges: EventEmitter({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, __isAsync: false }), statusChanges: EventEmitter({ _isScalar: false, observers: [ ], closed: false, isStopped: false, hasError: false, thrownError: null, __isAsync: false }), _parent: }), email: FormControl({ validator: Function, asyncValidator: Function, _onCollectionChange: Function, pristine: true, touched: false, _onDisabledChange: [ Function ], _onChange: [ Function ], _pendingValue: '', value: '' .... Usage: 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();
  });
});

我似乎无法理解是什么导致了这个问题。已经为此浏览了几个文档和教程,但它似乎不起作用。

最佳答案

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

关于Angular 单元测试表单验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57457293/

相关文章:

javascript - Angular Testing function.bind()

Angular 2 : separation all services to one module

angular - 如何在模板驱动的表单中为 ngModelGroup 添加自定义验证

javascript - 使用 javascript 将多个用户表单输入存储在关联数组中

java - 使用计时器自动提交测试页面中的单选按钮

java - 使用模拟位置测试应用程序时出现 Android 错误

java - http url : 401 Unauthorized 的 HTTP 失败响应

angular - 可以使用 Ionic 2 更改手机和平板电脑的布局吗?

javascript - 单击提交表单链接,包括表单参数字段

node.js - "node --debug"和 "node --debug-brk"无效