Автоматические тесты важны для большинства приложений.
В этой статье мы рассмотрим, как писать тесты для компонентов React.
Модули Mocking
Мы можем имитировать модули, которые не работают в тестовой среде.
Например, если у нас есть следующие компоненты:
Map.js
import React from "react"; import { LoadScript, GoogleMap } from "react-google-maps"; export default function Map(props) { return ( <LoadScript id="script-loader" googleMapsApiKey="YOUR_API_KEY"> <GoogleMap id="example-map" center={props.center} /> </LoadScript> ); }
Contact.js
import Map from "./map"; export default function Contact({ name, email }) { return ( <div> <address> {name} {email} </address> <Map center={props.center} /> </div> ); }
Затем мы можем протестировать Contact
компонент с имитацией Map
компонента, написав:
Contact.test.js
import React from "react"; import { render, unmountComponentAtNode } from "react-dom"; import { act } from "react-dom/test-utils"; import Contact from "./contact"; jest.mock("./map", () => { return function DummyMap(props) { return ( <div data-testid="map"> {props.center.lat}:{props.center.long} </div> ); }; }); let container = null; beforeEach(() => { container = document.createElement("div"); document.body.appendChild(container); }); afterEach(() => { unmountComponentAtNode(container); container.remove(); container = null; }); it("should render contact information", () => { const center = { lat: 0, long: 0 }; act(() => { render( <Contact name="james" email="[email protected]" center={center} />, container ); }); expect( container.querySelector("address").textContent ) .toContain("james [email protected]"); expect(container.querySelector('[data-testid="map"]').textContent).toEqual( "0:0" ); });
У нас есть:
jest.mock("./map", () => { return function DummyMap(props) { return ( <div data-testid="map"> {props.center.lat}:{props.center.long} </div> ); }; });
издеваться над компонентом Map
.
Затем, когда мы вызываем render
, мы выполняем рендеринг с DummyMap
вместо фактического Map
компонента.
События
Чтобы проверить события, мы можем отправлять реальные события DOM на элементы DOM.
Например, если мы хотим протестировать компонент Toggle
:
import React, { useState } from "react"; export default function Toggle(props) { const [state, setState] = useState(false); return ( <button onClick={() => { setState(previousState => !previousState); props.onChange(!state); }} data-testid="toggle" > {state ? "off" : "on"} </button> ); }
Затем мы можем добавить для него тестовый файл, написав:
Toggle.test.js
import React from "react"; import { render, unmountComponentAtNode } from "react-dom"; import { act } from "react-dom/test-utils"; import Toggle from "./toggle"; let container = null; beforeEach(() => { container = document.createElement("div"); document.body.appendChild(container); }); afterEach(() => { unmountComponentAtNode(container); container.remove(); container = null; }); it("changes value when clicked", () => { const onChange = jest.fn(); act(() => { render(<Toggle onChange={onChange} />, container); }); const button = document.querySelector("[data-testid=toggle]"); expect(button.innerHTML).toBe("on"); act(() => { button.dispatchEvent(new MouseEvent("click", { bubbles: true })); }); expect(onChange).toHaveBeenCalledTimes(1); expect(button.innerHTML).toBe("off"); act(() => { button.dispatchEvent(new MouseEvent("click", { bubbles: true })); }); expect(onChange).toHaveBeenCalledTimes(2); expect(button.innerHTML).toBe("on"); });
Мы имитируем метод onChange
, который мы передаем как значение свойства onChange
.
Затем получаем кнопку с селектором[data-testid=toggle]
из компонента Toggle
.
Затем мы можем получить содержимое кнопки и сколько раз onChange
было вызвано после того, как мы вызывали dispatchEvent
для отправки щелчка MouseEvent
.
Нам нужно передать { bubbles: true }
, чтобы React делегировал событие документу.
Заключение
Мы можем имитировать модули, которые не можем удобно использовать в наших тестах.
Также мы можем запускать события для элементов и после этого проверять результат.