Тестирование рендеринга
Тестирование рендеринга — проверка того, что React (или другой UI-фреймворк) компонент отображает нужный контент при заданных props и state, через
renderиз Testing Library или snapshot-тесты.
Зачем нужно
Компонент должен рендерить правильный контент при разных наборах props: показывать данные пользователя, скрывать элементы при отсутствии прав, отображать loading-состояние. Тестирование рендеринга предотвращает регрессии в отображении при изменении логики.
Где используется
- Тестирование условного рендеринга (if/else, тернарные операторы)
- Проверка рендеринга списков с разным количеством элементов
- Тест loading/error/empty состояний компонента
- Проверка корректности отображения данных из props
Основной контент
Базовый тест рендеринга
// UserCard.test.tsx
import { render, screen } from '@testing-library/react';
import { UserCard } from './UserCard';
test('отображает имя и email пользователя', () => {
render(<UserCard name="Alice" email="alice@example.com" />);
expect(screen.getByText('Alice')).toBeInTheDocument;
expect(screen.getByText('alice@example.com')).toBeInTheDocument;
});
Условный рендеринг
// Badge.tsx — рендерит badge только для admin
test('показывает badge для admin', () => {
render(<UserCard name="Alice" role="admin" />);
expect(screen.getByText('Admin')).toBeInTheDocument;
});
test('скрывает badge для обычного пользователя', () => {
render(<UserCard name="Bob" role="user" />);
expect(screen.queryByText('Admin')).not.toBeInTheDocument;
});
Loading/Error/Empty состояния
// DataList.test.tsx
test('показывает спиннер при загрузке', () => {
render(<DataList status="loading" data={} />);
expect(screen.getByRole('progressbar')).toBeInTheDocument;
expect(screen.queryByRole('list')).not.toBeInTheDocument;
});
test('показывает ошибку при сбое', () => {
render(<DataList status="error" data={} error="Ошибка сети" />);
expect(screen.getByText('Ошибка сети')).toBeInTheDocument;
});
test('показывает пустое состояние при отсутствии данных', () => {
render(<DataList status="success" data={} />);
expect(screen.getByText('Данных нет')).toBeInTheDocument;
expect(screen.queryByRole('listitem')).not.toBeInTheDocument;
});
test('рендерит список при наличии данных', () => {
const data = [{ id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }];
render(<DataList status="success" data={data} />);
expect(screen.getAllByRole('listitem')).toHaveLength(2);
expect(screen.getByText('Item 1')).toBeInTheDocument;
});
Рендеринг с провайдерами
// Если компонент использует Context, Redux, Router — нужна обёртка
import { renderWithProviders } from '../test-utils';
test('UserProfile рендерится с store', () => {
renderWithProviders(<UserProfile userId={1} />, {
preloadedState: {
users: { '1': { name: 'Alice', email: 'alice@test.com' } },
},
});
expect(screen.getByText('Alice')).toBeInTheDocument;
});
// test-utils.tsx
export function renderWithProviders(ui: React.ReactElement, options = {}) {
const { preloadedState, ...renderOptions } = options;
const store = configureStore({ reducer: rootReducer, preloadedState });
return render(<Provider store={store}>{ui}</Provider>, renderOptions);
}
Snapshot — для фиксации структуры
test('Button рендерится стабильно', () => {
const { container } = render(<Button variant="primary" label="Click" />);
expect(container).toMatchSnapshot;
});
Частые ошибки
- Тест HTML-структуры вместо пользовательского контента —
expect(container.querySelector('.btn-primary')).toBeTruthyломается при рефакторинге стилей; проверяй черезgetByRole,getByText getByдля проверки отсутствия —expect( => screen.getByText('Admin')).toThrowнеудобно; используйqueryByTextс.not.toBeInTheDocument- Snapshot без review — принятый снимок с багом в рендеринге закрепляет баг; всегда проверяй diff снимков
Связанные темы
- _MOC Тестирование
- React Testing Library -- основы
- Testing Library -- подход
- Jest -- snapshot тесты
- Тестирование хуков