I've some problems to tests component with FormGroupDirective
in viewProviders
.
Can't create mock of parent
and set empty formGroup.
My component:
@Component({
(...)
viewProviders: [
{
provide: ControlContainer, useExisting: FormGroupDirective
}
]
})
export class SomeNestedFormComponent implements OnInit {
form: FormGroup;
constructor(private fb: FormBuilder, private parent: FormGroupDirective) {}
ngOnInit() {
this.form = this.parent.form;
this.form.addControl('field', this.createSomeFormGroup());
}
}
Spec:
describe('SomeNestedFormComponent', () => {
let component: SomeNestedFormComponent;
let fixture: ComponentFixture<SomeNestedFormComponent>;
let formGroupDirective: Partial<FormGroupDirective>;
beforeEach(async(() => {
formGroupDirective = {
form: new FormGroup({})
};
TestBed.configureTestingModule({
imports: [
SharedModule,
FormsModule,
ReactiveFormsModule
],
declarations: [SomeNestedFormComponent],
providers: []
})
.overrideComponent(PermissionListComponent, {
set: {
viewProviders: [
{
provide: FormGroupDirective, useValue: formGroupDirective
}
]
}
})
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(SomeNestedFormComponent);
component = fixture.componentInstance;
component.ngOnInit();
fixture.detectChanges();
});
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
This throw: Error: formGroupName must be used with a parent formGroup directive. (...)
Try to handle FormGroupDirective
as a service with spyOn
, but it throws TypeError: this.form.addControl is not a function
describe('SomeNestedFormComponent', () => {
(...)
let fgdSpy: jasmine.SpyObj<SomeNestedFormComponent>;
beforeEach(async(() => {
const FGDirectiveSpy = jasmine.createSpyObj('FormGroupDirective', ['form', 'addControl']);
TestBed.configureTestingModule({
(...)
providers: [
{provide: FormGroupDirective, useValue: FGDirectiveSpy}
]
})
.compileComponents()
.then(() => {
fgdSpy = TestBed.get(FormGroupDirective);
(...)
});
Is there any way to test that component?
Let me share what i did on this scene.
Created mockFormGroup as like in my parent component and then created mock FormControlDirective as formGroupDirective to be used in useValue providers.
Finally assign parent component's form to mocked formGroup like below
component.parent.form = mockFormGroup;
It is essential to add FormControlDirective in providers to avoid the error No provider for FormControlDirective.
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
import { ReactiveFormsModule, FormGroupDirective, FormControlDirective, FormBuilder, ControlContainer, FormGroup, FormControl } from '@angular/forms';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
describe('MyComponent', () => {
let component: MyComponent;
let fixture: ComponentFixture<MyComponent>;
let formGroupDirective: FormControlDirective;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MyComponent ],
imports: [
HttpClientTestingModule,
ReactiveFormsModule
],
providers: [ FormGroupDirective,
{ provide: ControlContainer, useValue: formGroupDirective }
],
schemas: [NO_ERRORS_SCHEMA]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MyComponent);
component = fixture.componentInstance;
//mock parent formGroup
const mockFormGroup: FormGroup = new FormGroup({
});
//dummy formgroupDirective to avoid undefined addControl function
const formGroupDirective: FormGroupDirective = new FormGroupDirective([], []);
component.parent.form = mockFormGroup;
component.ngOnInit();
fixture.detectChanges();
});
it('should be created', () => {
expect(component).toBeTruthy();
});
});
Here is how I managed to fix the problem of injecting a FormGroupDirective.
My componet -
import {Component, Input, OnInit} from '@angular/core';
import {ControlContainer, FormControl, FormGroupDirective} from "@angular/forms";
@Component({
selector: 'app-checkbox',
templateUrl: './checkbox.component.html',
styleUrls: ['./checkbox.component.scss'],
viewProviders: [{provide: ControlContainer, useExisting: FormGroupDirective}]
})
export class CheckboxComponent implements OnInit {
@Input() controlName: string;
public formControl: FormControl;
constructor(private formGroupDirective: FormGroupDirective) {
}
ngOnInit(): void {
this.formControl = this.formGroupDirective.form.get(this.controlName) as FormControl;
}
}
The test -
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
import {CheckboxComponent} from './checkbox.component';
import {FormBuilder, FormGroupDirective, ReactiveFormsModule} from "@angular/forms";
describe('CheckboxComponent', () => {
let component: CheckboxComponent;
let fixture: ComponentFixture<CheckboxComponent>;
beforeEach(waitForAsync(() => {
const fb = new FormBuilder()
const formGroupDirective = new FormGroupDirective([], []);
formGroupDirective.form = fb.group({
test: fb.control(null)
});
TestBed.configureTestingModule({
declarations: [CheckboxComponent],
imports: [
ReactiveFormsModule
],
providers: [
FormGroupDirective,
FormBuilder,
{provide: FormGroupDirective, useValue: formGroupDirective}
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CheckboxComponent);
component = fixture.componentInstance;
component.controlName = 'test';
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