angulartestingangular-reactive-formsformbuilderangular9

How to mock a FormBuilder for Angular Component Unit Test


I am working in an Angular 9 project.

I have a component that is accepting a formBuilder as an input from a Parent Component. This is my Child component (the one I am testing):

export class ChildComponent implements OnInit {
  @Input() parentForm: FormGroup;  //this is coming from the parentComponent

  ngOnInit(): void {
    if (this.parentForm) {
      this.filteredSelectables = this.parentForm
        .get("recipientTypes")
        ...
    }
  }
...

I am wanting to write tests for this component, but I need to create a form that the test can use (or I need to mock the parent component and return the form I want?)

I have added FormBuilder to the testBed providers, but I still can't figure out how to make a mock form that I can test with. The 'should create' test is passing, but I can't test anything else because parentForm can't be null for them. Here's my current test:

describe("ChildComponent", () => {
  let component: ChildComponent;
  let fixture: ComponentFixture<ChildComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ChildComponent, MatAutocomplete],
      providers: [FormBuilder],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
    })
      .compileComponents()
      .then(() => {
        fixture = TestBed.createComponent(ChildComponent);
        component = fixture.componentInstance;
      });
  }));

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

  it("should create", () => {
    expect(component).toBeTruthy();
  });
...

I've tried creating the form like this:

component.parentForm = FormBuilder.group({
      recipientTypes: new FormControl(
        {
          value: ["mock"],
          disabled: true
        },
        Validators.required
      )
    });

and adding it to either the beforeEach() or even inside the actual test. But I get an errs.

I thought that maybe I need to mock the parentComponent and make it send a formBuilder? Here's my parent component:

export class ParentComponent implements OnInit, OnDestroy {
  parentForm: FormGroup;

  constructor(
    private router: Router,
    private formBuilder: FormBuilder
  ) {}

  ngOnInit() {
    this.setFormTemplate();
  }

  setFormTemplate() {
    this.templateForm = this.formBuilder.group({
      name: new FormControl(
        {
          value: this.name,
          disabled: true
        },
        Validators.required
      ),
      recipientTypes: new FormControl(
        {
          value: this.recipientTypes,
          disabled: true
        },
        Validators.required
      )
    });
  }
...

How can I make a formBuilder for my tests?


Solution

  • Try!:

    import { FormBuilder } from '@angular/forms';
    ....
    describe("ChildComponent", () => {
      let component: ChildComponent;
      let fixture: ComponentFixture<ChildComponent>;
      let formBuilder: FormBuilder;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [ChildComponent, MatAutocomplete],
          providers: [FormBuilder], // add this as a provider
          schemas: [CUSTOM_ELEMENTS_SCHEMA]
        })
          .compileComponents()
          .then(() => {
            fixture = TestBed.createComponent(ChildComponent);
            component = fixture.componentInstance;
          });
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(ChildComponent);
        component = fixture.componentInstance;
        formBuilder = TestBed.inject(FormBuilder); // get a handle on formBuilder
        // add the mock data here
        component.parentForm = formBuilder.group({ 
          recipientTypes: new FormControl(
            {
              value: ["mock"],
              disabled: true
            },
            Validators.required
          )
        });
        // this fixture.detectChanges will kick off the ngOnInit
        fixture.detectChanges();
      });
    
      it("should create", () => {
        expect(component).toBeTruthy();
      });