2

I want to unit test my following method:

this.boxValue = '';

subscribeToFilterChanges(): void {
  this.filterBox.valueChanges
    .subscribe(
      data => {
        if (data) {
          this.boxValue = data.trim().toLowerCase();
        }
      }
    );
}

filterBox is a FormControl:

filterBox = new FormControl('');

HTML is:

<mat-form-field appearance="standard">
  <input matInput [formControl]="filterBox"
        id="filterBox-input">
</mat-form-field>

I've written the unit test as:

it('verify filter changes', () => { 
  let filterBoxInput = fixture.debugElement.query(By.css('#filterBox-input'));
  filterBoxInput.nativeElement.value = 'dummy';
  filterBoxInput.nativeElement.dispatchEvent(new Event('input'));
  fixture.detectChanges();
  fixture.whenStable().then(() => {
    expect(component.boxValue).toBe('dummy1');
  });
});

This test should fail, but still it is showing as passed, even though incorrect value is specified in .toBe()

What could be the issue?

I referred to Angular Testing: FormControl valueChanges Observable

Akxe
  • 9,694
  • 3
  • 36
  • 71
user5155835
  • 4,392
  • 4
  • 53
  • 97
  • You shouldn't need the `fixture.whenStable().then(` part. Reactive forms are synchronous. If you really want to keep it, then return that promise, or use `it('...', async(() => { ... }));` – JB Nizet Oct 12 '19 at 15:41
  • @JBNizet I just want to verify the value of boxValue. I don't need the `fixture.whenStable()` specifically. How can I do it in other ways? – user5155835 Oct 12 '19 at 15:50
  • 1
    Well, as I said, remove it. Check the value right after you've called detectChanges(), without wrapping the check into a whenStable().then() callback. `fixture.detectChanges(); expect(component.boxValue).toBe('dummy1');` – JB Nizet Oct 12 '19 at 15:59
  • @JBNizet Thank you. If the element is mat-select, then what should be in place of input in `new Event('input')` ? – user5155835 Oct 12 '19 at 16:32
  • I don't use angular material, but a mat-select is not a native HTML element, so it won't work with native events. See https://stackoverflow.com/questions/54474470/how-to-fire-selectionchange-event-on-an-angular-material-matselect-from-test-cod – JB Nizet Oct 12 '19 at 16:43

1 Answers1

0

I think that the issue here is that your component is not initialized properly at the time you're manipulating your input.

You must tell Angular to perform databing by calling fixture.detectChanges(); right after creating component:

const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges();

Also, as was mentioned in comments, whenStable is not needed here.

The completed test could look like:

it('verify filter changes', () => {
  const fixture = TestBed.createComponent(AppComponent);
  fixture.detectChanges();
  const component = fixture.debugElement.componentInstance;
  let filterBoxInput = fixture.debugElement.query(By.css('#filterBox-input'));
  filterBoxInput.nativeElement.value = 'dummy';
  filterBoxInput.nativeElement.dispatchEvent(new Event('input'));
  fixture.detectChanges();
  expect(component.boxValue).toBe('dummy'); // should pass
});

Ng-run Example

yurzui
  • 205,937
  • 32
  • 433
  • 399