How to: End-To-End-Testing mit Cypress

Jeder der mal mit komponentenbasiertem Programmieren angefangen hat, kennt die Situation. Man schreibt eine Komponente, die auf den ersten Blick funktioniert, dann aber beim Aufruf unerwartete Fehler aufweist. In der Entwicklungsphase ist dies ganz natürlich, aber wenn die Anwendung dem Kunden übergeben bzw. Endnutzer zur Verfügung gestellt wird und es zum Knall kommt, ist es katastrophal für die Reputation der eigenen Firma.

Jetzt sitzt du da und musst mehrere 1000 Elemente testen, die bei jeder Änderung sich gegenseitig beeinflussen. Testvorgänge mehrmals manuell auszuführen ist zeit- und nervenraubend.

Abhilfe schafft das End-to-End Test-Framework Cypress, welches speziell für das Testing von Web-Applikationen entwickelt wurde.

Das Besondere an Cypress ist, dass alles automatisiert abläuft. Manuelles hin her klicken gehört der Vergangenheit an, wenn das Testsetup ordentlich umgesetzt ist.

Eine ausführliche Featurebeschreibung könnt ihr unter: https://docs.cypress.io/guides/overview/why-cypress.html#Our-mission nachlesen

Mit Cypress starten

Cypress installieren

Zuallererst navigieren wir im Terminal in unseren Projektordner und installieren dort anschließend alle nötigen NPM Pakete:

$ cd/your/project/path

Mit npm:

$ npm install cypress --save-dev

Mit yarn:

$ yarn add cypress --dev

Cypress öffnen

Mit npm:

$ npx cypress open

Mit yarn:

$ yarn run cypress open

Cypress Benutzeroberfläche

Das Hauptmenü sollte in etwa so aussehen:

Wie du sehen kannst, liefert das Tool bereits viele fertig geschriebene Beispiele. Um zu prüfen, ob alles funktioniert, kannst du der Einfachheit halber auf ein Bespieltest klicken und es öffnet sich ein neues Fenster, wo der gewählte Test ausgeführt wird.

Der Test-Runner von Cypress öffnet sich und sollte in etwa so aussehen:

Die Ersten Schritte

In diesem Abschnitt werde ich euch eine kleine Zusammenfassung geben, was ihr für den Start wissen solltet.

1. Testdatei erstellen

  • Alle Test-Files kommen in dem Ordner: cypress/intergration
  • Namenkonvention: fileName_spec.js oder fileName.spec.js
  • describe(), it(), context() und specify() beinhalten die auszuführende Testbefehle und ihr könnt damit auch euer Test strukturieren und ein Name geben.

Dateistruktur an einem Bespiel:

// -- Start: Our Application Code --
function add (a, b) {
  return a + b
}
// -- End: Our Application Code --

// -- Start: Our Cypress Tests --
describe('Unit test our math functions', function() {
  context('math', function() {
    it('can add numbers', function() {
      expect(add(1, 2)).to.eq(3)
    })
})
// -- End: Our Cypress Tests --

2. Test schreiben

Sobald ihr die Test-File angelegt habt, aktualisiert Cypress automatisch die Testliste und euer Test sollte im Menü auswählbar sein.

In diesem Abschnitt werden die grundlegenden Funktionen gezeigt.

Test Website besuchen: cy.visit()

Diese Funktion überprüft den Link und gibt ein true zurück, falls ein 2XX Status wie 200 zurückkommt. Anderenfalls wird ein false zurückgegeben und der Test schlägt fehl.

describe('My First Test', function() {
  it('Test PHMU Website', function() {
    cy.visit('https://www.phmu.de/')
  })
})
  • Wie ihr sehen könnt werden die Befehle in dem Commando Log als Großbuchstaben angezeigt. Hier in unseren Beispiel VISIT.
  • Ein Klick darauf, wird das angesprochene Element in Funktion visuell angezeigt.
  • Alle Test werden als eine Timeline dargestellt und ihr könnt dadurch die Zeit “zurückspringen” und genau schauen, wann und wo der Test fehlgeschlagen hat.

Elemente abfragen

Im Cypress können wir ein Element aus unsere Test-Website abfragen und herauspicken (Query).

Die gängigen Funktionen dafür sind:

contains(content) – Gibt das DOM-Element zurück, dass den entsprechenden innerText enthält.

describe('My First Test', function() {
  it('Test PHMU Website', function() {
    cy.visit('https://www.phmu.de/')
  })
  it('Test contain PHMU slogan', function() {
    cy.contains('Unser Herz schlägt digital')
  })
})

get(selector) – Gibt das das DOM-Element zurück, dass mit dem Selektor ausgewählt wurde.

describe('My First Test', function() {
  it('Test PHMU Website', function() {
    cy.visit('https://www.phmu.de/')
  })
  it('Test contain PHMU slogan', function() {
    cy.get('img[class=image]')
    //Sucht ein img element mit der CSS-Klasse image
  })
})

Mit Elementen interagieren

Nachdem ihr im vorherigen Schritt die Elemente abgefragt haben, ist es auch möglich mit den Elementen zu interagieren. Falls eine Interaktion mit einem Element nicht möglich ist, wird der Test fehlgeschlagen.

type()

describe('My First Test', function() {
  it('Test contact formular', function() {
    cy.visit('https://www.phmu.de/workshops')
  })
  it('Test firstname input', function() {
    cy.get('input[id="firstname"]').type('Tung')
  })
})

click()

describe('My First Test', function() {
  it('Test contact formular', function() {
    cy.visit('https://www.phmu.de/workshops')
  })
  it('Test firstname input', function() {
    cy.get('button[id="submit"]').click()
  })
})

select()

describe('My First Test', function() {
  it('Test contact formular', function() {
    cy.visit('https://www.phmu.de/workshops')
  })
  it('Test firstname input', function() {
    cy.get('select[id="title"]').select("Doctor")
  })
})

Assertion

Mit should() kannst du überprüfen ob ein Element das ist, welches du erwartest. Als Beispiel möchten wir sicherstellen, dass die aktuelle URL die erwartete URL ist.

describe('My First Test', function() {
  it('Test PHMU Website', function() {
    cy.visit('https://www.phmu.de/')
  })
  it('Test workshop link', function() {
    cy.get(a[href="/workshop"]).click
    cy.url().should('include', '/workshop')
  })
})

In diesem Blog habe ich euch das nötigste mitgegeben, um euch auf Cypress aufmerksam zu machen. Es ist auch möglich Serveranfragen zu testen und zu validieren oder das Terminal auszulesen und nach Fehlern zu testen. Cypress ist sehr umfangreich und bietet viele Möglichkeit, sein Web-Interface auf Herz und Nieren zu testen..

Wie ich bereits erwähnt habe, empfehle ich euch wärmsten die Dokumentation. Diese beinhaltet neben der guten Dokumentation auch Best Practices für ein effektives Testing von Web-Applikation.

Links

Vue Barcamp Berlin 2019

Tag 1

Nach monatelangen Warten war es endlich soweit. Von 25.10.2019 bis 27.10.2019 machten sich das Team PHMU Mit Marschgepäck und Vorfreude auf dem Weg in die Bundeshauptstadt Berlin. Das Zeil der Reise war das Vue Barcamp 2019.

Nach der Fahrt und Ankunft in Berlin, stand Entdeckung als Erstes auf unserem To Do List. Gleich nach dem ersten Schritt aus dem Zug wurden wir förmlich von der Größe Berlins erschlagen. Egal ob Tags oder Nachts, überall sind Menschenmassen, Musik, Lichter und …. . Ab da merkt man erst , dass Dresden eigentlich noch eine kleine überschaubare Stadt ist. Nachdem wir uns ausgetobt haben ging es auch schon ins Hotel um uns auf einem interessanten Tag vorzubereiten.

Tag 2

Nachdem wir uns trotz durch einen Einstieg in die falsche Bahn, am Veranstaltungsort pünktlich angekommen sind, ging das Barcamp auch schon sofort los.

Bei einem Barcamp planen die Teilnehmer das Programm selber, indem Sie ein Thema präsentieren oder über ein Probleme, dass sie diskutieren wollen, vorschlagen. Anschließend wird nach der Anzahl der Interessenten das Thema in das Programm hinzugefügt oder nicht.

Bereits am ersten Tag konnte dadurch genug Themen gefunden werden, um einem ganzen Tag und hinaus zu füllen.

Programmablauf für den Samstag

Von Workshop für Vue.js Einsteiger, Frameworks Ankündigungen bis hin zur Diskussion über das kommende Update zur Vue.js 3.0 war alles dabei.

Diskussion über die Neuerungen  in Vue.js 3.0 
Phillipp war auch am Start und berichtete der Community von seiner Arbeit mit Storybook

Tag 3

Am zweiten Tag war der Programmablauf wieder prall gefüllt mit interessanten Inhalten, angeregt durch Diskussionen und Themen am vorherigen Tag.

Meine Erfahrung

Wie man sehen kann, bezieht das Barcamp sein Reiz aus dem Austausch von Informationen unter den Vue.js Entwicklern. Es folgt wie im Leben das Prinzip von Geben und Nehmen. Indem wir der Vue.js Community unsere Erfahrungen aus unseren Projekten mitteilen, erhalten wir von der Community viele gute Anregungen für zukünftige Projekte.

Die nette Ramona vom Shopware hat es uns am ersten Tag das Test-Framework cypress.io  vorgestellt und wir waren sofort begeistert. Dies hat uns verleitet bei unseren zukünftigen Projekten mit dem Framework zu arbeiten.

Alles in einem war das Vue Barcamp eine spannende Angelegenheit. Am Anfang hatte ich als Vue.js Anfänger große Angst mich in dem Wirbelstrom von Expertenwörtern zu verlieren. Doch wie es sich herausstellte, waren viele Teilnehmer dabei die selber mit Vue.js  erst angefangen haben oder es lernen wollen. Die Angst war also zu Unrecht. Da die Themen breit gefächert sind, ist immer ein Thema für jede Könnensstufe dabei. Ich kann jedem so ein Barcamp wärmsten empfehlen. Es musst ja nicht immer nur Vue.js sein 😉

Mit Netlify Functions Emails versenden

Sagen wir du hast deine erste moderne statische Website (JAMStack) gebaut und willst sie dynamischer gestalten wie z.B durch das Versenden von E-Mails mit dynamischen Inhalten und Dateianhang. Dafür willst du aber keinen eigenen Server aufsetzen bzw. nutzen. Wie das gelingt, erklären wir in diesem Post.

Was benötigt man?

1. Mailing Service

Als allererstes brauchst du einen Mailing Service, der deine Emails versendet. Wichtig ist, dass du Emails nicht von deinem eigenen Emailserver senden solltest, sondern immer auf einen größeren Dienstleister zurückgreifen solltest um beispielsweise der Gefahr zu entgehen, dass du als Spamversender eingestuft wirst. Um eine Mail zu versenden, sprichst du die Service API mit einem API Key an und übergibst alle Daten, die in der Mail enthalten sein sollen und der Mailing Service verschickt sie dann an die Zieladresse.

Es gibt viele Services zur Auswahl und du solltest jenen nehmen, der von den Features und dem Preis her am besten zu dir passt. Da ich bei meinem letzten Projekt gerne mit POSTMARK gearbeitet habe, werde ich in diesem Post vorstellen, wie man diesen Dienst benutzt.

2. Netlify

Als Nächstes brauchen wir eine kleine Menge serverseitigen Code, um dem API Key beim API Request zu schützen. Dafür eignen sich Lambda Funktionen bestens. Man ruft einen URL Endpoint auf und beim Aufruf wird ein vorgegebener Code ausgeführt. Netlify unterstützt dies, also wäre es eine gute Idee deine Seite darauf zu hosten.

Schritt 1: Mail Service einrichten

POSTMARK einrichten

Als Erstes melden wir uns bei Postmark an und gehen alle Schritte durch, bis wir zum Dashboard kommen und Zugriff auf den API Token haben.

API Key für Netlify zur Verfügung stellen

Um den API Key zu schützen, sollte der Key nur beim Ausführen serverseitigen Codes zur Verfügung gestellt werden. Im Netlify müssen wir deshalb unter “Environment” den Key einer Variable zuweisen.

Schritt 2: Functions schreiben

Wie erstellen wir eine Netlify Function? Ganz einfach. In deinem Projekt Ordner legst du ein Ordner mit dem Namen “functions” an. In diesem legst du dann alle JavaScript Dateien an, die du benötigst. In unserem Fall legen wir die Datei send-email.js an.

/project
   ... your entire website or whatever ...
   /functions/
         send-email.js

Postmark Node Library benutzen

Postmark stellt eine eigene Node.js Bibliothek zur Verfügung und mit einem Blick auf die Dokumentation entdecken wir gleich am Anfang ein einfaches Codebeispiel zum Testen.

const serverToken = "xxxx-xxxxx-xxxx-xxxxx-xxxxxx" //API Key
let postmark = require("postmark")
let client = new postmark.ServerClient(serverToken);

exports.handler = (event, context, callback) => {
client.sendEmail(
    {
        From: "from@example.com", //Deine Emailadresse
        To: "to@example.com", //Ziel Emailadresse
        Subject: "test email",
        HtmlBody: "test",
        TextBody: "test"
    }
).then(response => {
    console.log(response.To);
    console.log(response.SubmittedAt);
    console.log(response.Message);
    console.log(response.MessageID);
    console.log(response.ErrorCode);
});
}

Wenn du mit der AWS Lambda Funktionen noch nicht so vertraut bist oder nicht kennst – No Problem! Ich gebe dir einen kleinen Überblick über die einzelnen Parameter, die unser handler erhält.

  • event is an object that contains data on the request
  • context contains the user information when using Identity for user authentication
  • callback is a function we can use to create a response

Mit der callback() Methode können wir testen, ob unsere Anfrage bei der Mailing Service API angekommen ist.

  callback(null, {
    statusCode: 200,
    body: 'I am on my way !'
  })
}

Schritt 3: Testen

Netlify Dev

Nun haben wir unsere erste Netlify Funktion geschrieben und möchten unser Werk testen. Dafür gibt es ein kleines Tool namens Netlify Dev. Damit können wir einen dev Server simulieren, der uns eine lokale URL ausgibt mit denen wir unseren Funktionen in der Entwicklungsumgebung ausführen und testen können.

Nach der Installation und Ausführung sollte es ungefähr so aussehen:

Testen der Funktion

Um unsere Lambda Funktion aufzurufen, müssen wir sie mit eine URL, wie die unten ausgeführte, ansprechen:

http://localhost:8888/.netlify/functions/send-email

Wenn alles geklappt hat, wird sich der Empfänger über deine erste E-Mail freuen 🙂

Schritt 4: Email mit Daten befüllen

Glückwunsch, nun hast du deine erste E-Mail mit der Netlify Function verschickt. Leider ist der Inhalt noch statisch und langweilig. Um deiner Mail mehr Leben einzuhauchen, müssen wir den Code dynamischer machen.

Sagen wir du willst mehrere Glückwünsche per E-Mail an Freunde versenden und eine Textdatei mit einer persönliche Nachricht als Anhang hinzufügen.

Alle Daten befüllst du mit einem Formular und diese werden als ein Objekt gespeichert z.B.:

const congratulation = {
  targetEmail: "test@gmail.com", 
  reason: "Geburtstag",
  firstname: "Peter",
  message: "Alles Gute zum Geburtstag. Es freut mich das du erwachsen 
           wirst"
}

Nun müssen diese Daten beim Versenden an die URL der send-mail.js Funktion übergeben werden. Dazu nutzen wir eine HTTP Request mit der Funktion URL als Zieladresse mit den Formulardaten als payload.

axios({
          method: 'POST',
          headers: { 'content-type': 'application/json' },
          url: '/.netlify/functions/send-email',
          data: congratulation, //payload
      })

Als nächstes müssen wir in unserer send-mail.js Funktion noch den Inhalt der E-Mail mit den Daten aus dem payload befüllen. Es empfiehlt sich beim Entwickeln console.log(event) zu benutzen, um sich alle Daten aus dem Request im Terminal anzeigen zulassen

Um einen Anhang hinzuzufügen, braucht man nur einen Blick auf die Postmark Node.js Dokumentation zu werfen.

const attachment = new 
                    postmark.Models.Attachment("Glückwunschtext.txt", 
                    Buffer.from("payload.message").toString("base64"), 
                    "text");

client.sendEmail(
    {
        From: "from@example.com", //Deine Emailadresse
        To: "to@example.com", //Ziel Emailadresse
        Subject: "test email",
        HtmlBody: "test",
        TextBody: "test"
        Attachments: [attachment],
    })

Die fertig angepasste Funktion sieht dann am Ende so aus.

const serverToken = "xxxx-xxxxx-xxxx-xxxxx-xxxxxx" //API Key
let postmark = require("postmark")
let client = new postmark.ServerClient(serverToken);

exports.handler = (event, callback) => {
console.log(event) 
const payload = JSON.parse(event.body)

 const attachment = new 
                    postmark.Models.Attachment("Glückwunschtext.txt", 
                    Buffer.from("payload.message").toString("base64"), 
                    "text");

client.sendEmail(
    {
        From: "tung@phmu.de", //Deine Emailadresse
        To: payload.targetEmail, //Ziel Emailadresse
        Subject: payload.reason, 
        TextBody: `Liebe ${payload.firstname}, 
                  du hast eine Glückwunschemail erhalten`,
        Attachments: [attachment],
    })
} 

Der Inhalt der verschickten Emails sollte dann so aussehen:

Von: tung@phmu.de
An: test@gmail.com
Betreff: Geburtstag

Anhang: Glückwunschtext.txt

Nachricht: 
Liebe Peter, 
du hast eine Glückwunschemail erhalten             

Wie ihr seht, ist das Versenden von E-Mails mit Netlify Functions gar nicht so kompliziert. Man könnte jetzt die E-Mails noch fancier machen wie z. B. HTML Code hinzufügen und… Aber das werde ich dir überlassen 😉