Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Karma formGroup expects a FormGroup instance. Please pass one in

I understand the root of the error, the component I'm testing requires a FormGroup to be passed into it's @Input() form: FormGroup. I just can't figure out how to pass one in when testing this component.

There error occurs in my before each function when I call fixture.detectChanges() so the form must be passed in before that point

my current code get's the error group is not defined:

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import {
    ReactiveFormsModule,
    FormsModule,
    Validators,
    FormBuilder
} from '@angular/forms';
import { StaticComponent } from '../../firewall/static/static.component';

describe('StaticComponent', () => {
    let component: StaticComponent;
    let fixture: ComponentFixture<StaticComponent>;

    beforeEach(
        async(() => {
            TestBed.configureTestingModule({
                declarations: [
                    StaticComponent
                ],
                imports: [
                    CommonModule,
                    ReactiveFormsModule,
                    FormsModule
                ],
                providers: [
                    NetworkService,
                    NetworkValidator,
                    HostNameValidator,
                    NotificationsService
                ]
            }).compileComponents();
        })
    );

    beforeEach(() => {
        fixture = TestBed.createComponent(StaticComponent);
        component = fixture.componentInstance;
        component.ruleForm = FormBuilder.group({
            chain: ['chain', Validators.required],
            ip: [
                '',
                Validators.required,
                this.networkValidator.validateNetwork('ip')
            ],
            action: ['action', Validators.required]
        });
        fixture.detectChanges();
    });

    fit('should be created', () => {
        expect(component).toBeTruthy();
    });
});

How do I pass in a pre-fab form to my @Input of the component during the test? I cant seem to provide FormBuilder correctly

like image 416
FussinHussin Avatar asked Feb 07 '18 17:02

FussinHussin


2 Answers

This is a test component spec that I came up with for you. Notice the mocked FormBuilder that I have added and the way that I have provided it in the spec.

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TestingComponent } from './testing.component';
import { FormBuilder, Validators } from '@angular/forms';

describe('TestingComponent', () => {
  let component: TestingComponent;
  let fixture: ComponentFixture<TestingComponent>;
  const formBuilder: FormBuilder = new FormBuilder();

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ TestingComponent ],
      providers: [ { provide: FormBuilder, useValue: formBuilder } ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TestingComponent);
    component = fixture.componentInstance;
    component.ruleForm = formBuilder.group({
      chain: ['chain', Validators.required],
            ip: [
                '',
                Validators.required
            ],
            action: ['action', Validators.required]
    });
    fixture.detectChanges();
  });

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

This is my test component in case you need to refer to that.

import { Component, OnInit } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-testing',
  templateUrl: './testing.component.html',
  styleUrls: ['./testing.component.css']
})
export class TestingComponent implements OnInit {
  ruleForm: FormGroup = new FormGroup({});
  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.ruleForm = this.formBuilder.group({
      chain: ['chain', Validators.required],
            ip: [
                '',
                Validators.required
            ],
            action: ['action', Validators.required]
    });
  }
}
like image 85
R. Richards Avatar answered Nov 15 '22 15:11

R. Richards


I ran into the same error after running detectChanges. My component's FormGroup, however, was initiated in ngOnInit, not passed as an input.

The solution for my case was wrapping the component under test in a wrapper component. This process will force Angular to put the component under test through the lifecycle events e.g. ngOnInit that you would otherwise have to invoke yourself. It also feels like the right way to test a component with inputs. It's a little more boilerplate, but this method mimics angular's natural behavior more closely.

Here is a reproduction of code from this Medium article

  describe('ComponentUnderTestComponent', () => {
    let testHostComponent: TestHostComponent;
    let testHostFixture: ComponentFixture<TestHostComponent>;

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            declarations: [ComponentUnderTestComponent, TestHostComponent]
    }).compileComponents();
    }));

    beforeEach(() => {
    testHostFixture = TestBed.createComponent(TestHostComponent);
    testHostComponent = testHostFixture.componentInstance;
    testHostFixture.detectChanges();
  });

  it('should show TEST INPUT', () => {
     expect(testHostFixture.nativeElement.querySelector('div').innerText)
         .toEqual('TEST INPUT');
  });

  @Component({
    selector: `host-component`,
    template: `<component-under-test input="test input"></component-under-test>`
  })
  class TestHostComponent {
  }
});
like image 1
jjr4826 Avatar answered Nov 15 '22 14:11

jjr4826