I would like to know how to implement unit form tests with karma.
I've implemented a test but it always gives the following error: 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();
});
});
Full log when I run the ng test
command
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)
I fixed this error by adding the name="fieldName" ngDefaultControl attributes to the element that carries the [(ngModel)] attribute. I had the same problem and the issue was that my child component had an @input named formControl .
When you get the error No value accessor for form control with unspecified name attribute , there are generally two things that possibly has gone wrong: You are using ngModel with a third party control that doesn't register a NG_VALUE_ACCESSOR . In this case you need to use ngDefaultControl on the element.
I was able to resolve this problem by importing IonicModule
and RouterTestingModule
.
The test class was this way.
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();
});
});
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