Karma + Ionic 4 - 没有名称的表单控件的值访问器
Karma + Ionic 4 - No value accessor for form control with name
我想知道如何用 karma 实现单元形式测试。
我已经实施了一个测试,但它总是给出以下错误:Error: No value accessor for form control with name: 'email'
signup.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';
import { IonicModule } from '@ionic/angular';
import { SignupPage } from './signup.page';
const routes: Routes = [{ path: '', component: SignupPage }];
@NgModule({
imports: [CommonModule, FormsModule, ReactiveFormsModule, IonicModule, RouterModule.forChild(routes)],
declarations: [SignupPage]
})
export class SignupPageModule {}
signup.page.html
<ion-header no-border>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/"></ion-back-button>
</ion-buttons>
<ion-title>
<img src="../../../../assets/logo-colored.png">
</ion-title>
<ion-buttons slot="end">
<div class="center-title-helper"></div>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-progress-bar [hidden]="true" type="indeterminate"></ion-progress-bar>
<img src="../../../../assets/logo-colored.png">
<h3 text-center>Criar Conta</h3>
<ion-list no-padding>
<form [formGroup]="signupForm" (ngSubmit)="submitSignupForm()">
<ion-item [ngClass]="{ 'ion-touched ion-invalid' : emailControl.invalid }">
<ion-label position="floating">E-mail</ion-label>
<ion-input formControlName="email" type="e-mail"></ion-input>
</ion-item>
<div *ngIf="emailControl.invalid" padding-start>
<ion-note *ngIf="emailControl.hasError('required')" color="danger">
Insira o seu endereço de e-mail
</ion-note>
</div>
<ion-item [ngClass]="{ 'ion-touched ion-invalid' : passwordControl.invalid }">
<ion-label position="floating">Senha</ion-label>
<ion-input clearOnEdit="false" formControlName="password" type="password"></ion-input>
</ion-item>
<div *ngIf="passwordControl.invalid" padding-start>
<ion-note *ngIf="passwordControl.hasError('required')" color="danger">
Insira a sua senha
</ion-note>
</div>
<ion-button [hidden]="true">Fake Button</ion-button>
</form>
</ion-list>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-button expand="block" shape="round" (click)="submitSignupForm()">Criar Conta</ion-button>
</ion-toolbar>
</ion-footer>
signup.page.ts
import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-signup',
templateUrl: './signup.page.html',
styleUrls: ['./signup.page.scss'],
})
export class SignupPage implements OnInit {
signupForm: FormGroup;
constructor() { }
ngOnInit() {
this.signupForm = new FormGroup({
email: new FormControl(''),
password: new FormControl(''),
});
}
submitSignupForm() {
if (this.validateForm) {
}
}
get validateForm(): boolean {
if (this.emailControl.value === '') { this.emailControl.setErrors({ required: true }); }
if (this.passwordControl.value === '') { this.passwordControl.setErrors({ required: true }); }
return this.signupForm.valid;
}
get emailControl(): AbstractControl {
return this.signupForm.controls['email'];
}
get passwordControl(): AbstractControl {
return this.signupForm.controls['password'];
}
}
signup.page.spec.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SignupPage } from './signup.page';
describe('SignupPage', () => {
let component: SignupPage;
let fixture: ComponentFixture<SignupPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SignupPage ],
imports: [
FormsModule,
ReactiveFormsModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SignupPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
我 运行 ng test
命令时的完整日志
Error: No value accessor for form control with name: 'email'
at _throwError (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:2144:1)
at setUpControl (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:2054:1)
at FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective.addControl (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:5281:1)
at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName._setUpControl (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:5882:1)
at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName.ngOnChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:5803:1)
at checkAndUpdateDirectiveInline (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:22085:1)
at checkAndUpdateNodeInline (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:23353:1)
at checkAndUpdateNode (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:23315:1)
at debugCheckAndUpdateNode (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:23949:1)
at debugCheckDirectivesFn (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:23909:1)
我通过导入 IonicModule
和 RouterTestingModule
解决了这个问题。
测试class是这样的。
signup.page.spec.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { IonicModule } from '@ionic/angular';
import { SignupPage } from './signup.page';
describe('SignupPage', () => {
let component: SignupPage;
let fixture: ComponentFixture<SignupPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SignupPage ],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
ReactiveFormsModule,
RouterTestingModule,
IonicModule
],
providers: [FormBuilder],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SignupPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
对我来说,当我将 RouterTestingModule 作为 RouterTestingModule.withRoutes([]) 导入数组时它起作用了。
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SignupPage } from './signup.page';
import { RouterTestingModule } from '@angular/router/testing';
describe('SignupPage', () => {
let component: SignupPage;
let fixture: ComponentFixture<SignupPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SignupPage ],
imports: [
FormsModule,
ReactiveFormsModule,
RouterTestingModule.withRoutes([])
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SignupPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
我想知道如何用 karma 实现单元形式测试。
我已经实施了一个测试,但它总是给出以下错误:Error: No value accessor for form control with name: 'email'
signup.module.ts
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';
import { IonicModule } from '@ionic/angular';
import { SignupPage } from './signup.page';
const routes: Routes = [{ path: '', component: SignupPage }];
@NgModule({
imports: [CommonModule, FormsModule, ReactiveFormsModule, IonicModule, RouterModule.forChild(routes)],
declarations: [SignupPage]
})
export class SignupPageModule {}
signup.page.html
<ion-header no-border>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/"></ion-back-button>
</ion-buttons>
<ion-title>
<img src="../../../../assets/logo-colored.png">
</ion-title>
<ion-buttons slot="end">
<div class="center-title-helper"></div>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content padding>
<ion-progress-bar [hidden]="true" type="indeterminate"></ion-progress-bar>
<img src="../../../../assets/logo-colored.png">
<h3 text-center>Criar Conta</h3>
<ion-list no-padding>
<form [formGroup]="signupForm" (ngSubmit)="submitSignupForm()">
<ion-item [ngClass]="{ 'ion-touched ion-invalid' : emailControl.invalid }">
<ion-label position="floating">E-mail</ion-label>
<ion-input formControlName="email" type="e-mail"></ion-input>
</ion-item>
<div *ngIf="emailControl.invalid" padding-start>
<ion-note *ngIf="emailControl.hasError('required')" color="danger">
Insira o seu endereço de e-mail
</ion-note>
</div>
<ion-item [ngClass]="{ 'ion-touched ion-invalid' : passwordControl.invalid }">
<ion-label position="floating">Senha</ion-label>
<ion-input clearOnEdit="false" formControlName="password" type="password"></ion-input>
</ion-item>
<div *ngIf="passwordControl.invalid" padding-start>
<ion-note *ngIf="passwordControl.hasError('required')" color="danger">
Insira a sua senha
</ion-note>
</div>
<ion-button [hidden]="true">Fake Button</ion-button>
</form>
</ion-list>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-button expand="block" shape="round" (click)="submitSignupForm()">Criar Conta</ion-button>
</ion-toolbar>
</ion-footer>
signup.page.ts
import { Component, OnInit } from '@angular/core';
import { AbstractControl, FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-signup',
templateUrl: './signup.page.html',
styleUrls: ['./signup.page.scss'],
})
export class SignupPage implements OnInit {
signupForm: FormGroup;
constructor() { }
ngOnInit() {
this.signupForm = new FormGroup({
email: new FormControl(''),
password: new FormControl(''),
});
}
submitSignupForm() {
if (this.validateForm) {
}
}
get validateForm(): boolean {
if (this.emailControl.value === '') { this.emailControl.setErrors({ required: true }); }
if (this.passwordControl.value === '') { this.passwordControl.setErrors({ required: true }); }
return this.signupForm.valid;
}
get emailControl(): AbstractControl {
return this.signupForm.controls['email'];
}
get passwordControl(): AbstractControl {
return this.signupForm.controls['password'];
}
}
signup.page.spec.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SignupPage } from './signup.page';
describe('SignupPage', () => {
let component: SignupPage;
let fixture: ComponentFixture<SignupPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SignupPage ],
imports: [
FormsModule,
ReactiveFormsModule
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SignupPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
我 运行 ng test
命令时的完整日志
Error: No value accessor for form control with name: 'email'
at _throwError (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:2144:1)
at setUpControl (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:2054:1)
at FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective.addControl (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:5281:1)
at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName._setUpControl (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:5882:1)
at FormControlName.push../node_modules/@angular/forms/fesm5/forms.js.FormControlName.ngOnChanges (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/forms/fesm5/forms.js:5803:1)
at checkAndUpdateDirectiveInline (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:22085:1)
at checkAndUpdateNodeInline (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:23353:1)
at checkAndUpdateNode (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:23315:1)
at debugCheckAndUpdateNode (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:23949:1)
at debugCheckDirectivesFn (http://localhost:9876/_karma_webpack_/webpack:/node_modules/@angular/core/fesm5/core.js:23909:1)
我通过导入 IonicModule
和 RouterTestingModule
解决了这个问题。
测试class是这样的。
signup.page.spec.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { IonicModule } from '@ionic/angular';
import { SignupPage } from './signup.page';
describe('SignupPage', () => {
let component: SignupPage;
let fixture: ComponentFixture<SignupPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SignupPage ],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [
ReactiveFormsModule,
RouterTestingModule,
IonicModule
],
providers: [FormBuilder],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SignupPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
对我来说,当我将 RouterTestingModule 作为 RouterTestingModule.withRoutes([]) 导入数组时它起作用了。
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SignupPage } from './signup.page';
import { RouterTestingModule } from '@angular/router/testing';
describe('SignupPage', () => {
let component: SignupPage;
let fixture: ComponentFixture<SignupPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SignupPage ],
imports: [
FormsModule,
ReactiveFormsModule,
RouterTestingModule.withRoutes([])
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SignupPage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});