Umstellung von enzyme auf testing-library/react

Im Dezember 2021 gaben die Entwickler der sehr beliebten Unit-Testing-Bibliothek für React-Komponenten enzyme bekannt, dass sie die Entwicklung des Pakets einstellen werden. Wie in diesem Artikel auf dev.to erwähnt, führte React 18 zu viele bahnbrechende Änderungen ein und die Entwicklung einer kompatiblen Enzyme-Version bedeutete eine riesige, nicht durchführbare Überarbeitung des Pakets.

Da viele geOps-Anwendungen auf Enzyme für Unit-Tests angewiesen waren, musste eine alternative Lösung für Unit-Tests gefunden werden, um in Zukunft auf React 18 upgraden zu können. Glücklicherweise gibt es eine alternative Bibliothek, die auch offiziell von den React-Entwicklern empfohlen wird: testing-library/react.

Zunächst einmal ist es wichtig, einen wesentlichen Unterschied zwischen den beiden Bibliotheken zu benennen. Abgesehen von den DOM-Testmethoden bietet enzyme Test-Utilities, die auf den Komponentenzustand zugreifen und das Testen von Komponenten basierend auf ihren internen APIs ermöglichen. Stattdessen konzentriert sich testing-library/react nur auf das Testen der eigentlichen DOM-Elemente. Die Entwickler argumentieren, dass dieser Ansatz benutzerorientierter ist, da das DOM die endgültige Ausgabe ist, mit der der Benutzer tatsächlich interagiert. Dieser Ansatz vermeidet auch, dass der Test nach strukturellen Änderungen, die keinen Einfluss auf die Funktion der Komponente und die DOM-Ausgabe haben, angepasst werden muss, was sehr zeitaufwändig sein kann.

Eine ausführliche Dokumentation und ein Migrationsleitfaden beschreiben, wie enzyme-Tests mit testing-library/react umgeschrieben werden können. testing-library/react bietet eine Auswahl an Abfragefunktionen, die für eine benutzerorientierte Auswahl der DOM-Elemente  verwendet werden können.

In den folgenden Beispielen werden einige Tests in enzyme und umgeschrieben in testing-library/react verglichen.

Snapshots

Bei der Überprüfung von HTML-Baum-Snapshots testet testing-library/react das native innere oder äußere HTML des Zielelements, was die tatsächliche DOM-Ausgabe besser widerspiegelt.

enzyme

import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

test('should match snapshot', () => {
   const component = mount(<DialogComponent />);
   expect(component.html()).toMatchSnapshot();
 });

testing-library/react

import { render } from '@testing-library/react';

test('should match snapshot', () => {
   const { container } = render(<DialogComponent />);
   expect(container.innerHTML.toMatchSnapshot();
 });

Abfrage-Selektoren

react-testing-library bietet eine Auswahl an Abfragemethoden, um Ziel-DOM-Knoten zu finden. getByTestId ist besonders nützlich, da es das Auffinden von Ziel-Tags durch die Abfrage ihrer eindeutigen Test-ID präzisiert.

enzyme

import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

test('should close Dialog on close button click.', () => {
   const wrapper = mount(<ToggleButton />);
   const component = wrapper.find('ToggleButton');
   expect(component).toBeTruthy();
 });

testing-library/react

import { render } from '@testing-library/react';

test('should render toggle button', () => {
   const { getByTestId } = render(<ToggleButton />);
   const toggleBtn = getByTestId('toggle-btn');
   expect(toggleBtn).toBeTruthy();
 });

Events

Eine weitere praktische Funktion in testing-library/react ist die unkomplizierte Aktualisierung von Komponenten innerhalb von Tests mit async - await. Dies macht es sehr einfach, auf Änderungen nach Ereignissen wie Klicks oder Eingabeänderungen zu warten.

enzyme

import { configure, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

test("set state's text property on input change", () => {
   const text = 'Some text';
   const wrapper = mount(<TextInput value={text} />);
   expect(wrapper.find('TextInput').state().name)
     .toEqual(text);

   wrapper.find('textarea')
     .simulate('change', { target: { value: 'bar' } });

   expect(wrapper.find('TextInput').state().name)
     .toEqual('bar');
 });

testing-library/react

import { render, screen, fireEvent } from '@testing-library/react';

test("set state's text property on input change", async () => {
   const text = 'Some text';
   render(<TextInput value={text} />);
   const textarea = screen.getByTestId('text-area')
       .querySelector('textarea');
   expect(textarea.value).toBe(text);

   await fireEvent.change(textarea, { target: { value: 'bar' } });
   expect(textarea.value).toBe('bar');
});
geschrieben von Daniel Marsh-Hunn | 4.7.2022
Mehr zum Thema
9 min Lesezeit | Blog

Snapping stops to vehicle trajectories

How to snap points to a line string in a given order and what it has to do with quality assurance when importing public transport schedules.

weiterlesen
7 min Lesezeit | Blog

Using Redis Subscriptions efficiently in Python

Inspired by the websockets broadcast feature we built a subscription multiplexer for redis subscriptions to subscribe to Redis channels and patterns once for all relevant clients.

weiterlesen
6 min Lesezeit | Blog

Webkarten als PDF exportieren und drucken

Schon seit einiger Zeit bieten einige unserer Apps den Export unserer Karten im PDF-Format. Dieser Artikel stellt unsere Lösungen für diverse Neuerungen dieser Funktion vor.

weiterlesen
3 min Lesezeit | Blog

beyond tellerrand 2023

Am 11. September 2023 machten sich Mitglieder des Frontend-Teams von geOps auf den Weg nach Berlin, um an einer sehr interessanten und außergewöhnlichen Veranstaltung teilzunehmen: die beyond tellerrand Konferenz.

weiterlesen
3 min Lesezeit | Blog

React 18 Unterstützung für create-react-web-component

Wir wollen fünf Jahre alte Abhängigkeiten des Projekts trafimage-maps aktualisieren. Aber es scheint, dass eine Projektabhängigkeit veraltet ist. Was sollen wir tun? Das Projekt reparieren oder etwas anderes verwenden? Wir haben uns entschieden, das Projekt zu reparieren und der Gemeinschaft etwas zurückzugeben.

weiterlesen
8 min Lesezeit | Blog

Hinzufügen von Typ-Hinweisen zu vorhandenem Code in Python

Der Python-Interpreter behandelt Typen auf dynamische und flexible Weise ohne Einschränkungen bezüglich des Objekttyps, dem eine Variable zugewiesen ist. Seit Python 3.5 haben Programmierer die Möglichkeit, Typ-Annotationen in ihren Code einzufügen. Wir zeigen, wie man das macht.

weiterlesen

Kontakt

geOps AG
Solothurnerstrasse 235
CH-4600 Olten

fon: +41 61 588 05 05
mail: info@geops.ch
geOps GmbH
Bismarckallee 10
D-79098 Freiburg im Breisgau

fon: +49 761 458 925 0
mail: info@geops.de
Impressum | Datenschutz | Bedingungen