Zum Hauptinhalt springen
Version: 29.7

React-Apps testen

Inoffizielle Beta-Übersetzung

Diese Seite wurde von PageTurner AI übersetzt (Beta). Nicht offiziell vom Projekt unterstützt. Fehler gefunden? Problem melden →

Bei Facebook verwenden wir Jest, um React-Anwendungen zu testen.

Einrichtung

Einrichtung mit Create React App

Wenn Sie neu bei React sind, empfehlen wir Create React App. Es ist sofort einsatzbereit und liefert Jest bereits mit! Sie müssen lediglich react-test-renderer für Snapshot-Rendering hinzufügen.

Ausführen:

npm install --save-dev react-test-renderer

Einrichtung ohne Create React App

Bei bestehenden Anwendungen müssen Sie einige Pakete installieren, damit alles reibungslos funktioniert. Wir verwenden das babel-jest-Paket und das react-Babel-Preset, um Code in der Testumgebung zu transformieren. Siehe auch Babel-Nutzung.

Ausführen:

npm install --save-dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer

Ihre package.json sollte etwa so aussehen (wobei <current-version> die aktuelle Paketversion ist). Fügen Sie die Skripte und Jest-Konfigurationseinträge hinzu:

{
"dependencies": {
"react": "<current-version>",
"react-dom": "<current-version>"
},
"devDependencies": {
"@babel/preset-env": "<current-version>",
"@babel/preset-react": "<current-version>",
"babel-jest": "<current-version>",
"jest": "<current-version>",
"react-test-renderer": "<current-version>"
},
"scripts": {
"test": "jest"
}
}
babel.config.js
module.exports = {
presets: [
'@babel/preset-env',
['@babel/preset-react', {runtime: 'automatic'}],
],
};

Und schon können Sie loslegen!

Snapshot-Tests

Erstellen wir einen Snapshot-Test für eine Link-Komponente, die Hyperlinks rendert:

Link.js
import {useState} from 'react';

const STATUS = {
HOVERED: 'hovered',
NORMAL: 'normal',
};

export default function Link({page, children}) {
const [status, setStatus] = useState(STATUS.NORMAL);

const onMouseEnter = () => {
setStatus(STATUS.HOVERED);
};

const onMouseLeave = () => {
setStatus(STATUS.NORMAL);
};

return (
<a
className={status}
href={page || '#'}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
{children}
</a>
);
}
Hinweis

Beispiele verwenden Funktionskomponenten, aber Klassenkomponenten können analog getestet werden. Siehe React: Funktions- und Klassenkomponenten. Hinweis: Bei Klassenkomponenten soll Jest Props testen, nicht direkt Methoden.

Verwenden wir nun den Test-Renderer von React und die Snapshot-Funktion von Jest, um mit der Komponente zu interagieren, die gerenderte Ausgabe zu erfassen und eine Snapshot-Datei zu erstellen:

Link.test.js
import renderer from 'react-test-renderer';
import Link from '../Link';

it('changes the class when hovered', () => {
const component = renderer.create(
<Link page="http://www.facebook.com">Facebook</Link>,
);
let tree = component.toJSON();
expect(tree).toMatchSnapshot();

// manually trigger the callback
renderer.act(() => {
tree.props.onMouseEnter();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();

// manually trigger the callback
renderer.act(() => {
tree.props.onMouseLeave();
});
// re-rendering
tree = component.toJSON();
expect(tree).toMatchSnapshot();
});

Wenn Sie yarn test oder jest ausführen, wird eine Ausgabedatei wie die folgende erzeugt:

__tests__/__snapshots__/Link.test.js.snap
exports[`changes the class when hovered 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;

exports[`changes the class when hovered 2`] = `
<a
className="hovered"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;

exports[`changes the class when hovered 3`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
>
Facebook
</a>
`;

Beim nächsten Testlauf wird die gerenderte Ausgabe mit der zuvor erstellten Snapshot verglichen. Die Snapshot sollte zusammen mit Codeänderungen committet werden. Wenn ein Snapshot-Test fehlschlägt, müssen Sie prüfen, ob es sich um eine beabsichtigte oder unbeabsichtigte Änderung handelt. Wenn die Änderung erwartet wurde, können Sie Jest mit jest -u aufrufen, um den bestehenden Snapshot zu überschreiben.

Der Beispielcode ist unter examples/snapshot verfügbar.

Snapshot-Tests mit Mocks, Enzyme und React 16+

Bei Snapshot-Tests mit Enzyme und React 16+ gibt es eine Einschränkung. Wenn Sie ein Modul so mocken:

jest.mock('../SomeDirectory/SomeComponent', () => 'SomeComponent');

Erhalten Sie Konsolenwarnungen:

Warning: <SomeComponent /> is using uppercase HTML. Always use lowercase HTML tags in React.

# Or:
Warning: The tag <SomeComponent> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.

React 16 löst diese Warnungen durch seine Elementtyp-Prüfung aus, die das gemockte Modul nicht besteht. Ihre Optionen:

  1. Als Text rendern: Props werden im Snapshot nicht sichtbar, aber es ist einfach:

    jest.mock('./SomeComponent', () => () => 'SomeComponent');
  2. Als benutzerdefiniertes Element rendern: DOM-"Custom Elements" werden nicht geprüft und lösen keine Warnungen aus. Sie sind kleingeschrieben und enthalten Bindestriche:

    jest.mock('./Widget', () => () => <mock-widget />);
  3. react-test-renderer nutzen: Dieser kümmert sich nicht um Elementtypen und akzeptiert z.B. SomeComponent. Prüfen Sie Snapshots mit dem Test-Renderer und Komponentenverhalten separat mit Enzyme.

  4. Warnungen global deaktivieren (in Ihrer Jest-Setup-Datei):

    jest.mock('fbjs/lib/warning', () => require('fbjs/lib/emptyFunction'));

    Dies ist normalerweise nicht empfehlenswert, da nützliche Warnungen verloren gehen. Bei React-Native-Tests sind jedoch viele DOM-Warnungen irrelevant. Alternativ können Sie console.warn anpassen und spezifische Warnungen unterdrücken.

DOM-Tests

Zum Überprüfen und Manipulieren gerenderter Komponenten können Sie @testing-library/react, Enzyme oder Reacts TestUtils nutzen. Das folgende Beispiel verwendet @testing-library/react.

@testing-library/react

npm install --save-dev @testing-library/react

Implementieren wir eine Checkbox, die zwischen zwei Beschriftungen wechselt:

CheckboxWithLabel.js
import {useState} from 'react';

export default function CheckboxWithLabel({labelOn, labelOff}) {
const [isChecked, setIsChecked] = useState(false);

const onChange = () => {
setIsChecked(!isChecked);
};

return (
<label>
<input type="checkbox" checked={isChecked} onChange={onChange} />
{isChecked ? labelOn : labelOff}
</label>
);
}
__tests__/CheckboxWithLabel-test.js
import {cleanup, fireEvent, render} from '@testing-library/react';
import CheckboxWithLabel from '../CheckboxWithLabel';

// Note: running cleanup afterEach is done automatically for you in @testing-library/react@9.0.0 or higher
// unmount and cleanup DOM after the test is finished.
afterEach(cleanup);

it('CheckboxWithLabel changes the text after click', () => {
const {queryByLabelText, getByLabelText} = render(
<CheckboxWithLabel labelOn="On" labelOff="Off" />,
);

expect(queryByLabelText(/off/i)).toBeTruthy();

fireEvent.click(getByLabelText(/off/i));

expect(queryByLabelText(/on/i)).toBeTruthy();
});

Den Code für dieses Beispiel finden Sie unter examples/react-testing-library.

Benutzerdefinierte Transformer

Wenn Sie erweiterte Funktionen benötigen, können Sie auch Ihren eigenen Transformer erstellen. Hier ein Beispiel mit @babel/core anstelle von babel-jest:

custom-transformer.js
'use strict';

const {transform} = require('@babel/core');
const jestPreset = require('babel-preset-jest');

module.exports = {
process(src, filename) {
const result = transform(src, {
filename,
presets: [jestPreset],
});

return result || src;
},
};

Vergessen Sie nicht, die Pakete @babel/core und babel-preset-jest zu installieren, damit dieses Beispiel funktioniert.

Für die Integration mit Jest aktualisieren Sie Ihre Jest-Konfiguration mit: "transform": {"\\.js$": "path/to/custom-transformer.js"}.

Falls Sie einen Transformer mit Babel-Unterstützung erstellen möchten, können Sie babel-jest verwenden, um einen zu komponieren und Ihre benutzerdefinierten Konfigurationsoptionen zu übergeben:

const babelJest = require('babel-jest');

module.exports = babelJest.createTransformer({
presets: ['my-custom-preset'],
});

Weitere Details finden Sie in der dedizierten Dokumentation.