В экосистеме Radix UI моки и stubs играют ключевую роль при разработке интерактивных компонентов, особенно в сочетании с фреймворками типа React. Они позволяют изолировать поведение компонента, эмулировать внешние зависимости и контролировать сценарии взаимодействия без реальной реализации логики или API-запросов.
Stub — это объект или функция, которая заменяет
часть кода, возвращая заранее определённые значения. Используется для
контроля результатов и упрощения тестов. Пример: stub функции, которая
возвращает фиксированные данные для выпадающего меню Radix
DropdownMenu:
const fetchItemsStub = jest.fn(() => [
{ id: 1, label: 'Элемент 1' },
{ id: 2, label: 'Элемент 2' },
]);
Здесь stub гарантирует, что компонент всегда получит одинаковый набор данных.
Mock — объект, который не только заменяет
зависимость, но и позволяет отслеживать взаимодействие с ней: сколько
раз вызвана функция, с какими аргументами, какие методы были вызваны.
Пример: mock для проверки вызова обработчика выбора элемента в
Select компоненте Radix:
const onSelectM ock = jest.fn();
render(<Sel ect onValueCha nge={onSelectMock} />);
userEvent.click(screen.getByText('Элемент 1'));
expect(onSelectMock).toHaveBeenCalledWith('Элемент 1');Изоляция внешних зависимостей Radix UI
предоставляет низкоуровневые primitives, такие как Popover,
Dialog, Slider, которые часто зависят от
данных или состояний приложения. Stubs позволяют избежать фактического
вызова API и гарантируют предсказуемость тестов.
Эмуляция пользовательского взаимодействия Моки
используются для отслеживания событий. Например, при тестировании
Tabs можно проверить, что при переключении вкладки
вызываются правильные коллбеки:
const onTabChangeM ock = jest.fn();
render(
<Tabs onValueCha nge={onTabChangeMock}>
<TabsList>
<TabsTrigger value="tab1">Вкладка 1</TabsTrigger>
<TabsTrigger value="tab2">Вкладка 2</TabsTrigger>
</TabsList>
<TabsContent value="tab1">Содержимое 1</TabsContent>
<TabsContent value="tab2">Содержимое 2</TabsContent>
</Tabs>
);
userEvent.click(screen.getByText('Вкладка 2'));
expect(onTabChangeMock).toHaveBeenCalledWith('tab2');Тестирование асинхронных операций Для
компонентов Radix UI, которые зависят от асинхронных данных (например,
фильтры в DropdownMenu), stubs позволяют контролировать
поведение без реального запроса:
const fetchDataStub = jest.fn(() => Promise.resolve(['Опция 1', 'Опция 2']));
await act(async () => {
render(<MyDropdown fetchItems={fetchDataStub} />);
});
expect(fetchDataStub).toHaveBeenCalled();
expect(screen.getByText('Опция 1')).toBeInTheDocument();mockReset или
mockClear), чтобы избежать взаимного влияния тестов.Пример комбинированного подхода: использование stubs для данных и mock функций для проверки событий:
import { setupServer } fr om 'msw/node';
import { rest } from 'msw';
const server = setupServer(
rest.get('/api/items', (req, res, ctx) => res(ctx.json(['Опция A', 'Опция B'])))
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
const onChangeM ock = jest.fn();
render(<Dropdown fetchItems={() => fetch('/api/items')} onCha nge={onChangeMock} />);
userEvent.click(screen.getByText('Опция A'));
expect(onChangeMock).toHaveBeenCalledWith('Опция A');
Такой подход позволяет создавать надёжные тесты для Radix UI primitives, поддерживая высокое качество интерактивных интерфейсов и предотвращая регрессии при развитии проекта.