Erste Schritte mit React Testing Library

Avatar of Kingsley Silas
Kingsley Silas on

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ich kann raten, was Sie denken: *Noch* eine React-Testing-Bibliothek? So viele wurden bereits hier auf CSS-Tricks behandelt (verdammt, ich habe bereits eine veröffentlicht über Jest und Enzyme), gibt es also nicht bereits genug Optionen?

Aber react-testing-library ist nicht nur eine weitere Testbibliothek. Es ist eine Testbibliothek, ja, aber eine, die auf einem grundlegenden Prinzip basiert, das sie von anderen unterscheidet.

Je mehr Ihre Tests dem ähneln, wie Ihre Software verwendet wird, desto mehr Vertrauen können sie Ihnen geben.

Sie versucht, Tests dafür zu adressieren, *wie* ein Benutzer Ihre Anwendung nutzen wird. Tatsächlich geschieht dies auf eine Weise, die verhindert, dass Tests selbst bei Refactoring von Komponenten fehlschlagen. Und ich weiß, dass das etwas ist, auf das wir alle irgendwann in unserer React-Reise gestoßen sind.

Wir werden nun einige Zeit damit verbringen, gemeinsam Tests mit react-testing-library für eine einfache To-Do-Anwendung zu schreiben, die ich erstellt habe. Sie können das Repository lokal klonen

git clone https://github.com/kinsomicrote/todoapp-test.git

Und wenn Sie das tun, installieren Sie als Nächstes die erforderlichen Pakete

## yarn
yarn add --dev react-testing-library jest-dom

## npm
npm install --save-dev react-testing-library jest-dom

Falls Sie sich fragen, warum Jest dabei ist: Wir verwenden es für die Bestätigung. Erstellen Sie einen Ordner namens __test__ im Verzeichnis src und eine neue Datei namens App.test.js.

Snapshots erstellen

Snapshot-Tests speichern eine Aufzeichnung der Tests, die an einer getesteten Komponente durchgeführt wurden, um visuell zu sehen, was sich zwischen Änderungen ändert.

Wenn wir diesen Test zum ersten Mal ausführen, erstellen wir den ersten Snapshot davon, wie die Komponente aussieht. Daher wird der erste Test mit Sicherheit bestehen, denn nun ja, es gibt keinen anderen Snapshot, mit dem er verglichen werden könnte, der etwas Fehlerhaftes anzeigen würde. Er schlägt nur fehl, wenn wir eine neue Änderung an der Komponente vornehmen, indem wir ein neues Element, eine Klasse, eine Komponente oder Text hinzufügen. Etwas hinzufügen, das nicht da war, als der Snapshot erstellt oder zuletzt aktualisiert wurde.

Der Snapshot-Test wird der erste sein, den wir hier schreiben werden. Öffnen wir die Datei App.test.js und gestalten wir sie wie folgt:

import React from 'react';
import { render, cleanup } from "react-testing-library";
import "jest-dom/extend-expect";
import App from './App';

afterEach(cleanup);

it("matches snapshot", () => {
  const { asFragment } = render(<App />);
  expect(asFragment()).toMatchSnapshot();
});

Dies importiert die notwendigen Pakete, die wir zum Schreiben und Ausführen der Tests verwenden. render wird verwendet, um die Komponente anzuzeigen, die wir testen möchten. Wir verwenden cleanup, um nach jedem Testlauf aufzuräumen – wie Sie an der Zeile afterEach(cleanup) sehen können.

Mit asFragment erhalten wir ein DocumentFragment der gerenderten Komponente. Dann erwarten wir, dass es mit dem erstellten Snapshot übereinstimmt.

Lassen Sie uns den Test ausführen, um zu sehen, was passiert.

## yarn
yarn test

## npm
npm test

Wie wir jetzt wissen, wird ein Snapshot der Komponente in einem neuen Ordner namens __snapshots__ innerhalb des Verzeichnisses __tests__ erstellt, wenn dies unser erster Test ist. Wir erhalten darin eine Datei namens App.test.js.snap, die wie folgt aussieht:

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`matches snapshot 1`] = `
<DocumentFragment>
  <div
    class="container"
  >
    <div
      class="row"
    >
      <div
        class="col-md-6"
      >
        <h2>
          Add Todo
        </h2>
      </div>
    </div>
    <form>
      <div
        class="row"
      >
        <div
          class="col-md-6"
        >
          <input
            class="form-control"
            data-testid="todo-input"
            placeholder="Enter a task"
            type="text"
            value=""
          />
        </div>
      </div>
      <div
        class="row"
      >
        <div
          class="col-md-6"
        >
          <button
            class="btn btn-primary"
            data-testid="add-task"
            type="submit"
          >
            Add Task
          </button>
        </div>
      </div>
    </form>
    <div
      class="row todo-list"
    >
      <div
        class="col-md-6"
      >
        <h3>
          Lists
        </h3>
        <ul
          data-testid="todos-ul"
        >
          <li>
            <div>
              Buy Milk
              <button
                class="btn btn-danger"
              >
                X
              </button>
            </div>
          </li>
          <li>
            <div>
              Write tutorial
              <button
                class="btn btn-danger"
              >
                X
              </button>
            </div>
          </li>
        </ul>
      </div>
    </div>
  </div>
</DocumentFragment>
`;

Nun testen wir DOM-Elemente und Ereignisse

Unsere App enthält zwei To-Do-Elemente, die standardmäßig beim ersten Start der App angezeigt werden. Wir möchten sicherstellen, dass sie tatsächlich standardmäßig beim ersten App-Start angezeigt werden. Um dies zu testen, müssen wir die unsortierte Liste (<ul>) ansprechen und deren Länge überprüfen. Wir erwarten, dass die Länge gleich zwei ist – der Anzahl der Elemente.

it('it displays default todo items', () => {
  const { getByTestId } = render(<App />);
  const todoList = getByTestId('todos-ul');
  expect(todoList.children.length).toBe(2);  
});

In diesem Ausschnitt verwenden wir getByTestId, um die Test-IDs aus der App-Komponente zu extrahieren. Dann setzen wir todoList, um das Element todos-ul anzusprechen. Dies sollte zwei zurückgeben.

Nutzen Sie das bisher Gelernte, um einen Test zu schreiben, der bestätigt, dass ein Benutzer Werte in das Eingabefeld eingeben kann. Hier sind die Dinge, die Sie tun möchten:

  • Holen Sie sich das Eingabefeld
  • Setzen Sie einen Wert für das Eingabefeld
  • Lösen Sie ein Änderungsereignis aus
  • Bestätigen Sie, dass das Eingabefeld den Wert hat, den Sie ihm in Schritt 2 zugewiesen haben

Schauen Sie nicht auf meine Antwort unten! Nehmen Sie sich so viel Zeit, wie Sie brauchen.

Immer noch dabei? Großartig! Ich hole mir einen Kaffee und bin gleich zurück.

Mmm, Kaffee. ☕️

Oh, Sie sind fertig! Sie sind spitze. Vergleichen wir die Antworten. Meine sieht so aus:

it('allows input', () => {
  const {getByTestId } = render(<App />)
  let item = 'Learn React'
  const todoInputElement = getByTestId('todo-input');
  todoInputElement.value = item;
  fireEvent.change(todoInputElement);
  expect(todoInputElement.value).toBe('Learn React')
});

Mit getByTestId kann ich die Test-IDs in der Anwendung extrahieren. Dann erstelle ich eine Variable, die auf die Zeichenfolge Learn React gesetzt wird, und mache sie zum Wert des Eingabefeldes. Als Nächstes hole ich mir das Eingabefeld anhand seiner Test-ID und löse das Änderungsereignis aus, nachdem ich den Wert des Eingabefeldes gesetzt habe. Danach bestätige ich, dass der Wert des Eingabefeldes tatsächlich Learn React ist.

Passt das zu Ihrer Antwort? Hinterlassen Sie einen Kommentar, wenn Sie eine andere Methode haben!

Als Nächstes testen wir, ob wir ein neues To-Do-Element hinzufügen können. Wir müssen das Eingabefeld, den Button zum Hinzufügen neuer Elemente und die unsortierte Liste abrufen, da dies alle Elemente sind, die zum Erstellen eines neuen Elements benötigt werden.

Wir setzen einen Wert für das Eingabefeld und lösen dann einen Button-Klick aus, um die Aufgabe hinzuzufügen. Dies können wir tun, indem wir den Button mit getByText abrufen – durch Auslösen eines Klickereignisses auf dem DOM-Element mit dem Text Add Task sollten wir ein neues To-Do-Element hinzufügen können.

Lassen Sie uns bestätigen, dass die Anzahl der Kinder (Listenelemente) im unsortierten Listenelement gleich drei ist. Dies setzt voraus, dass die Standardaufgaben noch vorhanden sind.

it('adds a new todo item', () => {
  const { getByText, getByTestId } = render(<App />);
  const todoInputElement = getByTestId('todo-input');
  const todoList = getByTestId('todos-ul');
  todoInputElement.value = 'Learn React';
  fireEvent.change(todoInputElement);
  fireEvent.click(getByText('Add Task'))
  expect(todoList.children.length).toBe(3); 
});

Ziemlich gut, oder?

Dies ist nur eine Möglichkeit, in React zu testen

Sie können react-testing-library in Ihrer nächsten React-Anwendung ausprobieren. Die Dokumentation im Repository ist sehr ausführlich und – wie bei den meisten Tools – der beste Ausgangspunkt. Kent C. Dodds hat sie entwickelt und bietet einen vollständigen Kurs zum Testen bei Frontend Masters (Abonnement erforderlich), der auch die Besonderheiten von react-testing-library behandelt.

Das gesagt, dies ist nur eine Testressource für React. Es gibt natürlich auch andere, aber hoffentlich ist dies eine, die Sie jetzt ausprobieren möchten, nachdem Sie einen kleinen Einblick erhalten haben, aber nutzen Sie natürlich das, was für Ihr Projekt am besten geeignet ist.