jeudi 22 février 2018

Angular - Testing a form field with a debounced updated value call to a service

I have a form field (username) in a component that when updated calls a service to check for the value's availability in a database. Everything checks out fine but I can't seem to trigger the field's update function.

Here's the excerpt from the component code:

 ngAfterViewInit() {
   this.username.update
    .debounceTime(500) // wait 1/2 second before emitting last event
    .distinctUntilChanged() // only emit value if different from last value
    .subscribe((username: string) => {
      let data = { type: 'username', val: username };
      this._loginSrvc.chkUser(data).subscribe((response: IChkUserResponse)=>{
        if(response.isAvailable === false)
          this.username.control.setErrors({'taken': {value: this.username.value}});
      });
    });
 }

Here's the field in the components template:

<mat-form-field fxFlex>
  <input matInput placeholder="Username" aria-label="Username" forbiddenCharacters=';"\\\/\[\]\{\}\(\)' required [(ngModel)]="model.username" #username="ngModel" id="username" name="username">
  <mat-error *ngIf="newUserFrm.hasError('required','username')">Username is required</mat-error>
  <mat-error *ngIf="newUserFrm.hasError('forbiddenCharacters','username')"></mat-error>
  <mat-error *ngIf="newUserFrm.hasError('taken','username')">The username <em></em> is taken</mat-error>
</mat-form-field>

Here's my test:

it('should check for username availability',fakeAsync(()=>{
  spyOn(service,'chkUser');

  let input = fixture.debugElement.query(By.css('#username')).nativeElement;
  expect(input.value).toBe('');
  expect(component.username.value).toBe(null);

  input.value = user.username;
  input.dispatchEvent(new Event('input'));

  tick(500);

  expect(service.chkUser).toHaveBeenCalled();
}));

That last expect(service.chkUser).toHaveBeenCalled() is what is causing my test to fail. I've run this component in an application and it works as expected I'm just trying to get the test to pass. I've tried so many combinations of setting the input value and dispatching the event, waiting on the fixture to detectChanges or using whenStable(), throwing in a promise, using fakeAsync not using fakeAsync. Nothing seems to work.

Aucun commentaire:

Enregistrer un commentaire