Jest console.error NG0303: Can't bind to 'formGroup' since it isn't a known property of 'form'

Viewed 914

I'm testing a component that has a reactive form with Jest and Angular 11. Tests seem to behave correctly, but this error message is flooding the console when I run the tests. These errors do NOT appear when I ng serve, only during test. (redacted some file names)

console.error NG0303: Can't bind to 'formGroup' since it isn't a known property of 'form'.
      at logUnknownPropertyError (../packages/core/src/render3/instructions/shared.ts:1117:11)
      at elementPropertyInternal (../packages/core/src/render3/instructions/shared.ts:999:9)
      at ɵɵproperty (../packages/core/src/render3/instructions/property.ts:42:5)
      at UnderTestComponent_Template (ng:/UnderTestComponent.js:308:9)
      at executeTemplate (../packages/core/src/render3/instructions/shared.ts:511:5)
      at refreshView (../packages/core/src/render3/instructions/shared.ts:369:7)
      at refreshComponent (../packages/core/src/render3/instructions/shared.ts:1716:7)

I know Jest has some issues with imports, f.e. I need to use relative imports or Jest will crash. I don't know if that's is related.

// Module for the component under test
@NgModule({
  declarations: [UnderTestComponent],
  imports: [
    CommonModule,
    SharedModule,
    ReactiveFormsModule,
    FormsModule,
    // ...
  ],
  exports: [UnderTestComponent],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  providers: [TranslatePipe],
})
export class UnderTestModule{}
<!-- Component under test HTML snippet -->
<form novalidate (ngSubmit)="submitForm()" [formGroup]="formRoot">
  <div id="exampleDiv" class="formMember">
    <internal-input
      formControlName="example"
      type="text"
      maxLength="10"
      [allowedCharacterPattern]="numberRegex"
      id="exampleId"
    >
      <internal-input-label for="exampleId">Example Number</internal-input-label>
      <internal-message [error]="true" *ngIf="msgs.example">
        Example Number {{ msgs.example }}
      </internal-message>
    </internal-input>
  </div>
  // ...
</form>
// Jest test snippet for the component under test
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { UnderTestComponent} from './under-test.component';
import { ApiService } from '../../../services/api-service/api.service';
import { FormBuilder } from '@angular/forms';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

describe('UnderTestComponent', () => {
  let component: UnderTestComponent;
  let fixture: ComponentFixture<UnderTestComponent>;
  const mockApiService = {
    toDoMethod: jest.fn(),
  };

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [UnderTestComponent],
      schemas: [CUSTOM_ELEMENTS_SCHEMA],
      providers: [
        FormBuilder,
        { provide: ApiService, useValue: mockApiService },
      ],
    }).compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(UnderTestComponent);
    component = fixture.componentInstance;
  });

  describe('form:', () => {
    it.only('example too short', () => {
      fixture.detectChanges();
      let example = component.formRoot.get('example');
      example.setValue('123456789');
      expect(example.invalid).toBeTruthy();
    });
  });
}

The errors don't show up with some tests, for example:

   it.only('ngOnInit should create a form with the correct structure', () => {
      expect(component.formRoot).toBeUndefined();
      component.ngOnInit();
      expect(component.formRoot.get('example')).toBeTruthy();
      expect(
        component.formRoot.get('groupExample').get('groupMemberExample')
      ).toBeTruthy();
    });
1 Answers

The TestBed module also needs to import the FormsModule. So in your test setup extend the module like this:

await TestBed.configureTestingModule({
    ...
    imports: [FormsModule, ReactiveFormsModule, ...]
})
Related