Моки и стабы

Tippy.js — это высоко настраиваемая библиотека для создания всплывающих подсказок (tooltips) на веб-страницах. Основная идея заключается в привязке всплывающего элемента к целевому DOM-элементу с возможностью динамического управления содержимым, позиционированием и поведением.

Базовая инициализация Tippy.js выполняется через функцию tippy, которой передаётся селектор или конкретный элемент:

tippy('#button', {
  content: 'Нажмите для действия',
});

В этом примере создаётся простой tooltip для элемента с id button. Опция content может быть как строкой, так и функцией, возвращающей динамическое значение.


Работа с множественными элементами

Tippy.js позволяет привязывать подсказки к нескольким элементам одновременно:

tippy('.tooltip', {
  content: 'Общая подсказка для всех элементов',
});

Каждый элемент с классом tooltip получит собственный экземпляр подсказки. Это создаёт независимые тултипы, управляемые отдельно.


Моки и стабы в контексте Tippy.js

При тестировании интерфейсов часто необходимо изолировать поведение Tippy.js от фактического DOM. Для этого используют моки и стабы:

  • Мок (mock) — имитация реального объекта с возможностью контроля поведения для тестирования. В Tippy.js можно замокать методы создания и отображения тултипа.
  • Стаб (stub) — упрощённая заглушка, которая имитирует интерфейс функции или объекта, но без полноценной логики. Используется для проверки вызова методов или передачи параметров.

Пример стаба для метода show:

import tippy from 'tippy.js';

const fakeShow = jest.fn();
const instance = tippy(document.createElement('div'));
instance.show = fakeShow;

instance.show();
expect(fakeShow).toHaveBeenCalled();

Такой подход позволяет тестировать логику взаимодействия с тултипом без фактического рендера на странице.


Динамическое управление контентом

Контент тултипа может меняться в процессе работы приложения. Tippy.js поддерживает функцию вместо строки:

tippy('#dynamic', {
  content: () => {
    return document.querySelector('#dynamic-content').textContent;
  },
});

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


Управление жизненным циклом тултипов

Tippy.js предоставляет методы жизненного цикла:

  • show() — показать тултип.
  • hide() — скрыть тултип.
  • destroy() — удалить экземпляр тултипа и очистить события.
  • setContent(content) — изменить содержимое на лету.

Для стаба жизненного цикла создаются заглушки на эти методы, позволяя проверить, что вызовы происходят корректно:

const instance = tippy(document.createElement('div'));
instance.show = jest.fn();
instance.hide = jest.fn();

instance.show();
instance.hide();

expect(instance.show).toHaveBeenCalledTimes(1);
expect(instance.hide).toHaveBeenCalledTimes(1);

Настройка поведения через опции

Основные опции, влияющие на отображение и взаимодействие:

  • placement — позиция тултипа (top, bottom, left, right и их вариации).
  • trigger — событие, запускающее тултип (mouseenter, click, focus, manual).
  • delay — задержка показа или скрытия (может быть числом или массивом [showDelay, hideDelay]).
  • interactive — разрешает взаимодействие с содержимым тултипа.

Для тестирования поведенческих сценариев удобно использовать стабы для событий и таймеров:

jest.useFakeTimers();
const instance = tippy(document.createElement('div'), { delay: 500 });
instance.show();
jest.advanceTimersByTime(500);
expect(instance.state.isVisible).toBe(true);

Работа с DOM через моки

В ситуациях, когда DOM недоступен (например, при юнит-тестах на Node.js), создаются заглушки элементов:

const mockElement = {
  addEventListener: jest.fn(),
  removeEventListener: jest.fn(),
};
const instance = tippy(mockElement, { content: 'Тест' });
expect(mockElement.addEventListener).toHaveBeenCalled();

Такой подход изолирует Tippy.js от реальной страницы и позволяет сосредоточиться на логике и поведении тултипов.


Комбинирование моков и асинхронных операций

Tippy.js часто используют совместно с динамическими данными. Моки позволяют эмулировать асинхронное получение контента:

const fetchContent = jest.fn(() => Promise.resolve('Данные с сервера'));

tippy('#async', {
  content: async () => await fetchContent(),
});

await fetchContent();
expect(fetchContent).toHaveBeenCalled();

Это обеспечивает проверку как вызова асинхронной функции, так и корректного обновления контента тултипа без реальных запросов.


Практика повторного использования стаба

Стабы можно создавать один раз и использовать для нескольких тестов:

const stubShow = jest.fn();
const stubHide = jest.fn();

beforeEach(() => {
  const instance = tippy(document.createElement('div'));
  instance.show = stubShow;
  instance.hide = stubHide;
});

test('проверка show', () => {
  instance.show();
  expect(stubShow).toHaveBeenCalled();
});

test('проверка hide', () => {
  instance.hide();
  expect(stubHide).toHaveBeenCalled();
});

Это повышает консистентность тестов и снижает дублирование кода.


Взаимодействие с внешними библиотеками

Tippy.js легко интегрируется с фреймворками вроде React или Vue. В тестах компонентов используют мок-объекты тултипов, чтобы проверять рендеринг и события, не создавая реальных DOM-элементов. Это особенно полезно при CI/CD и юнит-тестах, где визуальные проверки невозможны.


Моки и стабы позволяют максимально гибко контролировать поведение Tippy.js в тестовой среде, обеспечивая точное тестирование логики интерфейса без необходимости реального рендера и сложной настройки DOM.