Моки и стабы

Unpoly — это JavaScript-фреймворк, предназначенный для упрощения работы с частичным обновлением страниц без полной перезагрузки. При тестировании приложений, использующих Unpoly, важно умение изолировать части интерфейса, которые зависят от внешних источников данных, чтобы тесты были быстрыми, предсказуемыми и независимыми. Для этого применяются моки и стабы.

Основные понятия

Мок (mock) — это объект или функция, имитирующая поведение реального компонента или API. Моки используются для проверки того, как компонент взаимодействует с внешними вызовами, например, отправку AJAX-запросов или вызовы методов другого модуля.

Стаб (stub) — это более простая имитация, которая возвращает заранее определённые данные без сложной логики. Стабы нужны, чтобы контролировать данные, которые возвращаются из внешнего источника, не проверяя сами вызовы.

В контексте Unpoly эти подходы особенно полезны для:

  • Изоляции фрагментов страницы при тестировании;
  • Симуляции серверного ответа без реального обращения к API;
  • Проверки поведения интерфейса при различных сценариях ответа сервера.

Подключение Unpoly к тестовой среде

Для тестов часто используют Jest, Jasmine или Mocha. Unpoly имеет встроенные методы для AJAX-запросов, которые можно перехватывать и заменять моками. Основной метод — это up.ajax, который возвращает промис. Его можно заменить мок-функцией:

jest.spyOn(up, 'ajax').mockImplementation((options) => {
  return Promise.resolve({
    status: 200,
    text: '<div class="mocked-content">Тестовый контент</div>'
  });
});

В этом примере каждый вызов up.ajax в тестах будет возвращать заранее определённый HTML, имитируя успешный серверный ответ.

Создание стаба для конкретного фрагмента

Иногда важно тестировать не весь AJAX, а только обновление конкретного элемента. Для этого используют селекторы Unpoly и методы up.render с переданными данными:

const stubContent = '<div id="user-list"><p>Пользователь 1</p></div>';

up.render('#user-list', stubContent);

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

Моки с проверкой вызовов

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

const ajaxMock = jest.spyOn(up, 'ajax').mockImplementation((options) => {
  expect(options.url).toBe('/api/users');
  expect(options.method).toBe('GET');
  return Promise.resolve({ status: 200, text: '<div>OK</div>' });
});

В этом случае тест не только подставляет данные, но и подтверждает правильность использования API.

Использование глобальных стаба и моков

Для крупных приложений удобно создавать отдельный модуль mocks.js, где хранятся все стабы и моки:

export const ajaxMocks = {
  usersList: () => Promise.resolve({
    status: 200,
    text: '<div id="user-list"><p>Пользователь A</p></div>'
  }),
  userDetail: (id) => Promise.resolve({
    status: 200,
    text: `<div id="user-detail">Пользователь ${id}</div>`
  })
};

Подключение к тестам через jest.spyOn(up, 'ajax').mockImplementation(...) позволяет централизованно управлять имитациями и легко менять данные.

Асинхронные сценарии и ошибки

Unpoly активно использует промисы и события для обновления интерфейса. Для тестирования ошибок можно мокировать отказ сервера:

jest.spyOn(up, 'ajax').mockImplementation(() => {
  return Promise.reject({ status: 500, text: 'Ошибка сервера' });
});

После этого можно проверять корректное отображение сообщений об ошибке или fallback-контента.

Практика: комбинация моков и стаба

  • Стаб подставляет нужный HTML или JSON для интерфейса.
  • Мок проверяет, что запрос был выполнен корректно, и возвращает результат.
  • Комбинация позволяет тестировать и логику взаимодействия, и визуальное обновление фрагментов страницы без реального сервера.
jest.spyOn(up, 'ajax').mockImplementation((options) => {
  if (options.url === '/api/users') {
    return Promise.resolve({ status: 200, text: '<div>Список пользователей</div>' });
  } else {
    return Promise.reject({ status: 404 });
  }
});

События Unpoly и тестирование

Unpoly генерирует события при рендеринге (up:fragment:loaded, up:fragment:rendered) и при ошибках (up:ajax:error). Моки и стабы позволяют тестировать реакции на эти события:

document.addEventListener('up:fragment:loaded', (event) => {
  expect(event.target.id).toBe('user-list');
});

Итоговые рекомендации

  • Использовать моки для контроля поведения вызовов AJAX;
  • Применять стабы для подстановки конкретного HTML или JSON;
  • Централизовать моки и стабы для удобного повторного использования;
  • Проверять события Unpoly через перехват DOM-событий;
  • Тестировать как успешные, так и ошибочные сценарии.

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