Integration-тесты проверяют совместную работу нескольких модулей системы. В контексте библиотеки Shopify Draggable такие тесты подтверждают корректное взаимодействие:
Если unit-тесты изолированно проверяют отдельные функции, то integration-тесты воспроизводят реальное поведение интерфейса: захват элемента, перемещение, сортировку, обновление DOM и генерацию событий.
Основная цель — убедиться, что drag-and-drop сценарии корректно работают в браузерной среде и взаимодействуют с DOM так, как ожидается в пользовательском интерфейсе.
При тестировании Draggable интеграция обычно включает несколько уровней:
Базовый класс:
import {Draggable} from '@shopify/draggable';
Отвечает за:
Библиотека использует систему плагинов:
SortableDroppableSwappableCollidableResizeMirrorIntegration-тесты часто проверяют совместную работу ядра и плагинов.
Drag-операции напрямую изменяют DOM:
Тесты должны проверять фактические изменения DOM-структуры.
Для проверки drag-and-drop поведения используется тестовая среда браузера.
Наиболее распространённые инструменты:
Часто применяется комбинация:
Jest + jsdom (для логики)
Playwright/Cypress (для реального браузера)
Причина — jsdom не полностью поддерживает pointer-события и drag-поведение.
Перед тестом необходимо создать структуру HTML, имитирующую реальный интерфейс.
document.body.innerHTML = `
<ul class="list">
<li class="item">A</li>
<li class="item">B</li>
<li class="item">C</li>
</ul>
`;
Инициализация draggable-системы:
import {Sortable} from '@shopify/draggable';
const sortable = new Sortable(document.querySelectorAll('.list'), {
draggable: '.item'
});
Теперь список поддерживает сортировку элементов.
Integration-тест должен воспроизвести полный цикл перемещения элемента:
const item = document.querySelector('.item');
item.dispatchEvent(new MouseEvent('mousedown', {
bubbles: true
}));
document.dispatchEvent(new MouseEvent('mousemove', {
bubbles: true,
clientX: 100,
clientY: 100
}));
document.dispatchEvent(new MouseEvent('mouseup', {
bubbles: true
}));
После выполнения сценария проверяется результат.
Главная задача integration-теста — удостовериться, что DOM обновился правильно.
const items = [...document.querySelectorAll('.item')];
const order = items.map(el => el.textContent);
expect(order).toEqual(['B', 'A', 'C']);
Проверяется:
Draggable генерирует большое количество событий.
Основные:
drag:startdrag:movedrag:stopsortable:startsortable:sortedsortable:stopIntegration-тесты проверяют:
const startHandler = jest.fn();
sortable.on('drag:start', startHandler);
Запуск drag-сценария:
simulateDrag();
Проверка:
expect(startHandler).toHaveBeenCalled();
Event-объекты содержат важные данные:
Пример теста:
sortable.on('drag:start', (event) => {
expect(event.source.textContent).toBe('A');
});
Integration-тест подтверждает, что система передаёт корректный контекст операции.
Для плагина Sortable критично проверять:
document.body.innerHTML = `
<ul class="list-a">
<li class="item">1</li>
</ul>
<ul class="list-b">
<li class="item">2</li>
</ul>
`;
Инициализация:
const sortable = new Sortable(
document.querySelectorAll('.list-a, .list-b'),
{ draggable: '.item' }
);
После drag-операции:
const containerB = document.querySelector('.list-b');
expect(containerB.children.length).toBe(2);
Во время drag-операции создаётся специальный DOM-элемент — mirror.
Он отображает перетаскиваемый элемент.
Integration-тест должен проверить:
const mirror = document.querySelector('.draggable-mirror');
expect(mirror).not.toBeNull();
expect(document.querySelector('.draggable-mirror')).toBeNull();
Плагин определяет столкновения элементов.
Integration-тест:
draggable.on('collidable:in', handler);
Проверка:
expect(handler).toHaveBeenCalled();
Позволяет бросать элементы в drop-зоны.
DOM-структура:
<div class="dropzone"></div>
Инициализация:
new Droppable(containers, {
draggable: '.item',
dropzone: '.dropzone'
});
Integration-тест проверяет:
droppable:droppedБольшинство приложений используют собственные обработчики событий.
Integration-тест должен подтверждать, что такие обработчики получают правильные данные.
Пример:
sortable.on('sortable:sorted', (event) => {
saveNewOrder(event.oldIndex, event.newIndex);
});
Тест:
expect(saveNewOrder).toHaveBeenCalledWith(0, 1);
Система поддерживает отмену действий через
event.cancel().
Пример:
sortable.on('drag:start', (event) => {
event.cancel();
});
Integration-тест:
simulateDrag();
const order = getListOrder();
expect(order).toEqual(['A', 'B', 'C']);
Порядок элементов не изменился — операция успешно отменена.
Некоторые integration-тесты проверяют нагрузку на систему.
Сценарий:
Тест оценивает:
В приложениях на React integration-тесты должны учитывать реактивное обновление DOM.
Основные проблемы:
Тест проверяет:
В среде Vue.js важно тестировать:
Integration-тест должен подтверждать, что после drag-операции:
Эффективные integration-тесты для Draggable обладают несколькими характеристиками.
Тесты должны имитировать реальные действия пользователя:
В отличие от unit-тестов, интеграционные проверки используют настоящий DOM и реальные события.
Тест должен проверять:
Стандартная структура:
describe()
beforeEach()
it()
simulateDrag()
assertions()
Пример:
describe('Sortable integration', () => {
beforeEach(() => {
setupDOM();
initSortable();
});
it('reorders elements', () => {
simulateDrag();
expect(getOrder()).toEqual(['B', 'A', 'C']);
});
});
Такой подход делает тесты:
Некоторые тесты вызывают только mousedown.
Drag-система требует полный цикл событий.
Иногда тесты проверяют только вызов handlers.
Это недостаточно — необходимо проверять изменения DOM.
jsdom не поддерживает:
Для сложных сценариев предпочтительны:
В инструментах вроде Playwright drag-операции можно выполнять напрямую.
Пример:
await page.dragAndDrop(
'.item:nth-child(1)',
'.item:nth-child(3)'
);
После этого выполняется проверка DOM.
Integration-тесты часто запускаются в системах непрерывной интеграции:
Для браузерных тестов используется headless-режим:
Это позволяет автоматически проверять drag-функциональность после каждого коммита.
Качественный набор integration-тестов для Shopify Draggable должен покрывать:
Такие тесты обеспечивают стабильную работу drag-and-drop интерфейсов даже при масштабных изменениях кода.