I am testing my angular code using Jasmine. I have imported everything but still getting errors. These are the 2 errors:
NullInjectorError: R3InjectorError(DynamicTestModule)[FormBuilder -> FormBuilder]: NullInjectorError: No provider for FormBuilder!
Expected undefined to be truthy.
These errors are on multiple ponent. I have attached example of one ponent with these errors. How can I solve it ? (I am a beginner so please try to answer it in the simplest manner)
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './appponent';
import {FormsModule } from '@angular/forms';
import { SortPipe } from './sort.pipe';
import { CustomPipeComponent } from './custom-pipe/custom-pipeponent';
import { CustpipeComponent } from './custpipe/custpipeponent';
import { RideFilterPipePipe } from './ride-filter-pipe.pipe';
import { ReactFormComponent } from './react-form/react-formponent';
import { TemplateDrivenFormComponent } from './template-driven-form/template-driven-formponent';
import { EmailValidator } from './template-driven-form/emailValidator';
@NgModule({
declarations: [
AppComponent,
SortPipe,
CustomPipeComponent,
CustpipeComponent,
RideFilterPipePipe,
ReactFormComponent,
TemplateDrivenFormComponent,
EmailValidator
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
appponent.spec.ts
import { TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './appponent';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule,
ReactiveFormsModule
],
declarations: [
AppComponent
],
})pileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixtureponentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'carpool'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixtureponentInstance;
expect(app.title).toEqual('carpool');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const piled = fixture.nativeElement as HTMLElement;
expect(piled.querySelector('.content span')?.textContent).toContain('carpool app is running!');
});
});
reactFormComponent.html
<div class="login-p">
<div class="container">
<div class="outer-box">
<h3 class="title">Reactive form</h3>
<form [formGroup]="registerForm">
<div class="form-group">
<label class="">Name</label>
<input class=" form-control" type="text" formControlName="firstName">
<p *ngIf="(registerForm.get('firstName')?.dirty ||
registerForm.get('firstName')?.touched ) &&
registerForm.get('firstName')?.errors "
class="alert alert-danger">This is required</p>
</div>
<div class="form-group">
<label class="">email</label>
<input class=" form-control" type="email" formControlName="email">
<p *ngIf="(registerForm.get('email')?.dirty ||
registerForm.get('email')?.touched ) &&
registerForm.get('email')?.errors "
class="alert alert-danger">invalid</p>
</div>
<div class="form-group">
<fieldset formGroupName="address">
<label class="">Steet</label>
<input class=" form-control" type="text" formControlName="street">
<label class="">Zip</label>
<input class=" form-control" type="text" formControlName="zip">
<label class="">City</label>
<input class=" form-control" type="text" formControlName="city">
</fieldset>
</div>
<button type="submit" [disabled]="!registerForm.valid" class="btn btn-primary" (click)="subForm()">Submit</button>
</form>
<div [hidden]="!submittedForm">
<p>Name: {{registerForm.get('firstName')?.value}}</p>
<p>Name: {{registerForm.get('email')?.value}}</p>
<p>Street: {{registerForm.get('address.street')?.value}}</p>
<p>City: {{registerForm.get('address.city')!.value}}</p>
<p>zip: {{registerForm.get('address.zip')!.value}}</p>
</div>
</div>
</div>
</div>
reactFormComponent.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-react-form',
templateUrl: './react-formponent.html',
styleUrls: ['./react-formponent.css']
})
export class ReactFormComponent implements OnInit {
registerForm!:FormGroup;
submittedForm!:boolean;
constructor(private formBuilder:FormBuilder) {}
ngOnInit(): void {
this.registerForm=this.formBuilder.group({
firstName: ['',Validators.required],
email: ['', validateEmail],
address: this.formBuilder.group({
street:[],
zip:[],
city:['',Validators.required]
})
});
}
subForm() {
this.submittedForm=true;
console.log(this.registerForm);
}
}
function validateEmail(eid:FormControl):any {
let email_regex=/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return email_regex.test(eid.value)?null : {
emailInvalid: {
message: 'Invalid Format'
}
};
}```
I am testing my angular code using Jasmine. I have imported everything but still getting errors. These are the 2 errors:
NullInjectorError: R3InjectorError(DynamicTestModule)[FormBuilder -> FormBuilder]: NullInjectorError: No provider for FormBuilder!
Expected undefined to be truthy.
These errors are on multiple ponent. I have attached example of one ponent with these errors. How can I solve it ? (I am a beginner so please try to answer it in the simplest manner)
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.ponent';
import {FormsModule } from '@angular/forms';
import { SortPipe } from './sort.pipe';
import { CustomPipeComponent } from './custom-pipe/custom-pipe.ponent';
import { CustpipeComponent } from './custpipe/custpipe.ponent';
import { RideFilterPipePipe } from './ride-filter-pipe.pipe';
import { ReactFormComponent } from './react-form/react-form.ponent';
import { TemplateDrivenFormComponent } from './template-driven-form/template-driven-form.ponent';
import { EmailValidator } from './template-driven-form/emailValidator';
@NgModule({
declarations: [
AppComponent,
SortPipe,
CustomPipeComponent,
CustpipeComponent,
RideFilterPipePipe,
ReactFormComponent,
TemplateDrivenFormComponent,
EmailValidator
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule,
ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
app.ponent.spec.ts
import { TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.ponent';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule,
ReactiveFormsModule
],
declarations: [
AppComponent
],
}).pileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.ponentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'carpool'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.ponentInstance;
expect(app.title).toEqual('carpool');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const piled = fixture.nativeElement as HTMLElement;
expect(piled.querySelector('.content span')?.textContent).toContain('carpool app is running!');
});
});
reactFormComponent.html
<div class="login-p">
<div class="container">
<div class="outer-box">
<h3 class="title">Reactive form</h3>
<form [formGroup]="registerForm">
<div class="form-group">
<label class="">Name</label>
<input class=" form-control" type="text" formControlName="firstName">
<p *ngIf="(registerForm.get('firstName')?.dirty ||
registerForm.get('firstName')?.touched ) &&
registerForm.get('firstName')?.errors "
class="alert alert-danger">This is required</p>
</div>
<div class="form-group">
<label class="">email</label>
<input class=" form-control" type="email" formControlName="email">
<p *ngIf="(registerForm.get('email')?.dirty ||
registerForm.get('email')?.touched ) &&
registerForm.get('email')?.errors "
class="alert alert-danger">invalid</p>
</div>
<div class="form-group">
<fieldset formGroupName="address">
<label class="">Steet</label>
<input class=" form-control" type="text" formControlName="street">
<label class="">Zip</label>
<input class=" form-control" type="text" formControlName="zip">
<label class="">City</label>
<input class=" form-control" type="text" formControlName="city">
</fieldset>
</div>
<button type="submit" [disabled]="!registerForm.valid" class="btn btn-primary" (click)="subForm()">Submit</button>
</form>
<div [hidden]="!submittedForm">
<p>Name: {{registerForm.get('firstName')?.value}}</p>
<p>Name: {{registerForm.get('email')?.value}}</p>
<p>Street: {{registerForm.get('address.street')?.value}}</p>
<p>City: {{registerForm.get('address.city')!.value}}</p>
<p>zip: {{registerForm.get('address.zip')!.value}}</p>
</div>
</div>
</div>
</div>
reactFormComponent.ts
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'app-react-form',
templateUrl: './react-form.ponent.html',
styleUrls: ['./react-form.ponent.css']
})
export class ReactFormComponent implements OnInit {
registerForm!:FormGroup;
submittedForm!:boolean;
constructor(private formBuilder:FormBuilder) {}
ngOnInit(): void {
this.registerForm=this.formBuilder.group({
firstName: ['',Validators.required],
email: ['', validateEmail],
address: this.formBuilder.group({
street:[],
zip:[],
city:['',Validators.required]
})
});
}
subForm() {
this.submittedForm=true;
console.log(this.registerForm);
}
}
function validateEmail(eid:FormControl):any {
let email_regex=/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return email_regex.test(eid.value)?null : {
emailInvalid: {
message: 'Invalid Format'
}
};
}```
Share
Improve this question
edited Feb 17, 2022 at 8:02
Anurag Srivastava
14.4k4 gold badges36 silver badges45 bronze badges
asked Feb 17, 2022 at 4:42
muskaan sharmamuskaan sharma
1772 gold badges5 silver badges12 bronze badges
4 Answers
Reset to default 3The error indicates the test module created in app.ponent.spec.ts
cannot find the provider for FormBuilder
.
FormBuilder
is defined in the FormsModule
. You will notice that it is imported in AppModule
(which is why your app piles and runs) but it is not imported in configureTestingModule
in app.ponent.spec.ts
.
Fix:
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule,
FormsModule, // << ----- add this line
ReactiveFormsModule
],
Not in the app.ponent.spec.ts
, but in <your-ponent-name>.spec.ts
you've got to add those:
imports: [
FormsModule,
ReactiveFormsModule,
],
providers: [<your-providers>],
declarations: [<your-ponent-name>],
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule,
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule,
FormsModule, // << ----- add this line
ReactiveFormsModule // You should add this too
],
This will solve the issue with below code in test...
imports: [
FormsModule,
ReactiveFormsModule,
],
providers: [FormBuilder],
But after that I also got different error
Error: NG0204: Can't resolve all parameters for FormGroup: (?, ?, ?).
Referring to this, I have later on opted to include this in my "tsconfig.spec.json" file. I am using Angular 14. It appear I need to refactor the application code itself, but for now I choose to not do it and set this in test tsconfig file instead.
"extends": "./tsconfig.json",
"pilerOptions": {
"useDefineForClassFields": false
},
Posting these 2 separate solution as some might encounter these chain of error too... hope this help!