I am trying to test a multistep form that I've created. For each step I'm passing in a form group name then calling FormGroupDirective.control.get in ngOnInit to get the formGroup used in that particular component.
Here's my step-one component setup.
export class StepOneComponent implements OnInit {
stepForm!: FormGroup;
billingRequired = false;
@Input() formGroupName!: string;
@Input() formHeading: string;
constructor(private rootFormGroup: FormGroupDirective, private formService: FormService) { }
ngOnInit(): void {
this.stepForm = this.rootFormGroup.control.get(this.formGroupName) as FormGroup;
}
toggle() {
this.formService.billingToggle();
}
}
And the form initialized in my formService
multiStepForm: FormGroup = this.fb.group({
orgInformation: this.fb.group({
name: ['', [Validators.required]],
address: ['', [Validators.required]],
country: ['', [Validators.required]],
city: ['', [Validators.required]],
state: ['', [Validators.required]],
zip: ['', [Validators.required]],
contactFirstName: ['', [Validators.required]],
contactMiddleName: [''],
contactLastName: ['', [Validators.required]],
contactSuffix: [''],
contactEmail: ['', [Validators.required, Validators.email]],
contactPhone: ['', [Validators.required, Validators.minLength(10)]],
contactExt: [''],
}),
billingInformation: this.fb.group({
cardNumber: ['', [Validators.required]],
expiration: ['', [Validators.required]],
cvv: ['', [Validators.required, Validators.minLength(3)]],
cardName: ['', [Validators.required]],
})
})
For the test I am trying to just get the basic setup figured out. Despite setting up a mock formGroup for stepForm, I keep getting NG01052: formGroup expects a FormGroup instance. Please pass one in.
Here's my test so far
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { StepOneComponent } from './step-one.component';
import { FormControl, FormGroup, FormGroupDirective, Validators } from '@angular/forms';
import { FormService } from 'src/app/services/form/formservice.service';
describe('StepOneComponent', () => {
let component: StepOneComponent;
let fixture: ComponentFixture<StepOneComponent>;
let service: FormService;
const formgroupstub = {
control: {
get: jasmine.createSpy('get')
}
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [StepOneComponent],
providers: [
{ provide: FormGroupDirective, useValue: formgroupstub },
]
}).compileComponents();
fixture = TestBed.createComponent(StepOneComponent);
component = fixture.componentInstance;
service = TestBed.inject(FormService);
component.formGroupName = 'orgInformation';
component.stepForm = new FormGroup({
orgInformation: new FormGroup({
name: new FormControl('', Validators.required),
}),
});
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
I'm trying to mock the formGroupDirective properly so I can test this component, but I can't figure out how to do it.
You most likely need to add ReactiveFormsModule
to the imports
array.
imports: [
StepOneComponent,
ReactiveFormsModule,
],
But that's most likely not the main issue.
The main issue is that we are mocking stepForm
for it to be overridden in the ngOnInit
. The first fixture.detectChanges
is when ngOnInit
is called.
So we assign a correct value to stepForm
only for it to be overridden in the fixture.detectChanges()
call where ngOnInit
is called and assigns it to the mock service's value. The mock service value is returning undefined
at the moment.
To potentially fix it, we could try something like:
component.formGroupName = 'orgInformation';
// Make the get of the stub return the form value for it to be populated
// in the ngOnInit.
formgroupstub.control.get.and.returnValue(new FormGroup({
name: new FormControl('', Validators.required),
}),
}));
// Now call fixture.detectChanges() which will call ngOnInit
fixture.detectChanges();