Angular - Forcing a reactive form to be valid in a unit test

Viewed 8265

I am using Angular v4.4.4. In a component, after a button is clicked in the template, the form is saved assuming the reactive form is valid. Something like (pseudo-code):

public onSave(): void {
    if (this.myForm.valid) {
        this._createFoo();
    }
}

private _createFoo(): void {
    this._fooService.createItem(this.foo).subscribe(result => {
        // stuff happens...
    });
}

In the related unit test I need to force the form to be valid so I can confirm the service is being called. Something like this:

it('should create Foo', () => {
    const spy = spyOn(_fooService, 'createItem').and.callThrough();
    component.foo = new Foo();
    fixture.detectChanges();
    const bookButton = fixture.debugElement.query(By.css('#bookButton'));
    expect(bookButton !== null).toBeTruthy('missing Book button');
    bookButton.triggerEventHandler('click', null);
    expect(spy).toHaveBeenCalled();
});

This will fail because myForm is never set as valid.

In this particular case I do not want to give every input in the form a value. I just need to watch and see if the service subscription occurs. How can I force the form to be valid?

3 Answers

Why not just clear the validators list?

// If there are any async validators
//
this.myForm.clearAsyncValidators();
// If there are any normal validators
//
this.myForm.clearValidators();
// Doing the validation on all the controls to put them back to valid
//
this.formGroup.updateValueAndValidity();

This will ensure your form has no validators, thus being valid.

If someone is still struggling with this:

As @realappie answer suggests, we should clear all sync/async validators. But the validators in most cases are on the controls and not the form itself . So, just loop all the controls perform this operation on each control.

From the test file it should look like:

const controls = component.myForm.controls;

for (const control in controls) {
    // Clear sync validators - use clearAsyncValidators() for async
    // validators
    controls[control].clearValidators();
    // should update just the control and not everything
    controls[control].updateValueAndValidity({ onlySelf: true });
}
component.myForm.updateValueAndValidity();

using only javascript, you can do:

      Object.defineProperty(comp.editForm, 'valid', {
        get: () => true
      });

to override the getter, to always return true.

Related