web-dev-qa-db-fra.com

Angular Testing: FormControl valueChanges Observable

J'ai une entrée de texte et j'écoute les changements.

composant

name = new FormControl('',Validators.required);

ngOnInit() {
  this.data = 'oldvalue';
  this.checkName();
}

checkName() {
  this.name.valueChanges.subscribe(val=>{
     console.log(val);
     this.data= "newvalue"; // updating Value
  });
}

[~ # ~] html [~ # ~]

<input name="name" formControlName="name">

Ma tentative jusqu'à présent:

component.spec.ts

it('should test data field ', () => {
    const fixture = TestBed.createComponent(UserComponent);
    const app=fixture.debugElement.componentInstance;
    const el = fixture.nativeElement.querySelector('input');
    el.value ='something';
    dispatchEvent(new Event(el));
    fixture.detectChanges();
    fixture.whenStable().then(()=>{expect(app.data).toBe('newvalue');
});

Problème: Même si le champ de saisie est rempli, le code dans le rappel d'abonnement n'est jamais exécuté.

Cela montre toujours:

"Oldvalue" attendue pour être "newvalue".

J'ai également essayé la méthode setValue() mais cela n'a pas fonctionné. il ne va jamais à l'intérieur

app.name.setValue('vikas');
fixture.detectChanges();
fixture.whenStable().then(()=>{expect(app.data).toBe('newvalue');

J'ai fait référence Mise à jour du champ html d'entrée à partir d'un Angular 2 et Composant Angular2: test du changement de la valeur d'entrée du formulaire mais pas de chance :(

Qu'est-ce que je rate?

10
Vikas

À première vue, je pense que vous avez manqué le fait que votre FormControl n'est pas connecté à l'entrée parce que vous utilisez la directive FormControlName qui prend le nom de contrôle comme @Input.

Si vous voulez tester FormControl, vous pouvez considérer FormControlDirective qui prend FormControl comme @Input:

<input name="name" [formControl]="name">
                                  ^^^^^
                      `name` is FormControl instance here not string

Maintenant, nous pouvons être sûrs que chaque fois que nous modifions du texte en entrée, votre FormControl déclenchera les changements. Mais dès que vous écrivez un tel modèle angular vous demandera la dépendance ReactiveFormsModule dans votre test:

import { ReactiveFormsModule } from '@angular/forms';
....

TestBed.configureTestingModule({
   imports: [
     ReactiveFormsModule  <=== add this
   ],
   declarations: [TestComponent],
});

En ce qui concerne votre test.

1) Vous devez indiquer au TestBed d'effectuer la liaison de données en appelant fixture.detectChanges():

const fixture = TestBed.createComponent(TestComponent);
fixture.detectChanges(); <== add this

2) Vous devez déclencher correctement le changement sur l'entrée:

el.dispatchEvent(new Event('input'));

Voici tout le code:

it('should display original title', () => {
  const fixture = TestBed.createComponent(TestComponent);
  fixture.detectChanges();
  const app = fixture.debugElement.componentInstance;
  const el = fixture.nativeElement.querySelector('input');
  el.value = 'something';
  el.dispatchEvent(new Event('input'));
  fixture.detectChanges();
  fixture.whenStable().then(() => {
    expect(app.data).toBe('newvalue');
  });
});

Exemple Plunker

17
yurzui