Moe's Anmerkungen zu den Fallstricken der Testautomatisierung bei Shopware

common Shopware testing traps
Ramona Schwering
Ramona Schwering

September 28, 2021

Dieser Inhalt ist auch in folgender Sprache verfügbar: english

Manchmal schlagen unsere Pipelines fehl. Wenn das bei unseren eigenen Merge-Requests passiert, müssen wir es beheben - ich kann mir vorstellen, dass es Dir genauso geht, wenn Du mit den Tests von Shopware arbeitest. Dies sind meine Anmerkungen zu häufigen Fallen bei der Testautomatisierung im Zusammenhang mit Shopware.
Shopware
Unit Tests
End-To-End Tests
Testing pitfalls

Dieser Artikel sollte Teil spezifischer Hilfsressourcen sein, die Dir zeigen, wie Du fehlerhafte Pipelines überprüfen, debuggen und beheben kannst. In gewisser Weise ist dies eine Art Merkblatt für all die kleinen Probleme, die mir in meiner täglichen Arbeit oder als Fragen in StackOverflow oder über Shopware's community slack helfen. Notizen dienen als Checkpoint für Gedanken, richtig?

Aktualisiert am 28. September 2021" message="Es ist ein lebendiges Dokument, Du kannst also gerne etwas dazu beitragen, Dich bei mir melden und zu einem späteren Zeitpunkt nachsehen, ob neue Fallstricke entdeckt wurden

Allgemeine Dinge

Honorable mention

Ich habe bereits einen Leitfaden, wie Du Deine Tests auf allgemeine, häufige Fallstricke überprüfen kannst. Er könnte für Dich hilfreich sein, wenn Du Dir einen Überblick über alle Informationen zu diesem Thema verschaffen möchtest.

Gibt es bereits Voreinstellungen, Tests oder andere testbezogene Inhalte von Shopware?

Natürlich gibt es das. Shopware 6 ist quelloffen, ebenso wie alle seine Tests. Du kannst also alles, was mit unseren Tests zu tun hat, in diesem Repository finden:

Was die Dokumentation betrifft, so gibt es bereits eine Menge Inhalt zu entdecken:

Aber das ist noch nicht alles. Shopware stellt einige voreingestellte Plugins zur Verfügung, um Sie mit Helper und Commands zu versorgen:

Du kannst sie gerne ausprobieren. 💙

Kann ich auf die PSH-Skripte verzichten?

Ja, sicher! Das sollte einfach sein, denn Du kannst einfach die normalen Befehle verwenden. So zum Beispiel mit Cypress: Verwende einfach den Pfad zum Stammverzeichnis Deines Tests (oder navigiere dorthin) und dann ./node_modules/.bin/cypress open. Mit Jest und natürlich PHPUnit sollte es das Gleiche sein. Die PSH-Skripte dienen als Wrapper um die Standardbefehle, also kannst Du Dir auch diese Skripte ansehen, um zu sehen, wie Du die Tests selbst starten kannst.

PHP Unit Tests

Wieder einmal Aktualisierungen von Abhängigkeiten ...

Manchmal ist es sinnvoll, Versionsnummern von Abhängigkeiten nicht zu fixieren, um Fehler aufgrund von Inkompatibilitäten oder ähnlichem zu entdecken. Nehmen wir Symfony Updates als Beispiel: Es könnte der Fall eintreten, dass sie ein Update veröffentlichen, das unsere Pipelines fehlschlagen lässt. Untersuchen wir einen plötzlichen Fehler in Verbindung mit Symfony, z.B.:

"Parameter #5 $default of method Symfony\\Component\\Console\\Command\\Command::addOption()
 expects array<string>|bool|string|null, int given.",

Lösung

Sicher, wir wollen auf dem neuesten Stand bleiben, aber das ist die Kehrseite der Medaille. Wenn Du also einen Fehler in Verbindung mit Symfony siehst, stelle sicher, dass Du deren Releases überprüfst.

Migration schlägt fehl

Es kann vorkommen, dass unsere PHPUnit-Pipelines aufgrund von neuen oder geänderten Migrationen fehlschlagen. Hier ist ein repräsentativer Fehler:

In AbstractMySQLDriver.php Zeile 61:
  Während der Ausführung von 'SELECT * FROM migration WHERE class = ?' ist eine Ausnahme aufgetreten 
  with params ["Shopware\\Core\\Migration\\Migration1536232600Language"]:
  SQLSTATE[42S02]: Basistabelle oder Ansicht nicht gefunden: 1146 Tabelle 'sw6.migration' existiert nicht

Manchmal schlagen die Migrationstests auch direkt fehl. Was ist nun zu tun?

Lösung

Wenn Du Migrationen schreibst, behalte immer unsere docs im Hinterkopf. Wenn Du eine fehlgeschlagene Pipeline debuggen musst, kann es der erste Schritt sein, zu überprüfen, ob alle Migrationen korrekt angewendet werden.

Ein häufiger Fehler ist die falsche Verwendung von Sprachen. Bitte denke dran, dass obwohl Deutsch und Englisch die Standardsprachen sind, das nicht bedeutet, dass diese beiden Sprachen auch immer verfügbar sind!

Jest Unit Tests

jest.spyOn() funktioniert nicht wie erwartet

Die jest.spyOn-Methode funktioniert nicht wie erwartet, wenn die Methode als Callback aufgerufen wird (z.B. aus der Vorlage). Lösungen aus stackoverflow usw. können die Leute verwirren, weil wir keine benannten Importe der Komponenten verwenden.

Lösung

Die Komponente wird in einer Variablen gespeichert und das Spionieren muss vorher durchgeführt werden. Siehe hier:

const swMeteorSingleSelect = Shopware.Component.build('sw-meteor-single-select');

// Fahre dann mit Deinem Test fort

Warten auf das Auslösen von Ereignissen

Manchmal ist es notwendig, auf das Auslösen eines Ereignisses zu warten, bevor man mit dem Test fortfährt, z.B. wenn man mit einem zusammenklappbaren Panel in der Storefront arbeitet.

Lösung

Einen Ereignis-Listener in ein Versprechen verpacken:

const isEventTriggered = new Promise((resolve) => {
   $(collapse).on('shown.bs.collapse', () => {
      resolve();
   });
});

// Aufruf einer Methode, die das Ereignis auslöst
$(collapse).collapse('show');

// Warten, bis der Event-Handler ausgelöst wurde
await isEventTriggered;

Wie man ein Event auslöst

Um eine bestimmte Funktionalität zu testen, ist es notwendig, ein Event programmatisch auszulösen.

Lösung

Durch die Verwendung der jsdom-Umgebung in Ihrer spec-Datei kannst Du auf die gesamte DOM-API zugreifen, was uns erlaubt, ein Standard-Ereignis oder sogar benutzerdefinierte Ereignisse zu feuern.

/**
 * @jest-environment jsdom
 */
describe('some spec file', () => {
    it('should react to a click event', () => {
        const element = document.querySelector('.my-selector');
        const clickEvent = new Event('click');

        element.dispatchEvent(clickEvent);
    });
})

End-to-End Tests mit Cypress

Lokaler Fehler beim Starten von Cypress in einer Docker-Umgebung

Wenn Du mit dem Standard-Docker-Setup von Shopware arbeitest, könntest Du über die folgende Fehlermeldung stolpern:

No protocol specified (Cypress:92): Gtk-WARNING \*\*: 09:39:50.737: cannot open display: :0 

Lösung

Basierend auf dieser Anleitung musst Du die XVFB-Nachrichten von Cypress aus dem Docker-Container heraus an einen X11-Server weiterleiten, der auf dem Host-Rechner läuft. Die erwähnte Anleitung zeigt ein Beispiel für Mac; andere Betriebssysteme erfordern möglicherweise andere Befehle. Ein erster Ansatzpunkt ist das Ausprobieren einer für Dich passenden xhost-Konfiguration. Ein möglicher Befehl könnte xhost +local sein:

Meine Tests schlagen nur manchmal fehl

In CI sehe ich, dass ein Test auf nicht-deterministische Weise fehlschlägt: Manchmal geht er durch, manchmal schlägt er fehl.

Lösung

Um dieses Verhalten reproduzierbar zu machen, setze ihn bitte in eine Schleife und führe ihn ca. 20-30 Mal aus. Ich empfehle, das in CI auszuführen, aber es ist auch möglich, das lokal zu tun.

// Verwende im Build Lodash, um den Test 100 Mal zu wiederholen
Cypress._.times(100, (k) => {
   it(`typing hello ${k + 1} / 100`, () => {
       // Schreibe hier Deine Testschritte rein
   })
})

Wenn Du feststellst, dass es tatsächlich einige Ausfälle gibt, könntest Du damit beginnen, den Zeitplan zu überprüfen. Wenn Du lokal arbeitest, kannst Du mit dem folgenden Befehl verwenden, um die Ausführung des Cypress-Tests anzuhalten und fortzusetzen:

cy.pause(); // Dadurch wird der Test unterbrochen, bis Du ihn manuell fortsetzt

When working in CI, use a temporary wait to check the timing:

cy.wait(500); // Zeit in ms, d.h. es wird eine halbe Sekunde lang gewartet
Vorsicht!

Verwende feste Wartezeiten nur vorübergehend, um zu debuggen. Ersetz diese Wartezeit durch eine dynamische Behauptung, wenn die Flakiness durch Timing-Probleme verursacht wird. Weitere Informationen findest Du in unseren Best Practices und den Cypress Best Practices. Natürlich solltest Du auch die Schleife entfernen, sobald Du mit dem Debuggen fertig bist.

Wenn Du mehr über dieses Thema erfahren willst, gibt es einen Artikel von mir.

Das Element, mit dem ich interagieren möchte, ist nicht mehr verfügbar

Manchmal wird ein Element neu gerendert oder verwendet eine Animation, die dazu führt, dass es für einen kurzen Moment verschwindet oder nicht nicht mehr zur Interaktion bereit ist. Der folgende Fehler ist der bekannteste:

cy.click failed because the element has been detached from the DOM

Eigentlich gibt es viele mögliche Lösungen oder Workarounds, das wäre eine wunderbare Idee für einen eigenen Artikel, denke ich. In der Zwischenzeit hat Cypress selbst eine Blog-Serie über viele dieser Probleme geschrieben.