Integration тесты

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 — тестовый раннер для проверки логики.

Создание тестового DOM

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);
});

Особенности интеграционного тестирования:

  • Тест проверяет не только расчет координат, но и визуальное соответствие позиции в DOM.
  • Middleware 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();
});

Важные моменты:

  • В интеграционных тестах важно проверять состояние после завершения анимации.
  • Использование таймеров позволяет контролировать асинхронные изменения в DOM.

Интеграция с реальными компонентами UI

Для полноценного интеграционного тестирования Floating UI в рамках React или Vue:

  1. Создать компонент с реальным reference и floating.
  2. Использовать render из Testing Library или mount в Vue Test Utils.
  3. Проверять визуальные эффекты и корректность координат через 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);
});

Практические рекомендации

  • Всегда проверять координаты плавающего элемента в реальном DOM.
  • Middleware (offset, flip, shift, arrow) следует тестировать по отдельности и вместе, чтобы выявить конфликты.
  • Для интеграционных тестов полезно создавать контейнеры с ограниченной областью видимости, чтобы проверить поведение на границах.
  • Симуляция событий пользователя (hover, focus, click) помогает проверить динамическое поведение Floating UI.

Эти подходы позволяют создать надёжную интеграционную базу для компонентов, использующих Floating UI, и гарантировать корректное поведение плавающих элементов в разных сценариях интерфейса.