Shepherd.js предоставляет гибкий API для создания интерактивных пользовательских туров, и тестирование таких туров требует внимания к нескольким ключевым аспектам: рендеринг шагов, триггеры событий и корректное завершение тура. Основной подход — изолировать каждый шаг и проверять его поведение независимо от всего приложения.
Для начала необходимо подключить Shepherd.js и инструмент для unit-тестирования, например Jest или Mocha. Важно создать DOM-элемент, к которому будет привязываться тур, так как без реального контейнера шаги не смогут корректно отобразиться:
import Shepherd from 'shepherd.js';
import 'shepherd.js/dist/css/shepherd.css';
beforeEach(() => {
document.body.innerHTML = '<div id="app"></div>';
});
Тур создаётся через конструктор Shepherd.Tour. Для
unit-тестирования рекомендуется задавать минимально необходимые шаги и
отключать анимацию и авто-скролл, чтобы тесты выполнялись
предсказуемо:
const tour = new Shepherd.Tour({
useModalOverlay: true,
defaultStepOptions: {
cancelIcon: {
enabled: true
},
scrollTo: false,
canClickTarget: false
}
});
tour.addStep({
id: 'step1',
text: 'Приветственный шаг',
attachTo: {
element: '#app',
on: 'bottom'
}
});
tour.addStep({
id: 'step2',
text: 'Второй шаг',
attachTo: {
element: '#app',
on: 'top'
}
});
Каждый шаг можно проверять на корректное отображение с помощью
методов show() и
isOpen(). В тесте важно убедиться, что шаг
появляется после вызова show() и закрывается после
hide() или перехода к следующему шагу:
test('Проверка отображения шага', () => {
const step = tour.getById('step1');
expect(step.isOpen()).toBe(false);
step.show();
expect(step.isOpen()).toBe(true);
step.hide();
expect(step.isOpen()).toBe(false);
});
Shepherd.js предоставляет методы next(),
back(), complete() и события
show, hide, complete, которые
позволяют имитировать пользовательское взаимодействие:
test('Переход между шагами', () => {
tour.start();
expect(tour.currentStep.id).toBe('step1');
tour.next();
expect(tour.currentStep.id).toBe('step2');
tour.back();
expect(tour.currentStep.id).toBe('step1');
});
События можно подписывать через .on() и проверять, были
ли они вызваны:
test('События шагов', () => {
const showHandler = jest.fn();
const hideHandler = jest.fn();
const step = tour.getById('step1');
step.on('show', showHandler);
step.on('hide', hideHandler);
step.show();
expect(showHandler).toHaveBeenCalled();
step.hide();
expect(hideHandler).toHaveBeenCalled();
});
Для unit-тестов часто используется jsdom для
эмуляции DOM. Если шаг привязан к элементу, которого нет в DOM, он не
сможет отобразиться. Также можно мокировать методы
scrollIntoView или другие действия браузера:
Element.prototype.scrollIntoView = jest.fn();
Это гарантирует, что тесты не будут падать из-за отсутствия браузерной реализации.
Shepherd.js позволяет задавать уникальные свойства для каждого шага: кнопки, классы, условия перехода. Все эти элементы можно проверять:
tour.addStep({
id: 'step3',
text: 'Шаг с кнопкой',
buttons: [
{
text: 'Далее',
action: tour.next
}
]
});
test('Кнопка шага вызывает переход', () => {
const step = tour.getById('step3');
const nextSpy = jest.spyOn(tour, 'next');
step.show();
step.options.buttons[0].action();
expect(nextSpy).toHaveBeenCalled();
});
Метод complete() должен корректно завершать тур,
закрывать шаги и вызывать событие complete. В тестах это
можно проверять через мок-функции:
test('Завершение тура', () => {
const completeHandler = jest.fn();
tour.on('complete', completeHandler);
tour.start();
tour.complete();
expect(completeHandler).toHaveBeenCalled();
expect(tour.steps.every(step => !step.isOpen())).toBe(true);
});
Shepherd.js позволяет создавать несколько туров одновременно. В unit-тестах важно убедиться, что каждый тур работает изолированно и шаги одного тура не пересекаются с другим:
const tourA = new Shepherd.Tour({ useModalOverlay: true });
const tourB = new Shepherd.Tour({ useModalOverlay: true });
tourA.addStep({ id: 'a1', text: 'Тур A' });
tourB.addStep({ id: 'b1', text: 'Тур B' });
tourA.start();
expect(tourA.currentStep.id).toBe('a1');
expect(tourB.currentStep).toBeNull();
tourB.start();
expect(tourB.currentStep.id).toBe('b1');
Snapshot-тесты позволяют проверять, что структура DOM шага соответствует ожиданиям. Особенно полезно для сложных шагов с кастомными кнопками или контентом:
import { render } from '@testing-library/react';
test('Snapshot шага', () => {
tour.start();
const step = tour.getById('step1');
const { container } = render(step.el);
expect(container).toMatchSnapshot();
});
Snapshot фиксирует HTML и CSS шагов, предотвращая непреднамеренные изменения внешнего вида туров.
Такой подход к unit-тестированию Shepherd.js позволяет полностью покрыть рендеринг шагов, навигацию, пользовательские события и завершение тура, обеспечивая стабильность интерактивных инструкций и упрощая сопровождение кода при изменении интерфейса.