Floating UI — это современная библиотека для управления позиционированием всплывающих элементов в веб-приложениях. При тестировании поведения компонентов, использующих Floating UI, важно концентрироваться на точности вычисления позиции, корректности применения стратегий смещения и устойчивости к изменениям DOM. Unit-тесты здесь не проверяют визуальное отображение на экране, а подтверждают корректность логики вычислений.
Для unit-тестирования рекомендуется использовать Jest или Vitest, а
также JSDOM для имитации DOM-среды. Floating UI требует, чтобы элементы
имели реальные размеры и позиции, поэтому часто необходимо
мокировать размеры и координаты элементов через
свойства getBoundingClientRect:
const reference = document.createElement('div');
const floating = document.createElement('div');
reference.getBoundingClientRect = jest.fn(() => ({
width: 100,
height: 50,
top: 200,
left: 300,
right: 400,
bottom: 250,
}));
floating.getBoundingClientRect = jest.fn(() => ({
width: 150,
height: 75,
top: 0,
left: 0,
right: 150,
bottom: 75,
}));
Такой подход позволяет тестировать позиционирование без необходимости рендерить элементы в реальном браузере.
Floating UI предоставляет функции computePosition,
которые возвращают объект с координатами x и y
и информацией о стратегии позиционирования (placement,
middlewareData). В unit-тестах важно проверить:
placement:const {computePosition} = require('@floating-ui/dom');
test('позиция floating элемента с placement top', async () => {
const {x, y, placement} = await computePosition(reference, floating, {placement: 'top'});
expect(placement).toBe('top');
expect(y).toBeLessThan(reference.getBoundingClientRect().top);
});
offset, flip и shift:import {offset, flip, shift} from '@floating-ui/dom';
test('middleware offset корректно смещает элемент', async () => {
const {x, y} = await computePosition(reference, floating, {
placement: 'bottom',
middleware: [offset(10)]
});
expect(y).toBe(reference.getBoundingClientRect().bottom + 10);
});
test('flip middleware меняет placement при нехватке места', async () => {
const {placement} = await computePosition(reference, floating, {
placement: 'top',
middleware: [flip()]
});
expect(['top', 'bottom']).toContain(placement);
});
В реальных приложениях floating-элемент может зависеть от размеров окна и позиции скролла. В тестах эти данные можно замокировать:
Object.defineProperty(window, 'innerWidth', {value: 800});
Object.defineProperty(window, 'innerHeight', {value: 600});
window.scrollX = 50;
window.scrollY = 100;
При этом функции computePosition будут использовать эти
значения для расчёта x и y.
Floating UI поддерживает динамическое позиционирование через
middleware autoUpdate. Для unit-тестов важно симулировать
изменение размеров элементов и проверять, что новые координаты
пересчитываются корректно:
import {autoUpdate, computePosition} from '@floating-ui/dom';
let cleanup;
beforeEach(() => {
cleanup = autoUpdate(reference, floating, ({x, y}) => {
floating.style.transform = `translate(${x}px, ${y}px)`;
});
});
afterEach(() => {
cleanup();
});
test('обновление позиции при изменении размеров reference', async () => {
reference.getBoundingClientRect = jest.fn(() => ({
width: 200,
height: 100,
top: 100,
left: 100,
right: 300,
bottom: 200,
}));
const {x, y} = await computePosition(reference, floating, {placement: 'bottom'});
expect(y).toBe(200);
});
top,
bottom, left, right, а также
комбинации с start и end.Floating UI возвращает стратегию позиционирования
absolute или fixed. В тестах важно убедиться,
что:
absolute корректно учитывает offset родительского
контейнера.fixed игнорирует скролл страницы.test('fixed strategy игнорирует скролл', async () => {
const {x, y} = await computePosition(reference, floating, {strategy: 'fixed'});
expect(y).toBe(reference.getBoundingClientRect().top);
});
shift и flipMiddleware shift корректирует позицию floating-элемента
при пересечении с границами контейнера, а flip меняет
placement. Unit-тесты должны проверять оба эффекта:
test('shift корректирует координаты при выходе за viewport', async () => {
reference.getBoundingClientRect = jest.fn(() => ({
width: 100,
height: 50,
top: -20,
left: 50,
right: 150,
bottom: 30,
}));
const {x, y} = await computePosition(reference, floating, {middleware: [shift()]});
expect(y).toBeGreaterThanOrEqual(0);
});
Floating UI позволяет комбинировать middleware для сложного поведения. В unit-тестах важно проверять цепочку в целом:
test('offset + flip + shift middleware корректно взаимодействуют', async () => {
const {x, y, placement} = await computePosition(reference, floating, {
placement: 'top',
middleware: [offset(10), flip(), shift()]
});
expect(['top', 'bottom']).toContain(placement);
expect(x).toBeGreaterThanOrEqual(0);
expect(y).toBeGreaterThanOrEqual(0);
});
Unit-тесты для Floating UI концентрируются на точности вычислений координат, правильности применения middleware и устойчивости к изменениям размеров и скролла. Такой подход обеспечивает надежность позиционирования даже при сложных сценариях интерфейса.