Testing Library для Preact

Testing Library — это инструмент для тестирования компонентов, ориентированный на работу с интерфейсом, а не на внутренние детали реализации. В контексте Preact он обеспечивает удобный способ проверки того, как компоненты рендерятся, взаимодействуют с пользователем и реагируют на изменения состояния.

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

Установка и настройка

Для работы с Testing Library в Preact требуется несколько пакетов:

npm install @testing-library/preact @testing-library/jest-dom --save-dev
  • @testing-library/preact — обеспечивает рендеринг Preact-компонентов для тестирования.
  • @testing-library/jest-dom — добавляет удобные матчеры для Jest, позволяя писать более читаемые утверждения, например toBeVisible() или toHaveTextContent().

Настройка может включать интеграцию с Jest. В файле setupTests.js подключается jest-dom:

import '@testing-library/jest-dom';

Рендеринг компонентов

Основная функция для тестирования компонентов — render. Она позволяет отрендерить компонент и получить удобные методы для поиска элементов в DOM:

import { render } from '@testing-library/preact';
import MyComponent from './MyComponent';

test('рендерит текст', () => {
  const { getByText } = render(<MyComponent />);
  expect(getByText('Привет, Preact!')).toBeInTheDocument();
});

Методы поиска элементов:

  • getByText — ищет элемент по текстовому содержимому, выбрасывает ошибку, если элемент не найден.
  • queryByText — возвращает null, если элемент отсутствует, удобен для проверки отрицательных сценариев.
  • findByText — асинхронная версия, возвращает промис, ожидающий появления элемента.

Симуляция взаимодействий

Testing Library позволяет имитировать действия пользователя через пакет user-event:

npm install @testing-library/user-event --save-dev

Пример клика по кнопке и проверки эффекта:

import { render, screen } from '@testing-library/preact';
import userEvent from '@testing-library/user-event';
import Counter from './Counter';

test('увеличивает счетчик при клике', async () => {
  render(<Counter />);
  const button = screen.getByRole('button', { name: /увеличить/i });
  await userEvent.click(button);
  expect(screen.getByText('Счет: 1')).toBeInTheDocument();
});

Методы взаимодействия:

  • userEvent.click(element) — симуляция клика.
  • userEvent.type(element, text) — ввод текста в поле.
  • userEvent.selectOptions(select, option) — выбор значения в <select>.

Асинхронное тестирование

Компоненты Preact часто используют асинхронные операции, например загрузку данных. Testing Library предоставляет удобные утилиты для ожидания изменений DOM:

  • waitFor — ожидает выполнения условия:
import { render, screen, waitFor } from '@testing-library/preact';
import AsyncComponent from './AsyncComponent';

test('отображает данные после загрузки', async () => {
  render(<AsyncComponent />);
  await waitFor(() => expect(screen.getByText('Данные загружены')).toBeInTheDocument());
});
  • findBy* — сокращает использование waitFor, возвращает промис, который разрешается при появлении элемента.

Контейнеры и cleanup

По умолчанию render создает контейнер для компонента и автоматически очищает его после теста. Если требуется кастомный контейнер:

import { render } from '@testing-library/preact';

const container = document.createElement('div');
document.body.appendChild(container);

render(<MyComponent />, { container });

В большинстве случаев ручной cleanup не требуется, но его можно вызвать через:

import { cleanup } from '@testing-library/preact';
afterEach(cleanup);

Работа с состоянием и пропсами

Testing Library проверяет компонент «как есть», но можно легко обновлять пропсы и проверять реакцию:

import { render, screen } from '@testing-library/preact';
import { h } from 'preact';
import Greeting from './Greeting';

test('изменяет приветствие при изменении пропсов', () => {
  const { rerender } = render(<Greeting name="Алексей" />);
  expect(screen.getByText('Привет, Алексей')).toBeInTheDocument();

  rerender(<Greeting name="Мария" />);
  expect(screen.getByText('Привет, Мария')).toBeInTheDocument();
});

rerender полезен для проверки динамических обновлений без полного повторного рендера.

Доступность и роли

Testing Library стимулирует использование доступности:

  • getByRole — ищет элементы по их семантической роли (button, textbox, heading).
  • getByLabelText — ищет элементы формы по связанной метке <label>.
  • getByPlaceholderText — ищет элементы формы по placeholder.

Применение этих методов делает тесты более стабильными и ближе к поведению пользователя.

Совместимость с Preact Hooks

Hooks Preact (useState, useEffect, useRef) полностью поддерживаются Testing Library. Асинхронные эффекты и обновления состояния корректно обрабатываются при использовании waitFor или findBy*.

import { render, screen, waitFor } from '@testing-library/preact';
import Timer from './Timer';

test('отображает увеличивающееся время', async () => {
  render(<Timer />);
  await waitFor(() => expect(screen.getByText(/Время: \d+/)).toBeInTheDocument());
});

Мокирование внешних зависимостей

Для тестов компонентов с API-запросами используется мокирование через Jest:

jest.mock('../api', () => ({
  fetchData: jest.fn(() => Promise.resolve('Данные загружены'))
}));

Это позволяет полностью контролировать данные и предсказуемо тестировать поведение компонентов.


Testing Library для Preact обеспечивает подход к тестированию, сосредоточенный на поведении пользователя, совместим с современными инструментами Preact, включая хуки и асинхронные эффекты, и предлагает удобные утилиты для рендера, взаимодействия и ожидания изменений в DOM.