it-swarm.com.de

.detectChanges () funktioniert nicht innerhalb Angular Prüfung

Ich wurde mit dem Schreiben von Tests für eine mit Angular entwickelte Chat-App beauftragt. Hier ist der Ausschnitt aus Angular Vorlagencode, für den ich zurzeit Tests schreibe:

<div class="title-menu-container" fxLayoutAlign="center center">
  <button id="save-title-button" mat-icon-button *ngIf="titleInputEdit; else settings">
    <mat-icon class="secondary-text" (click)="saveTitle(titleInput.value)">check</mat-icon>
  </button>
  <ng-template #settings>
    <button mat-icon-button [matMenuTriggerFor]="menu" [disabled]="!(isGroupConversation$ | async)">
      <mat-icon class="secondary-text">settings</mat-icon>
    </button>
  </ng-template>
</div>

Wenn die boolesche Komponentenvariable 'titleInputEdit' wahr ist, wird die Schaltfläche "Speichern-Titel" angezeigt. Andernfalls wird die Schaltfläche "Einstellungen" angezeigt. Hier ist der Testfall, der Probleme verursacht:

it('save title button should be present', () => {
  component.titleInputEdit = true;
  fixture.detectChanges();
  expect(fixture.nativeElement.querySelector('#save-title-button')).not.toBe(null);
}); 

Ich "mockte" einfach die Komponentenvariable, rufe .detectChanges () auf und teste das Vorhandensein der Schaltfläche. Der Test schlägt jedoch fehl, wenn erwartet wurde, dass NULL nicht NULL ist. 

Durch verschiedene Aufrufe von console.log habe ich bestätigt, dass component.titleInputEdit korrekt auf true gesetzt ist, das fixture.nativeElement jedoch NICHT die richtige Schaltfläche enthält. 

Einige Dinge, die mir aufgefallen sind:

  • Wenn ich die Zeile 'component.titleInputEdit = true' in meine beforeEach versetze und sie entferne, und der detectChanges () - Aufruf aus meinem Test besteht, ist der Test erfolgreich.

    beforeEach(() => {
      fixture = TestBed.createComponent(TestComponent);
      component = fixture.componentInstance;
      component.titleInputEdit = true
      fixture.detectChanges();
      debugElement = fixture.debugElement;
    });     
    
    it('save title button should be present', () => {
        expect(fixture.nativeElement.querySelector('#save-title-button')).not.toBe(null);
    });
    
  • Wenn ich den Aufruf .detectChanges () von beforeEach () entferne und im Testfall belasse, ist der Test erfolgreich.

Ich bin relativ neu bei Angular, aber ich habe Fälle von Menschen mit einem ähnlichen Problem gefunden. Nachdem ich einige der in diesen Posts empfohlenen Dinge ausprobiert habe, kratzte ich immer noch am Kopf. Noch seltsamer ist, dass ich Tests für andere Angular-Komponenten geschrieben habe, die fast dasselbe tun, ohne dass es Probleme gibt. 

Das in den Angular-Dokumenten bereitgestellte Beispiel zeigt auch etwas sehr ähnliches:

it('should display a different test title', () => {
  component.title = 'Test Title';
  fixture.detectChanges();
  expect(h1.textContent).toContain('Test Title');
});    
4
LHB

Es stellt sich heraus, dass dies auf die Verwendung von ChangeDetectionStrategy.OnPush in der Komponente zurückzuführen ist. Wenn Sie OnPush verwenden, können Sie .detectChanges () nur einmal aufrufen, sodass nachfolgende Aufrufe nichts tun können. Ich bin mit Angular nicht vertraut genug, um ganz zu verstehen, warum. 

Ich konnte das erforderliche Verhalten erzeugen, indem ich die ChangeDetectionStrategy in meiner TestBed-Konfiguration überschrieb.

TestBed.configureTestingModule({
    imports: [],
    declarations: [TestComponent],
    providers: []
  })
    .overrideComponent(TestComponent, {
      set: { changeDetection: ChangeDetectionStrategy.Default }
    })
    .compileComponents();
11
LHB

Die hier gegebene Antwort https://stackoverflow.com/a/50142134/3765819 behebt das Problem. Es gibt jedoch auch einen anderen Weg, durch den meiner Meinung nach weitere Probleme auf der Benutzeroberfläche vermieden werden können. Das Problem, das ich hatte, war dem in der Frage beschriebenen ähnlich, was bedeutete, dass ich es beim Testen einer bestimmten Zeichenfolge in HTML nicht finden konnte. Obwohl der Code gut ausgeführt wurde, wurde die Benutzeroberfläche beim Testen nicht entsprechend aktualisiert. 

Was ich tun musste, war:

So fügen Sie ChangeDetectorRef in die .ts-Datei ein:

constructor(private changeDetector: ChangeDetectorRef) {}

und nennen Sie es bei Bedarf:

this.changeDetector.markForCheck();
1
fernandodof