E2E тестирование

Библиотека Shopify Draggable реализует сложную пользовательскую механику: перемещение элементов, сортировку списков, работу с контейнерами, drag-and-drop между областями интерфейса. Такие сценарии трудно покрыть только модульными или интеграционными тестами.

E2E-тестирование (End-to-End) проверяет систему на уровне реального пользовательского поведения. Тесты взаимодействуют с браузером так же, как это делает пользователь:

  • нажимают на элемент
  • перемещают курсор
  • перетаскивают объекты
  • проверяют изменения DOM
  • контролируют состояние приложения после взаимодействия

Для drag-and-drop интерфейсов это особенно важно, потому что:

  • события мыши формируются в сложной последовательности
  • участвуют координаты курсора
  • активируются внутренние события библиотеки
  • изменяется структура DOM

E2E-тесты позволяют проверить полный цикл работы Draggable: от пользовательского жеста до финального состояния интерфейса.


Инструменты для E2E тестирования

Для браузерного тестирования JavaScript-приложений чаще всего используются следующие инструменты:

Инструмент Особенности
Cypress быстрые тесты, простой API, встроенные ожидания
Playwright кроссбраузерное тестирование, высокая точность эмуляции
Selenium классический инструмент автоматизации браузеров
Puppeteer управление Chromium через DevTools

Наиболее удобными для drag-and-drop считаются Playwright и Cypress, так как они умеют корректно эмулировать пользовательские действия мышью.


Архитектура E2E тестирования drag-and-drop

При тестировании интерфейсов на основе Shopify Draggable важно проверять несколько уровней поведения.

1. Поведение интерфейса

Проверяется:

  • начало перетаскивания
  • перемещение элемента
  • подсветка зоны drop
  • окончание операции

2. Изменение DOM

После перемещения элемент должен:

  • оказаться в новом контейнере
  • занять новую позицию
  • изменить порядок в списке

3. Состояние приложения

Возможны дополнительные проверки:

  • обновление состояния хранилища
  • изменение данных в UI
  • отправка событий аналитики

Подготовка приложения для E2E тестирования

Структура HTML

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

После инициализации элементы можно менять местами. Именно это поведение и будет тестироваться.


Базовый сценарий E2E теста

Сценарий пользовательского поведения:

  1. открыть страницу
  2. взять первый элемент
  3. перетащить его вниз
  4. проверить изменение порядка

Пример теста с Playwright

Тестовый файл:

import { test, expect } from '@playwright/test';

test('items can be reordered', async ({ page }) => {

  await page.goto('http://localhost:3000');

  const first = page.locator('.item').nth(0);
  const third = page.locator('.item').nth(2);

  const firstBox = await first.boundingBox();
  const thirdBox = await third.boundingBox();

  await page.mouse.move(
    firstBox.x + firstBox.width / 2,
    firstBox.y + firstBox.height / 2
  );

  await page.mouse.down();

  await page.mouse.move(
    thirdBox.x + thirdBox.width / 2,
    thirdBox.y + thirdBox.height / 2
  );

  await page.mouse.up();

  const items = await page.locator('.item').allTextContents();

  expect(items).toEqual(['B', 'C', 'A']);
});

Что проверяет тест

  1. получение координат элементов
  2. эмуляцию перемещения мыши
  3. событие mousedown
  4. перемещение курсора
  5. событие mouseup
  6. итоговый порядок элементов

Такой тест максимально близок к реальному пользовательскому взаимодействию.


Особенности drag-and-drop тестирования

Последовательность событий

Перетаскивание формирует цепочку событий:

mousedown
drag:start
drag:move
drag:over
drag:stop
mouseup

Библиотека Shopify Draggable генерирует собственные события поверх стандартных DOM-событий.


Координаты курсора

Большинство drag-and-drop тестов используют:

element.boundingBox()

Это позволяет получить:

  • положение элемента
  • ширину
  • высоту

Координаты используются для корректного перемещения мыши.


Задержки рендеринга

После перемещения элемента DOM может обновляться асинхронно.

Поэтому тест должен учитывать:

  • ожидание завершения drag-операции
  • ожидание обновления интерфейса

В Playwright это реализуется автоматически через expect.


Проверка перемещения между контейнерами

Интерфейсы часто позволяют переносить элементы между списками.

HTML структура

<div class="container">
  <ul class="list list-a">
    <li class="item">A</li>
  </ul>

  <ul class="list list-b">
    <li class="item">B</li>
  </ul>
</div>

Тест

test('item can move between lists', async ({ page }) => {

  await page.goto('http://localhost:3000');

  const item = page.locator('.list-a .item');
  const target = page.locator('.list-b');

  const itemBox = await item.boundingBox();
  const targetBox = await target.boundingBox();

  await page.mouse.move(
    itemBox.x + 10,
    itemBox.y + 10
  );

  await page.mouse.down();

  await page.mouse.move(
    targetBox.x + 20,
    targetBox.y + 20
  );

  await page.mouse.up();

  await expect(page.locator('.list-b .item')).toHaveCount(2);
});

Проверяется факт появления элемента во втором контейнере.


Проверка событий библиотеки

Shopify Draggable генерирует собственные события:

  • drag:start
  • drag:move
  • drag:over
  • drag:stop
  • sortable:sort
  • sortable:sorted

Иногда необходимо убедиться, что события действительно происходят.

Инструментирование кода

window.events = [];

sortable.on('sortable:sorted', event => {
  window.events.push(event);
});

Проверка в тесте

const events = await page.evaluate(() => window.events.length);

expect(events).toBeGreaterThan(0);

Тестирование placeholder элементов

Во время перетаскивания библиотека может создавать placeholder — временную позицию элемента.

Проверки:

  • placeholder появляется
  • placeholder исчезает после drop
  • placeholder занимает правильную позицию

Пример проверки:

await expect(page.locator('.draggable--placeholder')).toBeVisible();

После завершения операции:

await expect(page.locator('.draggable--placeholder')).toHaveCount(0);

Тестирование доступности (Accessibility)

Drag-and-drop интерфейсы должны поддерживать клавиатуру.

В Shopify Draggable это реализуется через модуль:

KeyboardSensor

E2E тест может проверять:

  • выбор элемента клавишей
  • перемещение стрелками
  • подтверждение позиции

Пример теста:

await page.keyboard.press('Tab');
await page.keyboard.press('Space');
await page.keyboard.press('ArrowDown');
await page.keyboard.press('Space');

После этого проверяется порядок элементов.


Проверка анимаций

Draggable часто использует CSS-анимации при перестановке элементов.

E2E тесты должны учитывать:

  • задержку анимации
  • окончание transition

Playwright позволяет ожидать стабилизацию DOM:

await page.waitForTimeout(300);

Однако предпочтительно проверять конечное состояние интерфейса, а не промежуточные состояния.


Изоляция тестов

Каждый E2E тест должен запускаться в чистой среде.

Основные методы:

Перезагрузка страницы

await page.goto('/');

Очистка состояния приложения

localStorage.clear();

Использование тестового сервера

Часто используется отдельный тестовый билд приложения.


Тестирование различных сенсоров

Библиотека Shopify Draggable использует сенсоры для различных устройств:

Сенсор Назначение
MouseSensor мышь
TouchSensor сенсорные устройства
ForceTouchSensor pressure touch
KeyboardSensor клавиатура

E2E тесты могут проверять разные сценарии.

Например, сенсорный ввод.

Playwright:

await page.touchscreen.tap(100, 200);

Для мобильных интерфейсов это особенно важно.


Параллельный запуск тестов

Современные инструменты позволяют запускать E2E тесты параллельно.

Например в Playwright:

npx playwright test --workers=4

Это ускоряет проверку интерфейсов с большим количеством drag-and-drop сценариев.


CI интеграция

E2E тесты обычно запускаются в системе непрерывной интеграции.

Наиболее распространённые системы:

  • GitHub Actions
  • GitLab CI
  • Jenkins

Типичный pipeline:

install dependencies
build project
start test server
run e2e tests
collect reports

Отчёты о тестировании

Большинство фреймворков генерируют отчёты:

  • скриншоты падений
  • видео тестов
  • трассировку событий

В Playwright включается запись:

trace: 'on'
video: 'retain-on-failure'

Это значительно упрощает диагностику ошибок drag-and-drop интерфейсов.


Типичные проблемы при тестировании Draggable

Нестабильные координаты

Решение:

  • использовать boundingBox
  • избегать фиксированных координат

Слишком быстрые действия

Тесты могут выполняться быстрее браузера.

Решение:

  • использовать встроенные ожидания
  • проверять DOM после действия

CSS overlay

Некоторые элементы могут перекрывать draggable-элементы.

Решение:

  • проверять pointer-events
  • проверять z-index

Рекомендации по построению E2E тестов

Хорошая практика

  • тестировать реальные пользовательские сценарии
  • минимизировать зависимость от координат
  • проверять финальное состояние DOM
  • использовать стабильные селекторы (data-testid)

Плохая практика

  • тестировать внутреннюю реализацию библиотеки
  • проверять временные состояния
  • использовать фиксированные задержки

Стратегия покрытия drag-and-drop

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

  1. сортировку внутри списка
  2. перенос между контейнерами
  3. отмену операции
  4. работу клавиатуры
  5. мобильные сценарии
  6. появление placeholder
  7. события библиотеки

Такой набор E2E тестов обеспечивает проверку всей функциональности интерфейсов, построенных на основе Shopify Draggable.