Unit-тестирование компонентов

Для unit-тестирования компонентов Ant Design в JavaScript чаще всего используется комбинация Jest и React Testing Library. Jest обеспечивает быстрый и изолированный запуск тестов, а React Testing Library позволяет работать с компонентами так, как это делает пользователь, ориентируясь на их рендер и события.

Установка необходимых пакетов:

npm install --save-dev jest @testing-library/react @testing-library/jest-dom

Также рекомендуется подключить babel-jest, если используется Babel для трансформации JSX.

npm install --save-dev babel-jest @babel/preset-env @babel/preset-react

Настройка jest.config.js:

module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'],
  transform: {
    '^.+\\.(js|jsx)$': 'babel-jest',
  },
};

Тестирование кнопок и интерактивных компонентов

Компоненты Ant Design, такие как Button, поддерживают различные типы и состояния (type, loading, disabled). Проверка их поведения заключается в рендере компонента и симуляции действий пользователя.

Пример теста кнопки:

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

test('Button вызывает onClick', () => {
  const handleClick = jest.fn();
  render(<Button onCl ick={handleClick}>Нажми меня</Button>);

  const button = screen.getByText('Нажми меня');
  fireEvent.click(button);

  expect(handleClick).toHaveBeenCalledTimes(1);
});

Ключевой момент: использовать screen.getByText или screen.getByRole для поиска элементов, вместо обращения напрямую к DOM.


Тестирование форм

Формы Ant Design (Form, Input, Select, Checkbox) требуют особого подхода из-за внутреннего состояния и валидации. React Testing Library позволяет эмулировать ввод данных и проверять ошибки валидации.

Пример проверки формы с полем Input:

import { render, screen, fireEvent } from '@testing-library/react';
import { Form, Input, Button } from 'antd';

const MyForm = ({ onSubmit }) => (
  <Form onFin ish={onSubmit}>
    <Form.Item
      name="username"
      rules={[{ required: true, message: 'Введите имя пользователя' }]}
    >
      <Input placeholder="Имя пользователя" />
    </Form.Item>
    <Button htmlType="submit">Отправить</Button>
  </Form>
);

test('Form показывает ошибку при пустом поле', async () => {
  const handleSubmit = jest.fn();
  render(<MyForm onSub mit={handleSubmit} />);

  fireEvent.click(screen.getByText('Отправить'));

  expect(await screen.findByText('Введите имя пользователя')).toBeInTheDocument();
  expect(handleSubmit).not.toHaveBeenCalled();
});

Особенность Ant Design: ошибки валидации рендерятся асинхронно, поэтому для их проверки используется findByText, чтобы дождаться появления сообщения.


Тестирование модальных окон (Modal)

Компоненты типа Modal требуют проверки открывания и закрывания, а также корректного вызова коллбеков (onOk, onCancel).

Пример:

import { render, screen, fireEvent } from '@testing-library/react';
import { Modal, Button } from 'antd';
import { useState } from 'react';

const MyModal = ({ onOk }) => {
  const [visible, setVisible] = useState(false);

  return (
    <>
      <Button onCl ick={() => setVisible(true)}>Открыть модальное окно</Button>
      <Modal
        open={visible}
        onOk={() => {
          onOk();
          setVisible(false);
        }}
        onCan cel={() => setVisible(false)}
      >
        Содержимое модального окна
      </Modal>
    </>
  );
};

test('Modal вызывает onOk и закрывается', () => {
  const handleOk = jest.fn();
  render(<MyModal onOk={handleOk} />);

  fireEvent.click(screen.getByText('Открыть модальное окно'));
  fireEvent.click(screen.getByText('OK'));

  expect(handleOk).toHaveBeenCalledTimes(1);
  expect(screen.queryByText('Содержимое модального окна')).not.toBeInTheDocument();
});

Здесь важно использовать queryByText для проверки отсутствия элемента после закрытия модального окна.


Snapshot-тестирование

Для компонентов с нестандартной версткой или сложными стилями полезно snapshot-тестирование, чтобы отлавливать нежелательные визуальные изменения.

import { render } from '@testing-library/react';
import { Button } from 'antd';

test('Button рендерится корректно', () => {
  const { asFragment } = render(<Button type="primary">Кнопка</Button>);
  expect(asFragment()).toMatchSnapshot();
});

Преимущество: автоматическая фиксация структуры DOM. Важно: использовать для проверки структуры, а не функциональности.


Тестирование таблиц (Table)

Компонент Table часто содержит динамические данные, сортировку и пагинацию. Основные тесты включают проверку рендера данных и вызов обработчиков событий.

Пример теста сортировки:

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

const columns = [
  { title: 'Имя', dataIndex: 'name', key: 'name', sorter: (a, b) => a.name.localeCompare(b.name) },
];
const data = [
  { key: '1', name: 'Анна' },
  { key: '2', name: 'Борис' },
];

test('Table сортирует данные', () => {
  render(<Table columns={columns} dataSource={data} />);
  
  const header = screen.getByText('Имя');
  fireEvent.click(header); // триггер сортировки
  
  const rows = screen.getAllByRole('row');
  expect(rows[1]).toHaveTextContent('Анна');
  expect(rows[2]).toHaveTextContent('Борис');
});

Для таблиц рекомендуется тестировать функциональность, а не визуальное представление, так как Ant Design генерирует сложный DOM.


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

Компоненты Ant Design часто используются вместе с внешними библиотеками, например moment для DatePicker или axios для загрузки данных. Unit-тесты должны изолировать компонент, поэтому внешние зависимости мокаются.

Пример мока axios:

import axios from 'axios';
jest.mock('axios');

axios.get.mockResolvedValue({ data: [{ id: 1, name: 'Тест' }] });

Рекомендации по написанию unit-тестов для Ant Design

  1. Изолировать компоненты: тесты должны проверять только конкретный компонент, а не интеграцию с другими модулями.
  2. Использовать screen для поиска элементов: это делает тесты более читаемыми и похожими на пользовательские сценарии.
  3. Эмулировать события: fireEvent или userEvent для симуляции кликов, ввода и других действий.
  4. Асинхронные действия: использовать findBy и waitFor для проверки появления элементов, зависящих от состояния или валидации.
  5. Минимизировать snapshot-тесты: применять их только для сложной разметки, не для проверки функциональности.

Unit-тестирование компонентов Ant Design требует внимания к внутреннему состоянию и событиям, но при правильной настройке Jest и React Testing Library тесты становятся стабильными, читаемыми и поддерживаемыми.