Schreiben eines Jest-Tests
Lernziele
Nachdem Sie diese Lektion abgeschlossen haben, sind Sie in der Lage, die folgenden Aufgaben auszuführen:
- Schreiben eines Tests zum Prüfen Ihres Setups
- Schreiben eines fehlschlagenden Tests und Ändern Ihrer Komponente, damit sie den Test besteht
- Nennen der grundlegenden Jest-Befehle
- Erläutern von Lebenszyklus-Hooks
Ausgangspunkt ist eine Lightning-Webkomponente
Zum Testen einer Lightning-Webkomponente benötigen wir zunächst eine Webkomponente, die wir testen können.
Erstellen einer Lightning-Webkomponente
- Öffnen Sie in Visual Studio Code die Befehlspalette, indem Sie unter Windows Strg+Umschalt+P bzw. unter macOS Befehl+Umschalt+P drücken.
- Geben Sie
lightning web
ein. - Wählen Sie SFDX: Create Lightning Web Component aus.
- Geben Sie als Namen der neuen Komponente
unitTest
ein. - Drücken Sie die Eingabetaste.
- Drücken Sie erneut die Eingabetaste, um die Standardeinstellung
force-app/main/default/lwc
zu übernehmen.
Damit erstellen Sie im Verzeichnis "lwc" das Verzeichnis "unitTest" mit den anfänglichen Basisdateien.
Schreiben eines einfachen Tests
Jest-Tests werden anders geschrieben, gespeichert und ausgeführt als Jasmine- oder Mocha-Tests, die für den Lightning Testing Service für Aura-Komponenten geschrieben werden. Jest-Tests sind lokal und werden unabhängig von Salesforce gespeichert und ausgeführt. Es wird sogar ein Fehler gemeldet, wenn Sie versuchen, Jest-Tests in Ihrer Salesforce-Organisation bereitzustellen. Obwohl Jest-Tests für Lightning-Webkomponenten nicht in Ihrer Salesforce-Organisation bereitgestellt werden, sollten Sie sie unbedingt zusammen mit der Komponente in Ihr Versionskontrollsystem übertragen.
Der Ordner "__tests__"
Die Testdateien müssen von den anderen Komponentendateien getrennt werden. Falls ein solcher Ordner nicht automatisch angelegt wurde, erstellen Sie einen Ordner namens "__tests__" auf der obersten Ebene des Paketordners Ihrer Komponente. Speichern Sie alle Tests für diese Komponente im Ordner "__tests__".
- Klicken Sie in Visual Studio Code mit der rechten Maustaste auf das Verzeichnis
unitTest
und wählen Sie New Folder aus. - Geben Sie
__tests__
ein. - Drücken Sie die Eingabetaste.
Konfigurieren von ".forceignore"
Geben Sie Tests für andere Teammitglieder oder Systeme frei, indem Sie den Ordner "__tests__" in das Versionskontrollsystem übertragen. Sie sind ein wertvoller Teil Ihres Projekts und Continuous Integration-Prozesses. Damit sie nicht in Salesforce bereitgestellt werden, enthält die Datei ".forceignore" eine entsprechende Ausschlussanweisung.
- Stellen Sie sicher, dass die Datei
.forceignore
Ihres Projekts folgende Ausschlüsse enthält. Fügen Sie die entsprechenden Anweisungen andernfalls hinzu und speichern Sie die Datei.# LWC configuration files **/jsconfig.json **/.eslintrc.json # LWC Jest **/__tests__/**
Erstellen einer Jest-Testdatei
Unser erster Test ist einfach. Wir haben eine sum()
-Funktion, von der erwartet wird, dass sie zwei Zahlen addiert, die ihr als Argumente übergeben werden.
- Klicken Sie in Visual Studio Code mit der rechten Maustaste auf das Verzeichnis
__tests__
und wählen Sie New File aus. - Geben Sie
sum.test.js
ein. - Drücken Sie die Eingabetaste.
- Geben Sie folgenden Code in die neueste Testdatei ein:
import { sum } from '../sum'; describe('sum()', () => { it('should add 1 and 2 returning 3', () => { expect(sum(1, 2)).toBe(3); }); });
- Speichern Sie die Datei.
Ausführen des Tests
- Wählen Sie in Visual Studio Code zuerst View und dann Terminal aus. Damit öffnen Sie ein Terminal in Visual Studio Code. Das Terminal ist standardmäßig auf das oberste Verzeichnis des Projekts festgelegt.
- Führen Sie im Terminal den folgenden Befehl aus der vorherigen Einheit aus:
npm run test:unit
- Der Test schlägt fehl, da die Summenfunktion fehlt.
Sehen wir uns an, wie sich das beheben lässt.
- Klicken Sie in Visual Studio Code mit der rechten Maustaste auf das Verzeichnis
unitTest
und wählen Sie New File aus. - Geben Sie
sum.js
ein. - Drücken Sie die Eingabetaste.
- Geben Sie den folgenden Code in die neue Datei ein:
export function sum(x, y) { return x + y; }
- Speichern Sie die Datei.
- Führen Sie den Test im Terminal erneut aus:
npm run test:unit
- Dieses Mal wird der Test erfolgreich ausgeführt.
Herzlichen Glückwunsch! Sie haben gerade geprüft, dass Jest eingerichtet ist und funktioniert.
Sehen wir uns den Testcode und die einzelnen Abläufe an.
import { sum } from '../sum'; describe('sum()', () => { it('should add 1 and 2 returning 3', () => { expect(sum(1, 2)).toBe(3); }); });
- Zeile 1 importiert die exportierte
sum
-Funktion aus der JavaScript-Datei "sum". - In Zeile 3 beginnt die Jest-Testsuite. Die Funktion (bzw. der Block)
describe
ist eine Testsuite, die zwei Argumente akzeptiert. Das erste Argument ist die Beschreibung der Einheit, die wir testen; sie hat meist die Form eines Substantivs. Das zweite Argument ist eine Rückruffunktion mit einem oder mehreren Tests. Sie könnendescribe
-Testsuiten auch ineinander verschachteln, um den Code klarer zu strukturieren. - Zeile 4 enthält den eigentlichen Test (
it
ist ein Alias fürtest
). Die Funktion (bzw. der Block)it
akzeptiert ebenfalls zwei Argumente. Das erste Argument ist eine Beschreibung dessen, was wir erwarten, und beginnt meist mit einem Verb. Das zweite Argument ist eine Rückruffunktion, die den Test aufbaut und die Assertions oder Erwartungen für den Test enthält. - Zeile 5 ist die
expect
-Anweisung, die die Erfolgsbedingung festlegt, nämlich dass diesum
-Funktion die beiden Argumente 1 und 2 addiert und 3 zurückgibt.toBe
ist eine der vielen Jest-Abgleichsfunktionen ("Matcher").
Fügen Sie direkt unter Zeile 5 die folgende Zeile mit einer weiteren Assertion hinzu:expect(sum(1, 2)).not.toBeGreaterThan(3);
- Durch Hinzufügen von
.not
und.toBeGreaterThan
stellen Sie sicher, dass der Wert nicht größer als 3 ist. Sie könnten eine weitere expect-Anweisung mit.not.toBeLessThan(3)
hinzufügen.
Und nun zum Test der Lightning-Webkomponente:
Jest-Tests für eine Lightning-Webkomponente sollten das Verhalten einer einzelnen Komponente isoliert und mit möglichst wenige Abhängigkeiten von externen Komponenten oder Services testen.
Erneutes Durchlaufen des Prozesses mit einer Testdatei namens unitTest
Mit diesem Test wird überprüft, ob eine Eigenschaft festgelegt ist und beim Hinzufügen zum DOM der gewünschte Text angezeigt wird. Die Datei unitTest.test.js
wurde mit dem Ordner __tests__
bei der Ausführung des Befehls SFDX: Create Lightning Web Component erstellt.
- Ersetzen Sie den Code in
unitTest.test.js
durch den folgenden:import { createElement } from 'lwc'; import UnitTest from 'c/unitTest'; describe('c-unit-test', () => { afterEach(() => { // The jsdom instance is shared across test cases in a single file so reset the DOM while(document.body.firstChild) { document.body.removeChild(document.body.firstChild); } }); it('displays unit status with default unitNumber', () => { const element = createElement('c-unit-test', { is: UnitTest }); expect(element.unitNumber).toBe(5); // Add the element to the jsdom instance document.body.appendChild(element); // Verify displayed greeting const div = element.shadowRoot.querySelector('div'); expect(div.textContent).toBe('Unit 5 alive!'); }); });
- Speichern Sie die Datei.
- Führen Sie die Tests im Terminal erneut aus:
npm run test:unit
- Die Tests werden mit folgenden Ergebnissen fehlschlagen:
Test Suites: 1 failed, 1 passed, 2 total Tests: 1 failed, 1 passed, 2 total
Sehen wir uns zuerst den Testcode an, um die Voraussetzungen festzustellen. Dann ändern wir den Code entsprechend, damit die Tests erfolgreich abgeschlossen werden.
- Zeile 1 ist neu. Sie importiert die Methode
createElement
aus demlwc
-Framework. Sie steht nur in Tests zur Verfügung. - Zeile 2 importiert die Klasse
UnitTest
aus dem JavaScript-Steuerfeld der Komponente. - Zeile 4 enthält den Anfang des Testsuitenblocks
describe
. - Zeile 5 enthält eine Jest-Bereinigungsmethode.
afterEach()
ist eine der Einrichtungs- und Bereinigungsmethoden von Jest.afterEach()
wird nach jedem Test im zugehörigen describe-Block ausgeführt. DieseafterEach()
-Methode setzt am Ende des Tests das DOM zurück. Jest führt bei der Testausführung keinen Browser aus. Jest nutzt "jsdom" zur Bereitstellung einer Umgebung, die sich ähnlich wie das DOM oder Dokument eines Browsers verhält. Jede Testdatei erhält eine eigene Instanz von "jsdom", und Änderungen werden zwischen Tests in der Datei nicht zurückgesetzt. Es hat sich daher bewährt, die Datei zwischen Tests zu bereinigen, damit sich die Ausgabe eines Tests nicht auf andere Tests auswirkt. Es stehen noch weitere Einrichtungs- und Bereinigungsmethoden zur Verfügung. Mehr dazu finden Sie im Abschnitt "Ressourcen". - Zeile 12 enthält den Anfang des Testblocks
it
. - In Zeile 13 kommt die importierte Methode
createElement
zum Einsatz. Sie erstellt eine Instanz der Komponente und weist sie der Konstantenelement
zu. - In Zeile 16 prüft die Assertion
expect
, dass die VariableunitNumber
auf 5 eingestellt ist. Dies ist die erste Anforderung, auf die wir testen, dassunitNumber
zuerst auf 5 eingestellt ist. - Zeile 18 fügt das
element
mit derappendChild
-Methode zur jsdom-Version vondocument.body
hinzu. Der Aufruf verknüpft die Lightning-Webkomponente mit dem DOM und rendert sie, was auch bedeutet, dass die Lebenszyklus-Hooks "connectedCallback()" und "renderedCallback()" aufgerufen werden (dazu später mehr). - In Zeile 20 wird
querySelector
(eine standardmäßige DOM-Abfragemethode) verwendet, um das DOM nach einemdiv
-Tag zu durchsuchen. Verwenden Sieelement.shadowRoot
als übergeordnetes Element für die Abfrage. Es handelt sich dabei um eine API nur für Tests, mit der Sie einen Blick hinter die virtuelle Systemgrenze werfen können, um die virtuelle Struktur einer Komponente zu inspizieren. - Zum Abschluss wird in Zeile 21 mit
expect
dertextContent
desdiv
-Tags geprüft, um zu bestätigen, dass er 'Unit 5 alive!' lautet. Das ist die letzte Anforderung: Bestätigen, dass der Text korrekt lautet.
Damit der Test erfolgreich durchgeführt wird, müssen Sie Code zu den HTML- und JavaScript-Dateien namens "unitTest" hinzufügen. Wir fügen Code hinzu, um die Anforderungen zu erfüllen.
- Klicken Sie auf die Datei
unitTest.html
, um sie zu öffnen. - Überschreiben Sie
unitTest.html
mit folgendem Code:<template> <lightning-card title="Unit Status" icon-name="standard:bot"> <div class="slds-m-around_medium"> Unit {unitNumber} alive! </div> </lightning-card> </template>
- Speichern Sie die Datei.
- Klicken Sie auf die Datei
unitTest.js
, um sie zu öffnen, und überschreiben Sie mit folgendem Code:import { LightningElement, api } from 'lwc'; import { sum } from './sum'; export default class UnitTest extends LightningElement { @api unitNumber = sum(2,3); }
- Speichern Sie die Datei und führen Sie die Tests aus:
npm run test:unit
- Alle Tests werden erfolgreich ausgeführt.
Testen asynchroner DOM-Aktualisierungen
Wenn sich der Zustand einer Lightning-Webkomponente ändert, wird das DOM asynchron aktualisiert. Um sicherzustellen, dass Ihr Test bis zum Abschluss der Aktualisierungen wartet, bevor er das Ergebnis bewertet, geben Sie ein aufgelöstes Promise-Objekt zurück. Dazu verketten Sie den restlichen Testcode mit dem aufgelösten Promise. Jest wartet, bis die Kette des Promise abgeschlossen ist, bevor es den Test beendet. Wird das Promise abgelehnt, lässt Jest den Test scheitern.
- Öffnen Sie die Datei
unitTest.test.js
. - Fügen Sie nach dem letzten Test diesen zweiten Test hinzu.
In diesem Test möchten wir prüfen, ob eine Eigenschaftsänderung den Text im DOM aktualisiert.it('displays unit status with updated unitNumber', () => { const element = createElement('c-unit-test', { is: UnitTest }); // Add the element to the jsdom instance document.body.appendChild(element); // Update unitNumber after element is appended element.unitNumber = 6 const div = element.shadowRoot.querySelector('div'); // Verify displayed unit status expect(div.textContent).toBe('Unit 6 alive!'); });
- Speichern Sie die Datei und führen Sie die Tests aus.
npm run test:unit
- Der Test schlägt mit folgender Meldung fehl:
Expected: "Unit 6 alive!" Received: "Unit 5 alive!"
Was passiert hier? Die expect
-Anweisung stellt fest, dass div.textContext
"Unit 6 alive" lauten sollte, aber noch "Unit 5 alive!" lautet. Damit die Änderung sichtbar wird, müssen wir darauf warten, indem wir ein aufgelöstes Promise
zurückgeben.
- Ersetzen Sie die fehlschlagende
expect
-Anweisung durch den folgenden Code. Fügen Sie den Code dabei direkt nach dem Kommentar// Verify display unit status
ein:expect(div.textContent).not.toBe('Unit 6 alive!'); // Return a promise to wait for any asynchronous DOM updates. Jest // will automatically wait for the Promise chain to complete before // ending the test and fail the test if the promise rejects. return Promise.resolve().then(() => { expect(div.textContent).toBe('Unit 6 alive!'); });
- Führen Sie den Test mit demselben Befehl wie beim letzten Mal aus oder nutzen Sie eine der anderen Optionen im Abschnitt "Ausführen von Jest-Tests" in der vorherigen Einheit.
- Dieses Mal wird der Test erfolgreich ausgeführt.
So weit, so gut. Sie haben jetzt drei erfolgreiche Tests in zwei Testsuiten. Als Nächstes fügen Sie einen vierten Test hinzu, damit Sie bei der Änderung eines Eingabefelds prüfen können, ob der Einheitenstatus aktualisiert wird. Dazu verwenden Sie ein Änderungsereignis im Eingabefeld.
- Öffnen Sie die Datei
unitTest.test.js
, falls sie nicht bereits geöffnet ist. - Fügen Sie nach dem zuletzt hinzugefügten Test eine Zeile ein und fügen Sie dann diesen dritten Test zu der Suite hinzu:
it('displays unit status with input change event', () => { const element = createElement('c-unit-test', { is: UnitTest }); document.body.appendChild(element); const div = element.shadowRoot.querySelector('div'); // Trigger unit status input change const inputElement = element.shadowRoot.querySelector('lightning-input'); inputElement.value = 7; inputElement.dispatchEvent(new CustomEvent('change')); return Promise.resolve().then(() => { expect(div.textContent).toBe('Unit 7 alive!'); }); });
- Speichern Sie die Datei und führen Sie den Test aus. Der Test schlägt mit folgender Meldung fehl:
Wie Sie sehen, wurde nur ein Test ausgeführt, die anderen beiden wurden übersprungen.
Sehen wir uns an, was getestet wird:
- Die ersten paar Zeilen sollten Ihnen vertraut sein. Sie fügen UnitTest zu
document.body
hinzu und erstellen dann einen Verweis aufdiv
. - Die Konstante
inputElement
wird mit einem Verweis auf ein "lightning-input"-Feld eingestellt. - Als Nächstes wird der Wert dieses Eingabefelds auf 7 festgelegt.
- Anschließend verwenden wir
dispatchEvent
, um ein Ereignis mit einemCustomEvent
auszulösen, das den Ereignistyp "change" verwendet. - Das
Promise
ist uns ebenfalls bekannt. Die einzige Änderung ist hier der Wert des geänderten Eingabefelds.
Wir ändern den Code nun so ab, dass die Tests erfolgreich abgeschlossen werden. Dazu fügen Sie lightning-input
zur HTML-Datei und die handleChange
-Methode zum JavaScript-Steuerfeld hinzu.
- Öffnen Sie
unitTest.html
. - Fügen Sie den folgenden Code zwischen den
lightning-card
-Tags und vordiv
hinzu:<lightning-input label="Unit Number" value={unitNumber} onchange={handleChange} > </lightning-input>
- Speichern Sie die Datei.
- Öffnen Sie
unitTest.js
. - Fügen Sie den folgenden Code nach der Anweisung
@api unitNumber
ein:handleChange(event) { this.unitNumber = event.target.value; }
- Speichern Sie die Datei und führen Sie die Tests aus.
- Die Tests werden wegen des hinzugefügten Eingabeelements und des JavaScript-Handlers erfolgreich ausgeführt.
Testen von Lebenszyklus-Hooks
Der Lebenszyklus von Lightning-Webkomponenten wird vom Framework verwaltet. Das Framework erstellt Komponenten, fügt sie zum DOM hinzu bzw. entfernt sie daraus und rendert DOM-Aktualisierungen, wenn sich der Zustand einer Komponente ändert. Es gibt mehrere Methoden für die Interaktion mit dem Lebenszyklus.
Der Lebenszyklus-Hook connectedCallback()
wird ausgelöst, wenn eine Komponente in das DOM eingefügt wird. Der Lebenszyklus-Hook connectedCallback()
wird ausgelöst, wenn eine Komponente aus dem DOM entfernt wird. Ein Verwendungszweck für diese Hooks besteht darin, Ereignis-Listener zu registrieren bzw. ihre Registrierung zu entfernen.
Ein gutes Beispiel dafür finden Sie im Repository "lwc-recipes" in lmsSubscriberWebComponent.
Als Nächstes befassen wir uns mit dem Schreiben von Jest-Tests für Wire-Services.
Ressourcen
- Salesforce-Blog: Einheitentests für Lightning-Webkomponenten mit Jest (Englisch)
- Entwicklerhandbuch: Schreiben von Jest-Tests für Lightning-Webkomponenten (Englisch)
- Entwicklerhandbuch: Lebenszyklus von Lightning-Webkomponenten (Englisch)
- Externe Website: Jest: Erste Schritte (Englisch)
- Externe Website: Jest: Expect-Verweis (Englisch)
- Externe Website: Jest: Vor- und Nachbereitung von Tests (Englisch)
- Externe Website: GitHub: salesforce/sfdx-lwc-jest
- Externe Website: GitHub: trailheadapps/lwc-recipes
- Externe Website: Wiki: Testgetriebene Entwicklung