Ich versuche, meiner Angular 2-App Komponententests hinzuzufügen. In einer meiner Komponenten befindet sich eine Schaltfläche mit einem (click)
Handler. Wenn der Benutzer auf die Schaltfläche klickt, wird eine Funktion aufgerufen, die in der .ts
Klassendatei definiert ist . Diese Funktion gibt im Fenster console.log eine Meldung aus, dass die Schaltfläche gedrückt wurde. Mein aktueller Testcode testet zum Drucken der console.log
Nachricht:
describe('Component: ComponentToBeTested', () => {
var component: ComponentToBeTested;
beforeEach(() => {
component = new ComponentToBeTested();
spyOn(console, 'log');
});
it('should call onEditButtonClick() and print console.log', () => {
component.onEditButtonClick();
expect(console.log).toHaveBeenCalledWith('Edit button has been clicked!);
});
});
Dies testet jedoch nur die Controller-Klasse, nicht den HTML-Code. Ich möchte nicht nur testen, ob die Protokollierung erfolgt, wenn sie onEditButtonClick
aufgerufen wird. Ich möchte auch testen, onEditButtonClick
was aufgerufen wird, wenn der Benutzer auf die in der HTML-Datei der Komponente definierte Schaltfläche zum Bearbeiten klickt. Wie kann ich das machen?
quelle
Ereignisse können mit den von bereitgestellten Funktionen
async
/ getestet werden , da jedes Ereignis im Browser asynchron ist und in die Ereignisschleife / -warteschlange verschoben wird.fakeAsync
'@angular/core/testing'
Im Folgenden finden Sie ein sehr einfaches Beispiel zum Testen des Klickereignisses mit
fakeAsync
.Die
fakeAsync
Funktion ermöglicht einen linearen Codierungsstil, indem der Testkörper in einer speziellenfakeAsync
Testzone ausgeführt wird.Hier teste ich eine Methode, die vom click-Ereignis aufgerufen wird.
it('should', fakeAsync( () => { fixture.detectChanges(); spyOn(componentInstance, 'method name'); //method attached to the click. let btn = fixture.debugElement.query(By.css('button')); btn.triggerEventHandler('click', null); tick(); // simulates the passage of time until all pending asynchronous activities finish fixture.detectChanges(); expect(componentInstance.methodName).toHaveBeenCalled(); }));
Im Folgenden finden Sie Informationen zu Angular-Dokumenten :
quelle
async
vs.fakeAsync
. Auch wenn in meiner Antwort habe ichasync
im Allgemeinen, würde meine Präferenz zu verwenden seinfakeAsync
.tick()
s haben, wenn Ihr Code aufruftsetTimeout
. Ich glaube nicht, dass ein Häkchen benötigt wird. Siehe stackoverflow.com/a/50574080/227299Ich benutze Angular 6 . Ich folgte der Antwort von Mav55 und es funktionierte. Ich wollte jedoch sicherstellen, dass
fixture.detectChanges();
es wirklich notwendig war, also entfernte ich es und es funktionierte immer noch. Dann entfernte ich, umtick();
zu sehen, ob es funktionierte und es tat. Schließlich entfernte ich den Test aus derfakeAsync()
Verpackung und überraschte, dass es funktionierte.Am Ende hatte ich folgendes:
it('should call onClick method', () => { const onClickMock = spyOn(component, 'onClick'); fixture.debugElement.query(By.css('button')).triggerEventHandler('click', null); expect(onClickMock).toHaveBeenCalled(); });
Und es hat gut funktioniert.
quelle
fixture.detectChanges()
, um die Lebenszyklusereignisse von Angular auszulösen. Es kann sein, dass Ihre Komponente keine hatngOnInit
oder dass der Test nicht bestanden werden musste.async
oderfakeAsync
. Um sicher zu gehen, sehe ich nichts falsches daran anzunehmen, dass alle Ereignisse asynchron sind und nurasync
oder verwendenfakeAsync
(es ist Ihre Präferenz).tick()
s zu verunreinigen, weil möglicherweise etwas asynchron ist? Sie sollten wissen, was asynchron ist und was nicht. Das Auslösen von Maus- / Tastatur- / Eingabeereignissen ist immer synchron.Ich hatte ein ähnliches Problem (detaillierte Erklärung unten) und habe es (in
jasmine-core: 2.52
) gelöst, indem ich dietick
Funktion mit der gleichen (oder größeren) Anzahl von Millisekunden wie im ursprünglichensetTimeout
Aufruf verwendet habe.Wenn ich zum Beispiel eine hätte
setTimeout(() => {...}, 2500);
(damit sie nach 2500 ms ausgelöst wird), würde ich anrufentick(2500)
, und das würde das Problem lösen.Was ich in meiner Komponente hatte, als Reaktion auf einen Klick auf die Schaltfläche Löschen :
delete() { this.myService.delete(this.id) .subscribe( response => { this.message = 'Successfully deleted! Redirecting...'; setTimeout(() => { this.router.navigate(['/home']); }, 2500); // I wait for 2.5 seconds before redirect }); }
Sie ist mein Arbeitstest :
it('should delete the entity', fakeAsync(() => { component.id = 1; // preparations.. component.getEntity(); // this one loads up the entity to my component tick(); // make sure that everything that is async is resolved/completed expect(myService.getMyThing).toHaveBeenCalledWith(1); // more expects here.. fixture.detectChanges(); tick(); fixture.detectChanges(); const deleteButton = fixture.debugElement.query(By.css('.btn-danger')).nativeElement; deleteButton.click(); // I've clicked the button, and now the delete function is called... tick(2501); // timeout for redirect is 2500 ms :) <-- solution expect(myService.delete).toHaveBeenCalledWith(1); // more expects here.. }));
PS Eine großartige Erklärung zu
fakeAsync
und allgemeine Asynchronität beim Testen finden Sie hier: Ein Video zu Teststrategien mit Angular 2 - Julie Ralph, ab 8:10 Uhr, dauert 4 Minuten :)quelle
Um das Ereignis des Schaltflächenaufrufs zuerst zu überprüfen, müssen wir die Methode ausspionieren, die nach dem Klicken auf die Schaltfläche aufgerufen wird, damit unsere erste Zeile "spyOn spy methode" lautet. Nehmen Sie zwei Argumente. () 'Nur Name erforderlich, dann müssen wir das Objekt der Schaltfläche zum Klicken machen. Jetzt müssen wir den Ereignishandler auslösen, zu dem wir das Klickereignis hinzufügen. Dann erwarten wir, dass unser Code die Submit-Methode einmal aufruft
it('should call onSubmit method',() => { spyOn(component, 'onSubmit'); let submitButton: DebugElement = fixture.debugElement.query(By.css('button[type=submit]')); fixture.detectChanges(); submitButton.triggerEventHandler('click',null); fixture.detectChanges(); expect(component.onSubmit).toHaveBeenCalledTimes(1); });
quelle
it('should call onSubmit method',() => { let mock = spyOn(component, 'onSubmit'); let submitButton: DebugElement = fixture.debugElement.query(By.css('button[type=submit]')); fixture.detectChanges(); submitButton.triggerEventHandler('click',null); fixture.detectChanges(); expect(mock).toHaveBeenCalledTimes(1); });