Test-Utilities

Import

import ReactTestUtils from 'react-dom/test-utils'; // ES6
var ReactTestUtils = require('react-dom/test-utils'); // ES5 mit npm

Übersicht

ReactTestUtils bieten eine einfache Möglichkeit, React-Komponenten in einem Test-Framework deiner Wahl zu testen. Bei Facebook benutzen wir Jest für schmerzfreie Javascript-Tests. Du kannst das React-Tutorial auf Jest’s Webseite besuchen, um Jest zu lernen.

Hinweis:

Wir empfehlen die Verwendung der React Testing Library, die konzipiert wurde, um das Schreiben von Tests zu ermöglichen, in denen Komponenten auf die gleiche Weise verwendet werden wie von Endnutzern.

Alternativ dazu gibt es von Airbnb eine Test-Utility namens Enzyme, mit der auf einfache Weise die Ausgabe von React-Komponenten zugesichert (asserted), manipuliert und durchlaufen werden kann.

Referenz

act()

Um eine Komponente für Assertionen vorzubereiten, setze den Code, der sie rendert und aktualisiert, in einen act()-Aufruf. Damit läuft der Test so ähnlich ab, wie React auch im Browser funktioniert.

Hinweis

Falls du react-test-renderer verwendest, kannst du dessen act-Export verwenden, der sich gleich verhält.

Stelle dir als Beispiel vor, du hast diese Counter-Komponente:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {count: 0};
    this.handleClick = this.handleClick.bind(this);
  }
  componentDidMount() {
    document.title = `Du hast ${this.state.count} Mal geklickt`;
  }
  componentDidUpdate() {
    document.title = `Du hast ${this.state.count} Mal geklickt`;
  }
  handleClick() {
    this.setState(state => ({
      count: state.count + 1,
    }));
  }
  render() {
    return (
      <div>
        <p>Du hast {this.state.count} Mal geklickt</p>
        <button onClick={this.handleClick}>
          Klick mich
        </button>
      </div>
    );
  }
}

So können wir sie testen:

import React from 'react';
import ReactDOM from 'react-dom';
import { act } from 'react-dom/test-utils';
import Counter from './Counter';

let container;

beforeEach(() => {
  container = document.createElement('div');
  document.body.appendChild(container);
});

afterEach(() => {
  document.body.removeChild(container);
  container = null;
});

it('kann einen Counter rendern und updaten', () => {
  // Erstes Rendern und componentDidMount testen
  act(() => {
    ReactDOM.render(<Counter />, container);
  });
  const button = container.querySelector('button');
  const label = container.querySelector('p');
  expect(label.textContent).toBe('Du hast 0 Mal geklickt');
  expect(document.title).toBe('Du hast 0 Mal geklickt');

  // Zweites Rendern und componentDidUpdate testen
  act(() => {
    button.dispatchEvent(new MouseEvent('click', {bubbles: true}));
  });
  expect(label.textContent).toBe('Du hast 1 Mal geklickt');
  expect(document.title).toBe('Du hast 1 Mal geklickt');
});

Vergiss nicht, dass das Abschicken von DOM-Events nur funktioniert, wenn der DOM-Container zum document hinzugefügt wurde. Du kannst react-testing-library zur Hilfe nehmen, um Boilerplate-Code zu reduzieren.


mockComponent()

mockComponent(
  componentClass,
  [mockTagName]
)

Übergebe dieser Methode ein gemocktes Komponenten-Modul, um es mit nützlichen Methoden zu erweitern, mit denen es als Dummy-React-Komponente verwendet werden kann. Anstatt wie üblich zu rendern, wird die Komponente zu einem einfachen <div> (oder zu einem anderen Tag, falls mockTagName angegeben wurde), das die ihr übergegebenen Children-Elemente enthält.

Hinweis:

mockComponent() ist eine veraltete API. Wir empfehlen, stattdessen shallow rendering oder jest.mock() zu verwenden.


isElement()

isElement(element)

Gibt true zurück, falls element ein React-Element ist.


isElementOfType()

isElementOfType(
  element,
  componentClass
)

Gibt true zurück, falls element ein React-Element vom Typ React componentClass ist.


isDOMComponent()

isDOMComponent(instance)

Gibt true zurück, falls instance eine DOM-Komponente (z. B. ein <div> oder <span>) ist.


isCompositeComponent()

isCompositeComponent(instance)

Gibt true zurück, falls instance eine benutzerdefinierte Komponente, z. B. eine Klasse oder Funktion, ist.


isCompositeComponentWithType()

isCompositeComponentWithType(
  instance,
  componentClass
)

Gibt true zurück, falls instance eine Komponente vom Typ React componentClass ist.


findAllInRenderedTree()

findAllInRenderedTree(
  tree,
  test
)

Durchläuft alle Komponenten in tree und sammelt alle Komponenten, bei denen test(component) true ist. Das ist für sich allein genommen nicht besonders nützlich, wird aber als Primitive für andere Test-Utilities verwendet.


scryRenderedDOMComponentsWithClass()

scryRenderedDOMComponentsWithClass(
  tree,
  className
)

Findet alle DOM-Elemente von Komponenten im gerenderten Baum, bei denen der Klassennamen der Komponenten mit className übereinstimmt.


findRenderedDOMComponentWithClass()

findRenderedDOMComponentWithClass(
  tree,
  className
)

Verhält sich wie scryRenderedDOMComponentsWithClass(), erwartet aber genau ein Resultat und gibt dieses zurück. Gibt einen Fehler aus, falls es mehr oder weniger als eine Übereinstimmung gibt.


scryRenderedDOMComponentsWithTag()

scryRenderedDOMComponentsWithTag(
  tree,
  tagName
)

Findet alle DOM-Elemente von Komponenten im gerenderten Baum, bei denen der Tagname der Komponenten mit tagName übereinstimmt.


findRenderedDOMComponentWithTag()

findRenderedDOMComponentWithTag(
  tree,
  tagName
)

Verhält sich wie scryRenderedDOMComponentsWithTag(), erwartet aber genau ein Resultat und gibt dieses zurück. Gibt einen Fehler aus, falls es mehr oder weniger als eine Übereinstimmung gibt.


scryRenderedComponentsWithType()

scryRenderedComponentsWithType(
  tree,
  componentClass
)

Findet alle Instanzen von Komponenten, deren Typ mit componentClass übereinstimmt.


findRenderedComponentWithType()

findRenderedComponentWithType(
  tree,
  componentClass
)

Verhält sich wie scryRenderedComponentsWithType(), erwartet aber genau ein Resultat und gibt dieses zurück. Gibt einen Fehler aus, falls es mehr oder weniger als eine Übereinstimmung gibt.


renderIntoDocument()

renderIntoDocument(element)

Rendert ein React-Element in einen separaten DOM-Knoten im Dokument. Diese Funktion benötigt ein DOM. Effektiv ist sie äquivalent zu:

const domContainer = document.createElement('div');
ReactDOM.render(element, domContainer);

Hinweis:

window, window.document und window.document.createElement müssen global verfügbar sein, bevor du React importierst. Ansonsten denkt React, dass es nicht auf das DOM zugreifen kann, und Methoden wie setState werden nicht funktionieren.


Andere Utilities

Simulate

Simulate.{eventName}(
  element,
  [eventData]
)

Simuliere das Abschicken eines Events auf einen DOM-Knoten mit optionalen eventData-Eventdaten.

Simulate hat eine Methode für jedes Event, das React versteht.

Ein Element anklicken

// <button ref={(node) => this.button = node}>...</button>
const node = this.button;
ReactTestUtils.Simulate.click(node);

Den Wert eines Input-Feldes verändern und dann ENTER drücken

// <input ref={(node) => this.textInput = node} />
const node = this.textInput;
node.value = 'Giraffe';
ReactTestUtils.Simulate.change(node);
ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});

Hinweis

Du musst jede Event-Eigenschaft angeben, die du in deiner Komponente verwendest (z. B. keyCode, which, etc.), da React keine davon für dich erstellt.