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

4

26

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?

Bulimia answered 4/10, 2017 at 20:5 Comment(5)
In this case, you should really create a unit test for the service and one for the component, so that they are separate. The component test should give a valid value and check the subscription, and the Service test should make sure the request is going throughBelsky
In this case the value returned by the service is irrelevant. The spy is just confirming the service is called. The service itself is tested elsewhere.Bulimia
I see. Is there a specific reason you don't want to put the values in directly? just to save time?Belsky
1) Regardless of best practices, is this possible? 2) The form is long and complex. In this case form values are irrelevant since the test just confirms that a subscription is made to the correct service. Forcing the form to be valid makes sure the test focuses on what is important.Bulimia
unfortunately I could not find anything and don't know the answer. Just keep updating your question and hopefully you'll get an answer, good luckBelsky
L
18

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.

Lacey answered 13/10, 2017 at 13:24 Comment(1)
I have: this.newClientForm.clearAsyncValidators(); this.newClientForm.clearValidators(); this.newClientForm.updateValueAndValidity(); console.log(this.newClientForm.status); --->"INVALID" :(Botanist
G
8

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();
Godoy answered 14/10, 2020 at 11:4 Comment(0)
J
5

using only javascript, you can do:

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

to override the getter, to always return true.

Jester answered 1/1, 2022 at 19:38 Comment(0)
D
5

Instead of making the form to be valid, we can spy on the valid property of the form group.

We can do like:

spyOnProperty(component.myForm, 'valid').and.returnValue(false);

This line of code return true whenever the valid property the form group (this.myForm.valid) is accessed and it helps to pass the test.

Duplicate answered 13/7, 2023 at 16:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.