Тестирование
Тест — это код, который сам проверяет, что приложение работает правильно: выводит нужный текст, реагирует на клики. Тесты запускаются одной командой и находят ошибки до того, как их увидят пользователи. Для проектов на Vite используют Vitest — программу запуска тестов, и Testing Library — набор функций для отрисовки компонента и поиска элементов на нём так, как их ищет человек.
Установка
В папке проекта списка задач выполните:
npm install -D vitest jsdom @testing-library/react @testing-library/dom @testing-library/user-event @testing-library/jest-domjsdom имитирует браузер внутри Node.js, чтобы компоненты могли отрисоваться без настоящего окна. Флаг -D записывает пакеты в зависимости для разработки.
Настройка
Добавьте раздел test в vite.config.js:
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
test: {
environment: 'jsdom',
globals: true,
setupFiles: './src/setupTests.js',
},
});Создайте src/setupTests.js — он подключает удобные проверки вроде toBeInTheDocument:
// src/setupTests.js
import '@testing-library/jest-dom/vitest';И добавьте команду в раздел scripts файла package.json: "test": "vitest".
Первый тест
Тест лежит рядом с компонентом и называется так же, но с .test.jsx. Создайте src/components/TodoList.test.jsx:
// src/components/TodoList.test.jsx
import { render, screen } from '@testing-library/react';
import { expect, test } from 'vitest';
import TodoList from './TodoList.jsx';
test('показывает сообщение, когда задач нет', () => {
render(<TodoList todos={[]} />);
expect(screen.getByText('Задач нет. Можно отдохнуть.')).toBeInTheDocument();
});render отрисовывает компонент, screen.getByText ищет элемент с таким текстом. Запустите npm test — в терминале появится зелёная отметка и 1 passed. Vitest продолжит следить за файлами и перезапускать тесты при сохранении.
Действия пользователя
Библиотека user-event нажимает кнопки и вводит текст, как настоящий пользователь. Проверим форму — src/App.test.jsx:
// src/App.test.jsx
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { expect, test } from 'vitest';
import App from './App.jsx';
test('добавляет задачу в список', async () => {
const user = userEvent.setup();
render(<App />);
await user.type(screen.getByRole('textbox'), 'Полить цветы');
await user.click(screen.getByRole('button', { name: 'Добавить' }));
expect(screen.getByText('Полить цветы')).toBeInTheDocument();
});getByRole ищет элемент по его роли: textbox — поле ввода, button — кнопка с указанным текстом. Тест вводит текст, нажимает «Добавить» и проверяет, что задача появилась.
Способы поиска
| Функция | Когда использовать |
|---|---|
getByRole | Кнопки, поля, ссылки — предпочтительный способ |
getByText | Обычный текст на странице |
getByLabelText | Поле, у которого есть label |
queryByText | Проверить, что элемента нет: вернёт null |
findByText | Дождаться элемента, который появится позже |
Частая ошибка
Действия user-event асинхронные. Без await проверка выполнится раньше, чем закончится ввод, и тест упадёт:
// Неправильно:
user.type(screen.getByRole('textbox'), 'Полить цветы');
// Правильно:
await user.type(screen.getByRole('textbox'), 'Полить цветы');Помечайте функцию теста как async и ставьте await перед каждым действием пользователя.