Unit тесты позволяют проверять отдельные компоненты интерфейса на корректность их работы без необходимости рендерить весь интерфейс приложения. В контексте Radix UI это особенно важно, так как библиотека предоставляет низкоуровневые, но мощные компоненты с богатым набором состояний и событий.
Для unit тестов чаще всего используют комбинацию Jest для запуска тестов и @testing-library/react для имитации пользовательских взаимодействий и проверки состояния DOM.
npm install --save-dev jest @testing-library/react @testing-library/jest-dom
jest.config.js с базовыми настройками:module.exports = {
testEnvironment: "jsdom",
setupFilesAfterEnv: ["@testing-library/jest-dom/extend-expect"],
moduleFileExtensions: ["js", "jsx", "ts", "tsx"],
};
jsdom покрывает все основные случаи.Radix UI DialogКомпонент Dialog состоит из Dialog.Root,
Dialog.Trigger и Dialog.Content. Unit тест
должен проверять:
import { render, screen, fireEvent } from "@testing-library/react";
import * as Dialog from "@radix-ui/react-dialog";
test("Dialog открывается и закрывается", () => {
render(
<Dialog.Root>
<Dialog.Trigger>Открыть</Dialog.Trigger>
<Dialog.Content>
<p>Содержимое диалога</p>
</Dialog.Content>
</Dialog.Root>
);
expect(screen.queryByText("Содержимое диалога")).toBeNull();
fireEvent.click(screen.getByText("Открыть"));
expect(screen.getByText("Содержимое диалога")).toBeVisible();
fireEvent.keyDown(document, { key: "Escape" });
expect(screen.queryByText("Содержимое диалога")).toBeNull();
});
Ключевые моменты:
fireEvent имитирует действия
пользователяМногие компоненты Radix UI, такие как Popover или
Tooltip, используют анимации и таймауты. Для тестов это
требует применения асинхронных утилит:
import { render, screen, waitFor, fireEvent } from "@testing-library/react";
import * as Tooltip from "@radix-ui/react-tooltip";
test("Tooltip отображается после наведения", async () => {
render(
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger>Наведи на меня</Tooltip.Trigger>
<Tooltip.Content>Подсказка</Tooltip.Content>
</Tooltip.Root>
</Tooltip.Provider>
);
fireEvent.mouseOver(screen.getByText("Наведи на меня"));
await waitFor(() => {
expect(screen.getByText("Подсказка")).toBeVisible();
});
});
Особенности:
waitFor позволяет дождаться окончания
анимаций или обновлений состоянияTooltip.Provider обязателен для корректного рендеринга
порталовRadix UI TabsКомпонент Tabs имеет несколько панелей и управляет
состоянием активного таба. Важно тестировать:
import { render, screen, fireEvent } from "@testing-library/react";
import * as Tabs from "@radix-ui/react-tabs";
test("Tabs переключаются корректно", () => {
render(
<Tabs.Root defaultValue="tab1">
<Tabs.List>
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">Содержимое 1</Tabs.Content>
<Tabs.Content value="tab2">Содержимое 2</Tabs.Content>
</Tabs.Root>
);
expect(screen.getByText("Содержимое 1")).toBeVisible();
expect(screen.queryByText("Содержимое 2")).toBeNull();
fireEvent.click(screen.getByText("Tab 2"));
expect(screen.getByText("Содержимое 2")).toBeVisible();
expect(screen.queryByText("Содержимое 1")).toBeNull();
});
Radix UI строго следует стандартам ARIA. Unit тесты могут проверять наличие нужных атрибутов:
import { render, screen } from "@testing-library/react";
import * as Toggle from "@radix-ui/react-toggle";
test("Toggle имеет правильный ARIA state", () => {
render(<Toggle.Root>Вкл/Выкл</Toggle.Root>);
const toggle = screen.getByRole("button");
expect(toggle).toHaveAttribute("aria-pressed", "false");
toggle.click();
expect(toggle).toHaveAttribute("aria-pressed", "true");
});
Преимущества такой проверки:
Иногда компоненты используют window или контекст,
который не нужен в unit тестах. В таких случаях используют
jest.mock:
jest.mock("some-external-library", () => ({
someFunction: jest.fn(() => "mocked value"),
}));
Это позволяет изолировать тестируемый компонент и проверять только его логику.
screen и селекторы,
ориентированные на текст или ролиUnit тесты компонентов Radix UI позволяют создавать стабильный и доступный интерфейс, минимизировать ошибки при рефакторинге и гарантировать корректную работу интерактивных элементов. Правильная организация тестов обеспечивает как покрытие базовой функциональности, так и проверку сложных состояний компонентов.