Conditional Testing mit Cypress

In diesem Blogbeitrag werden wir über Cypress sprechen. Falls Sie noch nichts von diesem Tool gehört haben - Cypress ist ein Framework, das für das Testen von Webanwendungen entwickelt wurde. Es läuft innerhalb Ihres Browsers und ermöglicht Ihnen die Manipulation und den Zugriff auf die DOM-Elemente.

Also available in English at Medium.com.

Bei miragon verwenden wir es für End-to-End-Tests unserer Anwendungen innerhalb unserer CI-Pipeline. Wenn Sie sich für Cypress interessieren, können wir Ihnen diese Einführung aus der offiziellen Dokumentation empfehlen.

Wenn Sie die gut geschriebene Cypress-Dokumentation lesen, werden Sie feststellen, dass die Autoren aus gutem Grund von der Verwendung bedingter Logik in Ihren Tests abraten. Dennoch gibt es Situationen, in denen bedingte Tests nützlich sein können. Schauen wir uns eine dieser Situationen einmal genauer an. Das folgende Beispiel enthält ein wenig bedingte Logik, um die Wiederholbarkeit einer Testsequenz zu gewährleisten.

Stellen Sie sich einen End-to-End-Test vor, bei dem der Benutzer ein Objekt in der Datenbank erstellt. Der zweite Test versucht dann, dieses Objekt wieder zu entfernen. Aber was passiert, wenn der erste Test fehlschlägt? Sie können sicher sein, dass auch der zweite Test fehlschlagen wird! Für diesen Anwendungsfall zeigen wir ein Beispiel, wie man die von einem Test erstellten Daten in einem beforeEach-Hook aufräumt.

Das Problem ist, dass wir nicht wissen, ob der erste Test überhaupt funktioniert hat, bevor wir den zweiten Test starten. Wenn wir dieses Problem ignorieren und jedes Mal versuchen, das Objekt zu löschen, wird der zweite Test mit Sicherheit auch fehlschlagen, wenn der erste Test nicht funktioniert hat, weil die Tabellenzeile mit dem Löschen-Button einfach nicht existiert. Um dies zu verhindern, müssen wir unsere Tests umstrukturieren. Anstatt Abhängigkeiten auf vorherige Tests zu haben, werden wir dafür sorgen, dass jeder Test alles, was er braucht, selbst erstellt. Nachdem der Test durchgeführt wurde, gibt es einen zusätzlichen Schritt, der die erstellten Elemente aufräumt. Auf diese Weise haben die beiden Tests keine Abhängigkeiten mehr voneinander.

Erstellen des Objekts

Um das Objekt zu erstellen, müssen wir das Formular ausfüllen und auf die Schaltfläche "Speichern" klicken. Stellen Sie sich die folgende Benutzeroberfläche vor:

Um dieses Formular auszufüllen und das Objekt zu speichern, können wir die folgenden Cypress-Anweisungen verwenden.

Um jedes Element eindeutig zu identifizieren, fügen wir jedem anklickbaren Element in unseren Anwendungen das Attribut data-cy hinzu. Dies werden wir verwenden, um die richtigen Schaltflächen und Eingaben in den folgenden Snippets zu finden.

// Button klicken, um die 'Neues Objekt'-Seite zu öffnen
cy.get('[data-cy=button-new-object]').click()

// Input-Felder Name und Beschreibung füllen
cy.get('[data-cy=input-name] input').type('My Object')
cy.get('[data-cy=input-description] input').type('This is my object.')

// Speichern-Button klicken
cy.get('[data-cy=button-save]').click()

Die Tabelle sieht dann so aus:

Aufräumen

Um sicherzustellen, dass der zweite Test das Element selbst erstellen kann, bereinigen wir die Liste im beforeEach-Hook, der von Cypress vor dem Start eines Tests ausgeführt wird. Wir durchlaufen jede Tabellenzeile und prüfen, ob das Element denselben Namen hat wie die gesuchte Zeile, und wenn ja, versuchen wir, es zu löschen. Der Befehl wird für jede Zeile der Tabelle ausgeführt, aber wir klicken nur auf den Button "Löschen", wenn die Zeile den gesuchten Text enthält. Auf diese Weise schlägt der Code nie fehl, unabhängig vom Inhalt der Tabelle.

// Über jede Tabellenzeile iterieren
cy.get('[data-cy=table-container] > table > tbody tr').each($row => {
    // Falls die Zeile denselben Namen hat wie das Objekt, nach dem wir suchen
    if ($row.text().includes('My Object')) {
        // Den Löschen-Button klicken...
        cy.get('[data-cy=delete-object-MyObject]')
            .click()
            // ...und den Popup-Dialog bestätigen
            .get('[data-cy=delete-dialog-button-delete]')
            .click()
        // Warten, bis das Objekt entfernt wurde
        cy.get(`[data-cy=delete-object-MyObject]`)
          .should('not.exist')
    }
})

Wie bereits erwähnt, fügen wir zu jedem Element ein data-cy-Attribut hinzu. Bei Tabellenzeilen und Listen müssen Sie jedoch sicherstellen, dass jede Zeile ihre eigene ID hat. Dazu wird eine vorhersehbare und eindeutige ID aus dem Inhalt der Zeile oder des Listenelements erzeugt. In einem zukünftigen Blogbeitrag werden wir vielleicht im Detail darüber sprechen.