Моки и стабы

Моки (mocks) и стабы (stubs) — это инструменты для имитации поведения объектов или функций в процессе тестирования и разработки интерактивных интерфейсов. В контексте библиотеки Shopify Draggable они помогают отделить логику перетаскивания элементов от реального DOM, что упрощает проверку сценариев drag-and-drop.


Использование моков для элементов Draggable

Моки позволяют создавать объекты, которые ведут себя как настоящие элементы Draggable, но не требуют реального DOM. Это особенно полезно для юнит-тестов, где нужно проверить события drag:start, drag:move и drag:stop.

import { Draggable } from '@shopify/draggable';

const mockContainer = document.createElement('div');
const mockItem = document.createElement('div');

mockContainer.appendChild(mockItem);

const draggable = new Draggable(mockContainer, {
  draggable: 'div'
});

// Подключение обработчика с мок-данными
draggable.on('drag:start', (event) => {
  console.log('Начало перетаскивания', event.source);
});

// Имитируем событие drag:start вручную
const mockEvent = {
  source: mockItem,
  sensorEvent: null,
};
draggable.trigger('drag:start', mockEvent);

Ключевые моменты использования моков:

  • Позволяют тестировать события без реального взаимодействия с пользователем.
  • Можно имитировать различные сценарии перетаскивания, включая ошибки и исключения.
  • Сокращают время тестирования за счёт исключения необходимости рендеринга DOM.

Стабы для управления поведением функций

Стаб — это объект или функция, которая заменяет оригинальный метод для контроля возвращаемых значений. В Draggable это удобно при тестировании колбэков или при работе с асинхронными операциями, например, при обновлении состояния после drag:stop.

import { Draggable } from '@shopify/draggable';

// Стаб функции, которая должна возвращать новые позиции элементов
const getNewPosition = jest.fn().mockReturnValue({ x: 100, y: 200 });

const draggable = new Draggable(document.querySelectorAll('.list'), {
  draggable: '.item'
});

draggable.on('drag:stop', (event) => {
  const newPosition = getNewPosition(event.source);
  console.log(newPosition);
});

// Проверка вызова стаба
draggable.trigger('drag:stop', { source: document.querySelector('.item') });
console.log(getNewPosition.mock.calls.length); // 1

Особенности стаба:

  • Позволяет проверять, что функции вызываются с ожидаемыми параметрами.
  • Удобен для симуляции сложного поведения без изменения основной логики.
  • Часто комбинируется с моками для полноценного тестирования drag-and-drop.

Интеграция моков и стабов в тесты Draggable

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

  1. Создание моков элементов и контейнеров – обеспечивает контроль над DOM без реального рендеринга.
  2. Применение стабов к критическим функциям – позволяет проверять реакцию приложения на события drag:start, drag:move и drag:stop.
  3. Триггеры событий вручную – используют draggable.trigger('event', mockEvent) для эмуляции пользовательских действий.
  4. Ассерты – проверка вызовов стабов и состояний мок-объектов после событий.

Пример комплексного теста:

import { Draggable } from '@shopify/draggable';
import { jest } from '@jest/globals';

const container = document.createElement('div');
const item = document.createElement('div');
container.appendChild(item);

const draggable = new Draggable(container, { draggable: 'div' });

const positionStub = jest.fn().mockReturnValue({ x: 50, y: 75 });

draggable.on('drag:stop', (event) => {
  const pos = positionStub(event.source);
  item.style.transform = `translate(${pos.x}px, ${pos.y}px)`;
});

// Мок события drag
const mockEvent = { source: item, sensorEvent: null };
draggable.trigger('drag:stop', mockEvent);

console.assert(positionStub.mock.calls.length === 1, 'Стаб должен быть вызван один раз');
console.assert(item.style.transform === 'translate(50px, 75px)', 'Позиция элемента должна обновиться');

Практические советы

  • Всегда отделять мок и стаб от реальных элементов Draggable, чтобы не влиять на поведение интерфейса.
  • Использовать стабы для функций, которые зависят от внешних данных или состояния.
  • Комбинировать ручную генерацию событий с моками для проверки сложных сценариев: сортировка элементов, nested drag, отмена перетаскивания.
  • Поддерживать чистоту моков и стабов в тестах, чтобы избежать накопления состояния между тестовыми кейсами.

Моки и стабы становятся критически важными при создании надёжных и быстрых тестов для интерфейсов drag-and-drop, позволяя имитировать поведение пользователя и предсказывать результаты без полного рендеринга страницы.