Читаемость первый приоритет

Читаемость кода является важнейшим аспектом при разработке тестов. Это особенно актуально в контексте React, где интерфейсы пользователей могут быть сложными и многоуровневыми. React Testing Library (RTL) предоставляет набор инструментов, направленных на создание тестов, которые не только проверяют функциональность, но и легко читаются и поддерживаются. В этой главе будет рассмотрено, как писать тесты с фокусом на читаемость и поддерживаемость.

Принципы React Testing Library

React Testing Library ставит акцент на тестирование того, как компоненты работают в контексте пользователя, а не на их внутреннем состоянии или реализации. Основная цель RTL — тестировать поведение компонентов, ориентируясь на то, как пользователь взаимодействует с приложением, а не как устроена его внутренняя структура.

Одним из ключевых аспектов является минимизация зависимостей от реализации компонента. Вместо того чтобы тестировать внутренние состояния, такие как props или state, RTL помогает тестировать взаимодействие с компонентом через интерфейс — например, клики, ввод текста или изменение состояния.

Использование семантических элементов и доступности

Читаемость тестов начинается с доступности. Важно помнить, что компоненты должны быть доступными для всех пользователей, включая тех, кто использует технологии ассистирования. В React Testing Library для выборки элементов лучше использовать семантические и доступные атрибуты, такие как aria-label, role, и текстовые содержимое. Это повышает как доступность приложения, так и читаемость тестов.

Например:

<button aria-label="Добавить в корзину">Добавить</button>

Этот элемент можно выбрать в тестах с помощью getByLabelText, что делает тест более читаемым и понятным:

const button = screen.getByLabelText(/добавить в корзину/i);

Применение таких подходов помогает избежать зависимостей от структуры DOM и упрощает поддержку тестов при изменении реализации компонентов.

Селекторы в тестах

React Testing Library предоставляет несколько методов для выбора элементов на странице. Важно выбирать их в соответствии с тем, как пользователи взаимодействуют с интерфейсом. Это повышает читаемость тестов, так как каждый селектор отражает конкретное намерение пользователя.

getByText

Метод getByText используется для поиска элемента по его текстовому содержимому. Это наиболее естественный способ выбора элементов, так как текст — это то, с чем пользователи взаимодействуют напрямую.

Пример:

const button = screen.getByText(/отправить/i);
expect(button).toBeInTheDocument();

getByRole

Метод getByRole позволяет выбирать элементы по их роли. Это особенно полезно, когда элемент выполняет конкретную функцию, например, кнопка или форма. Это улучшает читаемость тестов, поскольку название роли явно указывает на функциональность компонента.

Пример:

const button = screen.getByRole('button', { name: /отправить/i });
expect(button).toBeInTheDocument();

getByLabelText

Метод getByLabelText используется для выборки элементов формы, таких как input или textarea, которые имеют связанные с ними метки (label). Это особенно важно для доступности и понятности тестов, так как показывает, что элемент предназначен для взаимодействия с пользователем.

Пример:

const input = screen.getByLabelText(/имя/i);
expect(input).toBeInTheDocument();

Рекомендации по улучшению читаемости тестов

  1. Использование описательных имен тестов Каждый тест должен иметь понятное и описательное название. Это помогает сразу понять, что тест проверяет, и улучшает читаемость тестов.

    Пример:

    test('пользователь может добавить товар в корзину', () => {
      // тестирование
    });
  2. Минимизация логики внутри тестов Логика, необходимая для выполнения теста, должна быть максимально простой. Если необходимо подготовить данные, создавайте вспомогательные функции. Не добавляйте лишнюю логику, которая может отвлечь внимание от основной цели теста.

  3. Использование beforeEach и afterEach Для подготовки общего состояния и очистки после тестов используйте хуки beforeEach и afterEach. Это позволяет избежать дублирования кода и улучшает читаемость тестов.

    Пример:

    beforeEach(() => {
      render(<MyComponent />);
    });
    
    afterEach(() => {
      cleanup();
    });
  4. Избегание громоздких проверок Каждое утверждение в тесте должно быть четким и конкретным. Не пишите сложные проверки в одном тесте, делите их на несколько, если это необходимо. Тесты должны проверять один конкретный сценарий.

    Пример:

    // Плохо
    expect(screen.getByText(/ошибка/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /отправить/i })).toBeDisabled();
    
    // Хорошо
    expect(screen.getByText(/ошибка/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /отправить/i })).toBeDisabled();
  5. Использование утилитных функций для повторяющихся операций Если в тестах часто повторяются одни и те же действия (например, клики по кнопкам, ввод текста), имеет смысл выделить эти действия в утилитные функции.

    Пример:

    const clickSubmitButton = () => {
      const button = screen.getByRole('button', { name: /отправить/i });
      fireEvent.click(button);
    };

Пример читаемого теста

import { render, screen, fireEvent } from '@testing-library/react';
import MyForm from './MyForm';

test('проверка формы отправки', () => {
  render(<MyForm />);
  
  const nameInput = screen.getByLabelText(/имя/i);
  fireEvent.change(nameInput, { target: { value: 'Иван' } });
  
  const submitButton = screen.getByRole('button', { name: /отправить/i });
  fireEvent.click(submitButton);
  
  const successMessage = screen.getByText(/форма отправлена/i);
  expect(successMessage).toBeInTheDocument();
});

Этот тест проверяет форму, в которой пользователь вводит имя и отправляет его. Он использует доступные и понятные методы выбора элементов и избегает избыточной логики.

Заключение

React Testing Library помогает создавать тесты, которые легко читать и поддерживать. Основное внимание должно быть уделено тому, как пользователь взаимодействует с компонентом, а не его внутренней реализации. Использование правильных селекторов, описательных имен и минимизация логики в тестах способствует их читаемости и облегчает дальнейшую работу с кодом.