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
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, um zu prüfen, ob die Variablentypen gültig sind. In diesem Blogeintrag zeigen wir Ihnen, wie man das macht.

weiterlesen
2 min Lesezeit | Blog

Next.js Routing mit Nginx

Automatisch eine Nginx Routing-Konfiguration für statische Next.js Projekte generieren.

weiterlesen
2 min Lesezeit | Blog

Von Backend bis Frontend: wir suchen Verstärkung

Wir bieten zwei Stellen als Fullstack- oder Backend-Entwickler:innen für unsere Offices in Freiburg und Olten. Wenn du deine Leidenschaft in einem starken Team einbringen willst, dann solltest du dich bewerben.

weiterlesen
2 min Lesezeit | Blog

mapset 2.0 mit MUI

mapset 2.0 wurde unter Verwendung der Open-Source-React-Komponentenbibliothek MUI (Material-UI) umfassend überarbeitet.

weiterlesen
3 min Lesezeit | Blog

CORS in Django für Entwicklungs­umgebung

In diesem Beitrag geht es darum, wie man ein Django-Projekt so aufbaut, dass es nur im DEBUG-Modus CORS-Requests zulässt, auch wenn diese einen Login im Backend erfordern. Das Setup vereinfacht Tests in internen Entwicklungsumgebungen.

weiterlesen
5 min Lesezeit | Blog

Werkzeuge für schönere Python-Projekte

Dieser Blog-Beitrag skizziert den aktuellen Setup von pre-commit hooks, statischer Code-Analyse-Tools (Flake8, Black) und Abhängigkeitsmanagement (setuptools, pip-tools) für Python-Projekte bei geOps."

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

fon: +49 761 458 925 0
mail: info@geops.de