Первое правило 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 .

Комментарии (3)


  1. v1000
    16.04.2022 19:53
    +2

    Когда прочитал название в первый раз, подумал, что речь идет о электрических чайниках.


  1. nomn
    16.04.2022 22:02
    +2

    Не знаю чего я ожидал от статьи с таким заголовком, но получилось что-то вроде

    TDD в %React% (замените на что угодно или вовсе уберите)
    1. Напишите тест
    2. Напишите компонет
    3. Вы прекрасны


  1. uyrij
    19.04.2022 11:16

    Покажите, кто любит рисовать кнопку через TDD ? Такое желание противоестественно. Мне вот странно, почему мало примеров (на Хабре вообще не видел) про TDD , когда тесты создаются для решения задачки, вот уж где без тестов не обойтись! Действительно, одно дело ловить ошибки в онлайн, и другое с готовыми тестами решить задачку в локальном редакторе. Кстати, одного testing-library мало. Потому что тестов бывает больше одного и тогда нужен jest.