Test a component @Input binding in the form in Angular

Angular component binds data through @Input, where data can be passed from parent to child (or from smart component to presentation component). It is basic Angular practice, but writing specs for presentation component could be tricky in some cases.

In this example, smart component gets a form value from store, and passes down to presentation component to display in the form.

userName is retrieved in smart component:

private userName = this.store.select(getCurrentUser);

userName is used as in input to display in a form in presentation component

@Input()
public userName: string;

The form template:

<form [formGroup]="stepForm" novalidate>
   <input
    [formControl]="userName"
    [(ngModel)]="userName"
    >
</form>

Now we want to test the scenario when a userName is retrieved from store, it should be binded to our form.

it(`should load in existing value in store`, () => {
   component.userName = mockUser.name;
   setTimeout(() => { 
     expect(component.stepForm.value.userName)
     .toEqual(mockUser.name)
   }, 1000);
 })

The reason of using setTimeout is due to the loading time from store. In specs, we mock the input, but still when component is rendered, the value isn't there yet at that second. So it makes sure that value has been loaded and populated properly before makes comparison.

This simple spec passed if run by itself. It sometimes failed when run with other specs. Because setTimeout might have other spec threads running at the same time while waiting, which can mess up the state. Also, it's not the most elegant way of waiting for data to load.

A correct way is to subscribe to the form control valueChanges and once that change happens, it means that the form is loaded.

it(`should load in existing value from input`, () => {
   component.userName = mockUser.name;
   component.stepForm.controls['userName'].valueChanges.subscribe((value) => {
        expect(value).toEqual(mockUser.name);
});

Any time when userName gets updated - value changed, its value is binded to the form. This makes sure the test is reliable and trustable.