Test Utilities

Importazione

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

Panoramica

ReactTestUtils rende semplice testare i componenti React all’interno del framework di test che preferisci. In Facebook usiamo Jest per scrivere test in JavaScript. Impara come utilizzare Jest tramite il sito ufficiale React Tutorial.

Nota:

Suggeriamo l’utilizzo di React Testing Library, che è una libreria concepita per abilitare e favorire la scrittura di test che simulano il reale utilizzo dei componenti.

In alternativa, Airbnb ha rilasciato una libreria per i test chiamata Enzyme, che semplifica le operazioni di verifica, manipolazione ed analisi dell’output dei tuoi componenti.

Riferimento

act()

Per preparare un componente per le verifiche, racchiudi il codice che lo renderizza e lo aggiorna all’interno di una chiamata act(). Questo permette di simulare un comportamento che si avvicina a quello reale di React.

Nota

Se utilizzi react-test-renderer, hai a disposizione un modulo act che funziona allo stesso modo.

Ad esempio, prendiamo in considerazione il seguente componente Counter:

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

Possiamo testarlo in questo modo:

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('can render and update a counter', () => {
  // Testa il primo render e componentDidMount
  act(() => {
    ReactDOM.render(<Counter />, container);
  });
  const button = container.querySelector('button');
  const label = container.querySelector('p');
  expect(label.textContent).toBe('Hai cliccato 0 volte');
  expect(document.title).toBe('Hai cliccato 0 volte');

  // Testa il secondo render e componentDidUpdate
  act(() => {
    button.dispatchEvent(new MouseEvent('click', {bubbles: true}));
  });
  expect(label.textContent).toBe('Hai cliccato 1 volte');
  expect(document.title).toBe('Hai cliccato 1 volte');
});

Non dimenticare che generare degli eventi DOM ha effetto solamente quando il contenitore dello stesso è aggiunto al document. Puoi usare una libreria come react-testing-library per aumentare la pulizia del codice.


mockComponent()

mockComponent(
  componentClass,
  [mockTagName]
)

Passare il mock di un componente a questo metodo consente di migliorarlo, mettendo a disposizione delle funzionalità che permettono di utilizzare quest’ultimo come un componente React base. Il componente diventerà quindi un semplice <div> (o un altro tag se è presente mockTagNme), che conterrà degli eventuali componenti figli.

Nota:

mockComponent() è un’API legacy. Raccomandiamo l’utilizzo di shallow rendering oppure jest.mock().


isElement()

isElement(element)

Ritorna true se element è un qualsiasi componente React.


isElementOfType()

isElementOfType(
  element,
  componentClass
)

Ritorna true se element è un componente React di tipo componentClass.


isDOMComponent()

isDOMComponent(instance)

Ritorna true se instance è un componente DOM (come un <div> o uno <span>).


isCompositeComponent()

isCompositeComponent(instance)

Ritorna true se instance è un componente definito dall’utente, come una classe o una funzione.


isCompositeComponentWithType()

isCompositeComponentWithType(
  instance,
  componentClass
)

Ritorna true se instance è un componente di tipo componentClass.


findAllInRenderedTree()

findAllInRenderedTree(
  tree,
  test
)

Scorre tutti i componenti nel tree e li accumula dove test(component) è true. Questo di per sè non è molto utile, ma è utilizzato come base in altre librerie di test.


scryRenderedDOMComponentsWithClass()

scryRenderedDOMComponentsWithClass(
  tree,
  className
)

Trova tutti gli elementi DOM dei componenti renderizzati, il cui nome della classe corrisponde a className.


findRenderedDOMComponentWithClass()

findRenderedDOMComponentWithClass(
  tree,
  className
)

Come scryRenderedDOMComponentsWithClass() ma si aspetta un solo risultato, ritornandolo oppure generando un’eccezione in caso di più risultati.


scryRenderedDOMComponentsWithTag()

scryRenderedDOMComponentsWithTag(
  tree,
  tagName
)

Trova tutti gli elementi DOM dei componenti renderizzati che corrispondo al nome specifico del tag tagName.


findRenderedDOMComponentWithTag()

findRenderedDOMComponentWithTag(
  tree,
  tagName
)

Come scryRenderedDOMComponentsWithTag() ma si aspetta un solo risultato, ritornandolo oppure generando un’eccezione in caso di più risultati.


scryRenderedComponentsWithType()

scryRenderedComponentsWithType(
  tree,
  componentClass
)

Trova tutte le istanze dei componenti il cui tipo è componentClass.


findRenderedComponentWithType()

findRenderedComponentWithType(
  tree,
  componentClass
)

Come scryRenderedComponentsWithType() ma si aspetta un solo risultato, ritornandolo oppure generando un’eccezione in caso di più risultati.


renderIntoDocument()

renderIntoDocument(element)

Renderizza un elemento React in un nodo DOM separato, all’interno del documento. Questa funzione richiede un DOM. Equivale a:

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

Nota:

Dovrai avere window, window.document e window.document.createElement disponibili globalmente prima di importare React. Altrimenti React penserà di non poter accedere al DOM, e metodi come setState non funzioneranno.


Altre Utilities

Simulate

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

Simula la generazione di un evento su un nodo DOM, con un eventData opzionale.

Simulate ha un metodo per ogni evento che React supporta.

Cliccare un elemento

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

Cambiare il valore di un campo input e quindi premere ENTER

// <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});

Nota

Dovrai fornire qualsiasi proprietà agli eventi che usi nel tuo componente (ad esempio, keyCode, which, etc…), visto che React non ne definisce automaticamente nessuna.