Unit тестирование с Jest

Unit-тестирование представляет собой проверку отдельных компонентов или функций приложения на корректность работы. В контексте Preact это особенно важно, поскольку компонентная архитектура требует уверенности в правильной работе каждого элемента интерфейса. Jest — мощный фреймворк для тестирования JavaScript-приложений, полностью совместимый с Preact, обеспечивающий удобное написание и выполнение тестов.


Настройка окружения

Для работы с Jest в Preact требуется установить следующие пакеты:

npm install --save-dev jest @testing-library/preact @testing-library/jest-dom babel-jest
  • jest — основной фреймворк тестирования.
  • @testing-library/preact — утилиты для рендеринга Preact-компонентов и взаимодействия с ними.
  • @testing-library/jest-dom — расширения для удобных матчеров, таких как toBeInTheDocument.
  • babel-jest — трансформация современного JavaScript и JSX в код, понятный Jest.

Конфигурация Jest обычно задаётся в файле package.json или в отдельном jest.config.js. В Preact рекомендуется включать поддержку JSX через Babel:

module.exports = {
  testEnvironment: 'jsdom',
  transform: {
    '^.+\\.jsx?$': 'babel-jest'
  },
  moduleFileExtensions: ['js', 'jsx'],
};

Основные концепции тестирования компонентов

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

Для проверки отображения компонента используется функция render из @testing-library/preact:

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

test('рендерит кнопку с текстом', () => {
  const { getByText } = render(<MyButton label="Нажми меня" />);
  expect(getByText('Нажми меня')).toBeInTheDocument();
});

Ключевые моменты:

  • render создаёт виртуальное DOM-дерево компонента.
  • getByText и другие селекторы позволяют получать элементы для проверки.
  • toBeInTheDocument проверяет присутствие элемента в DOM.

Проверка событий

Unit-тестирование часто включает симуляцию событий, например, кликов:

import { fireEvent, render } from '@testing-library/preact';
import MyButton from './MyButton';

test('вызывает обработчик при клике', () => {
  const handleClick = jest.fn();
  const { getByText } = render(<MyButton label="Нажми" onCl ick={handleClick} />);
  
  fireEvent.click(getByText('Нажми'));
  expect(handleClick).toHaveBeenCalledTimes(1);
});

Особенности:

  • fireEvent имитирует пользовательские действия: клик, ввод текста, фокус и т.д.
  • jest.fn() создаёт мок-функцию для проверки вызовов.
  • toHaveBeenCalledTimes позволяет точно контролировать количество вызовов.

Тестирование состояния и пропсов

Preact-компоненты могут иметь внутреннее состояние с хуком useState и принимать пропсы. Тестирование состояния важно для проверки логики компонента:

import { render, fireEvent } from '@testing-library/preact';
import { useState } from 'preact/hooks';
import Counter from './Counter';

test('увеличивает счётчик при клике', () => {
  const { getByText } = render(<Counter initial={0} />);
  
  const button = getByText('Увеличить');
  fireEvent.click(button);
  
  expect(getByText('Счёт: 1')).toBeInTheDocument();
});

Примечания:

  • initial — проп, задающий начальное состояние.
  • После fireEvent.click состояние компонента обновляется, а DOM отражает новое значение.

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

Компоненты часто используют сторонние модули или API. Jest позволяет заменять их моками:

import { fetchData } from './api';
import DataComponent from './DataComponent';
import { render, waitFor } from '@testing-library/preact';

jest.mock('./api');

test('рендерит данные после запроса', async () => {
  fetchData.mockResolvedValue({ text: 'Привет' });
  
  const { getByText } = render(<DataComponent />);
  
  await waitFor(() => expect(getByText('Привет')).toBeInTheDocument());
});

Ключевые моменты:

  • jest.mock подменяет модуль на мок.
  • mockResolvedValue позволяет имитировать успешный результат промиса.
  • waitFor ждёт обновления DOM после асинхронного действия.

Организация тестов

  • Каждый компонент располагается рядом с тестами: Component.jsx и Component.test.jsx.
  • Тесты должны проверять конкретное поведение, а не внутреннюю реализацию.
  • Разделение на юнит-тесты и интеграционные тесты помогает поддерживать чистоту кода.

Полезные рекомендации

  • Использовать селекторы, максимально приближённые к пользовательскому поведению (getByText, getByRole).
  • Проверять состояния и побочные эффекты компонента после действий.
  • Мокировать внешние API и зависимости, чтобы тесты оставались быстрыми и детерминированными.
  • Автоматизировать запуск тестов через скрипт npm test и интегрировать с CI/CD.

Unit-тестирование с Jest в Preact обеспечивает надёжную проверку компонентов, позволяет выявлять ошибки на ранних этапах и поддерживать высокое качество фронтенд-кода. Правильная организация тестов и использование современных инструментов делают процесс тестирования удобным и масштабируемым.