Floating UI — это библиотека для управления позиционированием плавающих элементов в веб-приложениях. Интеграционные тесты в контексте Floating UI направлены на проверку взаимодействия компонентов, корректного расчёта позиций, учёта сдвигов и ограничений области видимости. В отличие от юнит-тестов, интеграционные тесты фокусируются на поведении нескольких компонентов вместе, а не на изоляции функций.
Для интеграционных тестов с Floating UI обычно используют комбинацию Jest и Testing Library (DOM Testing Library) или Cypress для e2e-тестирования. Основная цель — смоделировать пользовательские сценарии с плавающими элементами и проверить их позиционирование и динамическое поведение.
Пример установки зависимостей:
npm install @floating-ui/dom @testing-library/dom jest
@floating-ui/dom — основной модуль для работы с
позиционированием.@testing-library/dom — инструменты для взаимодействия с
DOM в тестах.jest — тестовый раннер для проверки логики.Floating UI работает с настоящим DOM, поэтому необходимо создать контейнеры и элементы для тестирования:
import { computePosition, offset, flip, shift } from '@floating-ui/dom';
document.body.innerHTML = `
<div id="reference" style="position: absolute; top: 100px; left: 100px; width: 50px; height: 50px;"></div>
<div id="floating" style="position: absolute; width: 100px; height: 100px;"></div>
`;
Ключевые моменты:
reference — опорный объект, относительно
которого позиционируется floating.floating должен иметь
position: absolute или fixed, чтобы Floating
UI корректно рассчитывал координаты.computePosition в тестахФункция computePosition — центральная в Floating UI. Она
возвращает координаты x и y для плавающего
элемента с учётом модификаторов.
test('Плавающий элемент корректно позиционируется снизу', async () => {
const reference = document.getElementById('reference');
const floating = document.getElementById('floating');
const { x, y } = await computePosition(reference, floating, {
placement: 'bottom',
middleware: [offset(10), flip(), shift({ padding: 5 })],
});
floating.style.left = `${x}px`;
floating.style.top = `${y}px`;
expect(floating.getBoundingClientRect().top).toBeGreaterThan(reference.getBoundingClientRect().bottom);
});
Разбор ключевых моментов:
placement: 'bottom' — указывает начальное предпочтение
позиции плавающего элемента.offset(10) — добавляет отступ между опорным и плавающим
элементами.flip() — позволяет элементу менять сторону, если на
выбранной позиции недостаточно места.shift({ padding: 5 }) — сдвигает элемент внутрь видимой
области, если он выходит за границы контейнера.Плавающие элементы часто изменяют позицию при изменении размеров окна или движения опорного элемента. Для интеграционных тестов важно имитировать эти изменения:
test('Элемент корректно смещается при изменении позиции reference', async () => {
const reference = document.getElementById('reference');
const floating = document.getElementById('floating');
reference.style.top = '200px';
const { x, y } = await computePosition(reference, floating, {
placement: 'top',
middleware: [offset(5), shift()],
});
floating.style.left = `${x}px`;
floating.style.top = `${y}px`;
expect(floating.getBoundingClientRect().bottom).toBeLessThan(reference.getBoundingClientRect().top);
});
Особенности интеграционного тестирования:
shift обеспечивает, что элемент не выйдет за
границы окна, что критично для адаптивных интерфейсов.Floating UI часто используется вместе с всплывающими подсказками,
меню и модальными окнами, которые могут иметь анимации. Для
интеграционных тестов анимации можно имитировать через прямое управление
стилями или использование jest.useFakeTimers():
test('Элемент плавно появляется при наведении', () => {
jest.useFakeTimers();
const reference = document.getElementById('reference');
const floating = document.getElementById('floating');
floating.style.opacity = '0';
floating.style.transition = 'opacity 300ms';
// Симулируем hover
reference.dispatchEvent(new MouseEvent('mouseenter'));
floating.style.opacity = '1';
jest.advanceTimersByTime(300);
expect(floating.style.opacity).toBe('1');
jest.useRealTimers();
});
Важные моменты:
Для полноценного интеграционного тестирования Floating UI в рамках React или Vue:
reference и
floating.render из Testing Library или
mount в Vue Test Utils.getBoundingClientRect.Пример для React:
import { render, screen } from '@testing-library/react';
import { useFloating } from '@floating-ui/react';
function Tooltip({ text }) {
const { x, y, reference, floating } = useFloating({ placement: 'top' });
return (
<>
<button ref={reference}>Hover me</button>
<div ref={floating} style={{ position: 'absolute', left: x ?? 0, top: y ?? 0 }}>
{text}
</div>
</>
);
}
test('Tooltip позиционируется над кнопкой', () => {
render(<Tooltip text="Hello" />);
const button = screen.getByText('Hover me');
const tooltip = screen.getByText('Hello');
expect(tooltip.getBoundingClientRect().bottom).toBeLessThan(button.getBoundingClientRect().top);
});
Эти подходы позволяют создать надёжную интеграционную базу для компонентов, использующих Floating UI, и гарантировать корректное поведение плавающих элементов в разных сценариях интерфейса.