Jeffrey P
Jeffrey P

Reputation: 367

How do I trigger the valuesChanged observable in a unit test after making changes to a FormGroup?

I am writing unit testing code on a component that includes a reactive form (FormGroup) and a subscription to valueChanges and I haven't figured out how to ensure the valueChanges event gets emitted by the FormGroup.

// In the component under test:
this.formGroup.get('field').valueChanges
     .subscribe((obj: any[]) => {
         debugger; // BREAKPOINT
         dataObject.fieldValues = [ ... ];
         ... details here should be unimportant ...
     });

// In the unit test:
it('should set dataObject from field component', fakeAsync(() => {
        [
    values: string[] = [ ... ];

    component.formGroup.get('field').setValue(values);
    component.formGroup.get('field').updateValueAndValidity({ emitEvent: true });
    fixture.detectChanges();
    tick();

    expect(component.dataObject.fieldValues.length).toEqual(values.length);

}));

I can not get the unit test spec to hit the breakpoint in the component subscription code.

Upvotes: 5

Views: 9116

Answers (1)

Erbsenkoenig
Erbsenkoenig

Reputation: 1659

The order of your tick()and fixture.detectChanges()is the key.

Expecting, that you already have a fixture.detectChnages() inside the beforeEarch loop where the componentInstance is set, then what you need to do is:

first call the tick(), so the test waits until the value is set. After that you can already access the value from inside the component like you did inisde your expect. If you then would want to expect a change inside your template you would need to trigger fixture.detectChanges which syncs your component with the template.

But important is here, that you call tick() before the fixture.detectChanges()

// In the component under test:
this.formGroup.get('field').valueChanges
     .subscribe((obj: any[]) => {
         debugger; // BREAKPOINT
         dataObject.fieldValues = [ ... ];
         ... details here should be unimportant ...
     });

// In the unit test:
it('should set dataObject from field component', fakeAsync(() => {
        [
    values: string[] = [ ... ];

    component.formGroup.get('field').setValue(values);
    component.formGroup.get('field').updateValueAndValidity({ emitEvent: true });

    tick();
    fixture.detectChanges(); // OPTIONAL

    expect(component.dataObject.fieldValues.length).toEqual(values.length);

}));

Upvotes: 8

Related Questions