Юнит-тестирование компонентов библиотеки MUI (Material-UI) в JavaScript чаще всего выполняется с использованием инструментов Jest и React Testing Library. Основная цель — проверка поведения отдельных компонентов, их рендеринга, взаимодействия с пользователем и корректности пропсов.
Для тестирования компонентов MUI необходимо установить базовые зависимости:
npm install --save-dev @testing-library/react @testing-library/jest-dom jest
Если используется TypeScript, добавляются типы:
npm install --save-dev @types/jest @testing-library/user-event
Важно учитывать, что многие компоненты MUI зависят от темы и контекста ThemeProvider. Без него тестируемый компонент может рендериться некорректно.
import { ThemeProvider, createTheme } from '@mui/material/styles';
const theme = createTheme();
const renderWithTheme = (ui) => {
return render(<ThemeProvider theme={theme}>{ui}</ThemeProvider>);
};
Для проверки корректного рендеринга компонентов MUI используется
render из React Testing
Library:
import { render, screen } from '@testing-library/react';
import Button from '@mui/material/Button';
test('кнопка отображается с правильным текстом', () => {
render(<Button>Нажми меня</Button>);
const buttonElement = screen.getByRole('button', { name: /Нажми меня/i });
expect(buttonElement).toBeInTheDocument();
});
Ключевые моменты:
toBeInTheDocument().Многие компоненты MUI принимают пропсы, влияющие на их визуальное состояние:
import Checkbox from '@mui/material/Checkbox';
import userEvent from '@testing-library/user-event';
test('чекбокс может быть отмечен и снят', async () => {
const user = userEvent.setup();
render(<Checkbox data-testid="checkbox" />);
const checkbox = screen.getByTestId('checkbox');
expect(checkbox).not.toBeChecked();
await user.click(checkbox);
expect(checkbox).toBeChecked();
await user.click(checkbox);
expect(checkbox).not.toBeChecked();
});
Особенности:
toBeChecked() и
not.toBeChecked() позволяют проверять
состояние компонентов, управляемых React.userEvent, который более надежен, чем
прямые вызовы fireEvent.Компоненты диалогов, модальных окон и всплывающих меню требуют
внимания к порталам (Portal) и
асинхронным операциям:
import Dialog from '@mui/material/Dialog';
import Button from '@mui/material/Button';
test('диалог открывается по клику', async () => {
const user = userEvent.setup();
render(<MyDialogComponent />); // компонент с кнопкой открытия диалога
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
await user.click(screen.getByText('Открыть диалог'));
expect(screen.getByRole('dialog')).toBeVisible();
});
Особенности тестирования:
screen.getByRole или
screen.queryByRole вместо поиска внутри контейнера
рендера.toBeVisible()
более информативна, чем просто присутствие в DOM.MUI компоненты имеют сложную структуру DOM, поэтому снимки помогают отслеживать изменения в визуальном отображении:
import { render } from '@testing-library/react';
import Card from '@mui/material/Card';
test('Card рендерится корректно', () => {
const { asFragment } = render(<Card>Контент карточки</Card>);
expect(asFragment()).toMatchSnapshot();
});
Примечания:
Компоненты MUI часто принимают onClick,
onChange и другие колбэки. Их проверка осуществляется
через jest.fn():
import Button from '@mui/material/Button';
test('колбэк вызывается при клике', async () => {
const user = userEvent.setup();
const handleClick = jest.fn();
render(<Button onCl ick={handleClick}>Нажми</Button>);
await user.click(screen.getByText('Нажми'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
Особенности:
toHaveBeenCalledTimes.toHaveBeenCalledWith.Если компонент MUI использует асинхронные операции (например, загрузка данных для Autocomplete):
import Autocomplete from '@mui/material/Autocomplete';
import TextField from '@mui/material/TextField';
test('Autocomplete отображает варианты после ввода', async () => {
const user = userEvent.setup();
const options = ['Apple', 'Banana', 'Cherry'];
render(
<Autocomplete
options={options}
renderInput={(params) => <TextField {...params} label="Фрукты" />}
/>
);
const input = screen.getByLabelText('Фрукты');
await user.type(input, 'B');
expect(await screen.findByText('Banana')).toBeInTheDocument();
});
Особенности:
findByText для
асинхронного ожидания элементов.user.type позволяет проверять
фильтрацию и динамическое обновление списка.Эти подходы позволяют создавать стабильные, поддерживаемые и понятные юнит-тесты для компонентов MUI в современных React-приложениях.