Работа с внешними зависимостями в JavaScript-приложениях часто требует изоляции компонентов для тестирования. Stimulus, как фреймворк для управления поведением пользовательского интерфейса, позволяет легко подключать внешние сервисы, однако для обеспечения надёжных тестов необходимо использовать моки и стабы.
Мок (Mock) — это объект, который имитирует поведение реального компонента или сервиса, но при этом позволяет отслеживать вызовы методов и проверять взаимодействие. Моки полезны для тестирования интеграций, когда важны именно вызовы методов и передаваемые данные.
Стаб (Stub) — это объект, предоставляющий заранее определённые ответы на вызовы функций, но без контроля за частотой или параметрами вызовов. Стабы упрощают тестирование компонентов, которые зависят от внешних данных, но не требуют проверки взаимодействия.
Stimulus строится вокруг контроллеров, каждый из которых управляет поведением определённого элемента DOM. Контроллеры часто взаимодействуют с внешними API, сервисами или библиотеками. Чтобы тестировать контроллеры в изоляции, внешние зависимости заменяются моками или стабами.
Пример стандартной структуры контроллера:
// app/javascript/controllers/notification_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static values = { endpoint: String };
connect() {
this.loadNotifications();
}
async loadNotifications() {
const response = await fetch(this.endpointValue);
const data = await response.json();
this.renderNotifications(data);
}
renderNotifications(notifications) {
this.element.innerHTML = notifications.map(n => `<p>${n.message}</p>`).join('');
}
}
В этом примере fetch является внешней зависимостью. Для
тестирования контроллера без реального запроса к серверу можно
использовать мок или стаб.
fetchСтаб возвращает заранее определённый результат:
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve([{ message: "Test notification" }]),
})
);
Теперь вызов loadNotifications() будет получать
фиктивные данные без обращения к сети. Такой подход позволяет проверять
только логику рендеринга и обработку данных, не полагаясь на реальный
сервер.
Моки позволяют не только подменять функционал, но и контролировать вызовы методов:
const mockFetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve([{ message: "Mocked notification" }]),
})
);
global.fetch = mockFetch;
// В тесте можно проверить, что fetch вызван с правильным URL
await controller.loadNotifications();
expect(mockFetch).toHaveBeenCalledWith(controller.endpointValue);
Это особенно полезно для контроллеров с более сложной логикой, где важен порядок и параметры вызовов внешних сервисов.
Stimulus-контроллеры часто используют:
Локальное хранилище (localStorage /
sessionStorage) Для тестирования можно создать простые объекты
с методами getItem, setItem и
removeItem, которые имитируют стандартное
поведение.
События и кастомные события Мок-объект для
события может проверять, был ли вызван метод dispatchEvent
и с какими данными.
Сторонние библиотеки UI или анимации Вместо подключения реальной библиотеки используется стаб, который не выполняет анимации, но возвращает ожидаемые данные.
Jest предоставляет удобные возможности для создания моков и стабов:
jest.fn() — создание функции-заглушки, отслеживающей
вызовы.jest.mock('module') — автоматическая подмена модуля
мок-версией.jest.spyOn(object, 'method') — создание шпиона,
позволяющего контролировать и подменять вызовы метода.Пример мокирования внешнего сервиса в Stimulus:
import NotificationController from "./notification_controller";
jest.mock("./notification_service", () => ({
fetchNotifications: jest.fn(() => Promise.resolve([{ message: "Mocked" }])),
}));
test("контроллер рендерит уведомления", async () => {
document.body.innerHTML = `<div data-controller="notification" data-notification-endpoint-value="/api/notifications"></div>`;
const element = document.querySelector("[data-controller='notification']");
const controller = new NotificationController(element);
await controller.loadNotifications();
expect(element.innerHTML).toContain("Mocked");
});
Моки и стабы обеспечивают надёжное тестирование Stimulus-контроллеров, повышают стабильность тестов и позволяют разрабатывать UI независимо от состояния серверов и сторонних библиотек. Этот подход критически важен для поддержания качественной архитектуры фронтенд-приложений и ускоряет процесс разработки.