I am working with Formly and created a couple Custom Templates. The only code included in the component is a call to a general error handling service, so there is really almost nothing to test other than that the component can be created. I am using only Jest for unit testing, but cannot figure out what I need to include to have the component compile successfully.
The error I am getting is: TypeError: Cannot read property 'formControl' of undefined. I am not sure what I am missing in my test.
For the simplest component (mainly styling and a directive - removed for now), I have the following:
Component:
@Component({
selector: 'my-formly-field-input',
templateUrl: './formly-field-input.component.html',
styleUrls: ['./formly-field-input.component.scss']
})
export class FormlyFieldInputComponent extends FieldType {
constructor(private formErrorService: FormErrorHandlerService) {
super();
}
getError(formItem: FormControl | FormGroup | FormArray): string {
return this.formErrorService.getFormError(formItem);
}
}
View:
<mat-form-field [floatLabel]="'always'"
class="w-100"
[appearance]="'fill'">
<mat-label>{{field.templateOptions.label}}</mat-label>
<input matInput
[formControl]="formControl"
[type]="field.templateOptions.type || 'text'"
[step]="field.templateOptions.step || 1"
[max]="field.templateOptions.max || undefined"/>
<mat-error *ngIf="formControl.errors">
{{getError(formControl)}}
</mat-error>
</mat-form-field>
Unit Test:
describe('FormlyFieldInputComponent', () => {
let component: FormlyFieldInputComponent;
let fixture: ComponentFixture<FormlyFieldInputComponent>;
const formHelperServiceStub: Partial<FormErrorHandlerService> = {
getFormError: (formItem) => 'Error Happened'
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
FormlyFieldInputComponent
],
imports: [
MyHelpersModule,
BrowserAnimationsModule,
FormlyModule.forRoot(),
FormlyMaterialModule,
MatFormFieldModule,
MatInputModule,
ReactiveFormsModule,
],
providers: [
{ provide: FormErrorHandlerService, useValue: formHelperServiceStub }
],
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FormlyFieldInputComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
Thanks in advance!!
Faced with a similar issue. I applied the approach with hosting form inside a mock component. I worked with a custom component, but I think it will be helpful:
@Component({
selector: 'app-test-cmp',
template: `
<form [formGroup]="form">
<formly-form [model]="{}" [fields]="fields" [options]="{}" [form]="form"></formly-form>
</form>`
})
class MockFormComponent {
form = new FormGroup({ });
fields: FormlyFieldConfig[] = [{
wrappers: ['your custom wrapper name'],
defaultValue: {}
}];
}
Next, I registered custom wrapper in formly module:
TestBed.configureTestingModule({
imports: [
... Your dependencies will be here,
FormlyModule.forRoot({
wrappers: [{'your custom wrapper name', component: FormlyFieldInputComponent}]
})
]
})
and initialized the component:
beforeEach(() => {
fixture = TestBed.createComponent(MockFormComponent);
mockComponent = fixture.componentInstance;
fixture.detectChanges();
component = fixture.debugElement.query(By.directive(FormlyFieldInputComponent)).componentInstance;
});