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

Ant Design предоставляет мощные инструменты для работы с формами через компонент Form. Тестирование форм включает проверку валидации, корректного отображения полей, обработки событий и отправки данных. Основная цель — убедиться, что форма работает предсказуемо и соответствует бизнес-логике.


Структура формы

В Ant Design форма создается с помощью компонента <Form> и дочерних элементов <Form.Item>:

import { Form, Input, Button } from 'antd';

const DemoForm = () => {
  const onFin ish = (values) => {
    console.log('Success:', values);
  };

  return (
    <Form onFin ish={onFinish} name="demo_form">
      <Form.Item
        name="username"
        rules={[{ required: true, message: 'Введите имя пользователя' }]}
      >
        <Input placeholder="Имя пользователя" />
      </Form.Item>

      <Form.Item
        name="password"
        rules={[{ required: true, message: 'Введите пароль' }]}
      >
        <Input.Password placeholder="Пароль" />
      </Form.Item>

      <Form.Item>
        <Button type="primary" htmlType="submit">
          Войти
        </Button>
      </Form.Item>
    </Form>
  );
};

При тестировании следует проверять:

  • Наличие всех обязательных полей.
  • Правильность заданной валидации.
  • Корректность отображения ошибок.

Тестирование с помощью Jest и React Testing Library

Для тестирования форм в Ant Design рекомендуется использовать React Testing Library, так как она позволяет имитировать поведение пользователя, а не только проверять структуру DOM.

Пример базового теста:

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

test('проверка обязательных полей формы', async () => {
  render(<DemoForm />);
  
  fireEvent.click(screen.getByText('Войти'));

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

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

  • Использование fireEvent для симуляции действий пользователя.
  • Проверка появления сообщений об ошибке через findByText.
  • Проверка успешной отправки формы через мок-функцию onFinish.

Мокирование отправки формы

Для проверки, что данные формы корректно передаются при успешной валидации, используется мок-функция:

test('успешная отправка формы', () => {
  const handleFinish = jest.fn();
  render(<DemoForm onFin ish={handleFinish} />);

  fireEvent.change(screen.getByPlaceholderText('Имя пользователя'), {
    target: { value: 'testuser' },
  });
  fireEvent.change(screen.getByPlaceholderText('Пароль'), {
    target: { value: 'password123' },
  });

  fireEvent.click(screen.getByText('Войти'));

  expect(handleFinish).toHaveBeenCalledWith({
    username: 'testuser',
    password: 'password123',
  });
});

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


Тестирование динамических форм

Ant Design поддерживает динамическое добавление и удаление полей через Form.List. Тестирование таких форм требует проверки:

  • Возможности добавления новых элементов.
  • Корректного удаления элементов.
  • Правильной валидации каждого элемента списка.

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

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

test('добавление и удаление элементов списка', () => {
  render(<DynamicForm />);
  
  fireEvent.click(screen.getByText('Добавить элемент'));
  expect(screen.getAllByPlaceholderText('Элемент')[0]).toBeInTheDocument();

  fireEvent.click(screen.getByText('Удалить'));
  expect(screen.queryByPlaceholderText('Элемент')).not.toBeInTheDocument();
});

Проверка пользовательских правил валидации

Форма может использовать кастомные правила через функцию validator:

<Form.Item
  name="age"
  rules={[
    { 
      validator: (_, value) => 
        value >= 18 ? Promise.resolve() : Promise.reject('Возраст должен быть ≥ 18')
    },
  ]}
>
  <Input type="number" placeholder="Возраст" />
</Form.Item>

Тестирование таких правил требует имитации ввода:

test('валидация кастомного правила', async () => {
  render(<DemoForm />);
  
  fireEvent.change(screen.getByPlaceholderText('Возраст'), { target: { value: 16 } });
  fireEvent.click(screen.getByText('Войти'));

  expect(await screen.findByText('Возраст должен быть ≥ 18')).toBeInTheDocument();
});

Интеграционное тестирование форм

При сложных формах рекомендуется интеграционное тестирование, которое:

  • Проверяет взаимодействие с API через мок-сервисы.
  • Контролирует изменение состояния приложения после отправки формы.
  • Оценивает работу условной логики показа/скрытия полей.

Пример использования MSW (Mock Service Worker) для мокирования API:

import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { render, screen, fireEvent } from '@testing-library/react';
import DemoForm from './DemoForm';

const server = setupServer(
  rest.post('/login', (req, res, ctx) => {
    return res(ctx.json({ success: true }));
  })
);

beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());

test('отправка формы на API', async () => {
  render(<DemoForm />);
  
  fireEvent.change(screen.getByPlaceholderText('Имя пользователя'), { target: { value: 'user' } });
  fireEvent.change(screen.getByPlaceholderText('Пароль'), { target: { value: 'pass' } });
  
  fireEvent.click(screen.getByText('Войти'));

  expect(await screen.findByText('Успешный вход')).toBeInTheDocument();
});

Рекомендации по покрытию тестами

  • Проверять каждое обязательное поле и каждое правило валидации.
  • Тестировать граничные значения, например пустые поля, длинные строки, некорректный формат.
  • Использовать моки и шпионы для проверки вызовов функций и отправки данных.
  • Для динамических форм тестировать добавление/удаление элементов и их валидацию.
  • Покрывать интеграционные сценарии с API и условной логикой отображения.

Тщательное тестирование форм в Ant Design обеспечивает надежность интерфейса и предотвращает ошибки валидации и логики отправки данных.