Введение в Test-Driven Development на React для чайников
- воскресенье, 17 апреля 2022 г. в 00:35:47
Первое правило Test-Driven Development (TDD) – это написание тестов перед написанием кода. Это звучит более интуитивно, когда мы говорим о разработке для бэкенда, если честно, но работает ли данная схема для фронтенда, в частности для React, что же, посмотрим.
В данном посте мы узнаем о TDD на React с простым примером.
Для демонстрации мы будем разрабатывать очень простой и очень ужасный счетчик.
Он поможет нам разобраться, как работает то, что мы хотим понять, в конечно счете мы фокусируемся больше на функциональности, нежели на эстетике.
В первую очередь, создадим простой React проект.
yarn create react-app react-test-driven-development
Когда проект создан, проверьте, все ли работает, просто запустив проект.
cd react-test-driven-development
yarn start
Вы должно получить что-то похожее по адресу http://localhost:3000.
Создайте новую папку components внутри папки src. Данная папка будет содержать компоненты, которые мы напишем. И внутри этой папки создайте файл с названием Counter.test.js. Как было сказано ранее, когда мы работаем с TDD мы пишем сначала тесты, а затем уже код приложения.
Это помогает заложить основы лучшей архитектуры вашего приложения, так как мы сначала думаем о том, как и что будет работать, и что нам нужно писать.
Наш идеальный компонент принимает в себя проп value, который в дальнейшем будет отображаться на экране в определенном тэге.
Прекрасно! Давайте напишем вначале тест.
Напишите данный код внутри Counter.test.js.
import { render, screen } from '@testing-library/react';
import Counter from "Counter";
Мы начинаем с того, что импортируем необходимые инструменты для написания тестов. Не беспокойтесь о 2 строчке, мы пока что ещё не создали компонент счетчика. Задача TDD это убедиться, что первый тест провалится, перед тем как написать работающий код.
С этим всем, мы теперь можем написать наш первый тест.
test('renders counter component', () => {
render(<Counter value={2} />);
const counterElement = screen.getByTestId("counter-test");
});
Здесь мы рендерим компонент счетчика в DOM и затем получаем его как элемент. Нам нужно будет протестировать две вещи:
Компонент отрисовался?
Компонент отображает именно значение "2"?
test('renders counter component', () => {
render(<Counter value={2} />);
const counterElement = screen.getByTestId("counter-test");
// Тест, отрисовался ли элемент счетчика
expect(counterElement).toBeInTheDocument();
// Тест, верно ли, что значение счетчика равно 2
expect(counterElement).toHaveTextContent("2");
});
Прекрасно! Теперь в командной строке запустите данную команду, чтобы проверить тесты.
yarn test
Команда, естественно, завершится ошибкой.
Прекрасно! Теперь мы можем написать наш компонент.
Внутри папки компонента создайте новый файл Counter.jsx. И поместите данный код внутри его.
import React from "react";
// Это компонент, который мы тестируем
function Counter({value}) {
return (
<p data-testid="counter-test">
{value}
</p>
);
}
export default Counter;
Теперь снова запустить команду для проверки тестов, всё должно быть зеленым.
Мы сделали отличную работу. Следующим шагом будет добавления нашего компонента в App.js и добавление кнопки для изменения состояния. И мы также будем следовать TDD для этого.
Примечание: вы можете увидеть данную ошибку в терминале после запуска тестов.
Warning: ReactDOM.render is no longer supported in React 18...
Вы можете найти решение данной проблемы на StackOverflow.
Дальнейшая задача, это добавление кнопки, которая будет изменять значение нашего счетчика в Counter.jsx. И мы это сделаем внутри App.js, так что напишем тесты для этого. Создайте файл App.test.js.
Для создания всего функционала нам нужно:
По нажатию на кнопку увеличивать значение счетчика на 1
Довольно легко, не так ли? Давайте писать тест.
Библотека testing-library даёт нам инструменты, которые позволяют нам обрабатывать срабатывание действия кнопки. Что очень хорошо!
Начнем с импорта нужных инструментов. Так как мы хотим, чтобы по действию события нажатия на экран (нажатие на кнопку) увеличивалось значение счетчика, то тесты у нас будут асинхронными.
import { render, screen } from '@testing-library/react';
import App from './App';
import userEvent from "@testing-library/user-event";
UserEvent эмулирует действия пользователя, такие как нажатие мышки, ввод текста, и многое другое. А вот и код теста.
import { render, screen } from '@testing-library/react';
import App from './App';
import userEvent from "@testing-library/user-event";
describe('Render the counter with Button', () => {
render(<App />);
it("render counter", async () => {
const appElement = screen.getByTestId('app-test');
expect(appElement).toBeInTheDocument();
// Тест, имеет ли счетчик верное стандартное значение
const counterElement = screen.getByTestId('counter-test');
expect(counterElement).toHaveTextContent('0');
// Получение элемента кнопки
const buttonElement = screen.getByTestId('button-counter-test');
expect(buttonElement).toBeInTheDocument();
// Срабатывание действия нажатия кнопки
await userEvent.click(buttonElement);
// Тест, изменилось ли значение счетчика на новое, и верно ли оно
expect(counterElement).toHaveTextContent('1');
})
});
Прекрасно, тесты происходят с ошибкой, как нам и нужно. Давайте теперь напишем функционал в компоненте.
Внутрь файла App.js добавьте данный код.
import React, { useState } from "react";
import Counter from "./components/Counter";
function App() {
const [count, setCount] = useState(0);
return (
<div data-testid="app-test">
<Counter value={count} />
<button data-testid="button-counter-test" onClick={() => setCount(count + 1)}>Increase</button>
</div>
);
}
export default App;
Мы используем хук useState для отслеживания и изменения состояния приложения.
После добавления кода запустите тесты снова. Все должно быть зеленым.
И принимайте мои поздравления 🥳! Мы написали наше первое, небольшое, страшненькое, но рабочее приложение на React используя TDD .