Stimulus — это JavaScript-фреймворк, ориентированный на минимальное вмешательство в HTML-разметку и расширение возможностей браузера через controllers. Тестирование компонентов Stimulus требует особого подхода, так как поведение контроллеров напрямую связано с DOM.
Интеграционные тесты в контексте Stimulus проверяют взаимодействие контроллера с элементами DOM, события и реакции на изменения атрибутов. Они не ограничиваются единичными методами, а охватывают цепочку действий: от инициализации контроллера до обновления состояния интерфейса.
Для тестирования контроллеров Stimulus обычно используют Jest или Mocha вместе с библиотеками для работы с DOM, например jsdom. Важной задачей является создание тестового HTML, который максимально повторяет структуру настоящей страницы.
Пример базового окружения:
import { Application } from "@hotwired/stimulus"
import ExampleController from "../controllers/example_controller"
document.body.innerHTML = `
<div data-controller="example" data-example-value="42">
<button data-action="click->example#doSomething">Click me</button>
<span data-example-target="output"></span>
</div>
`;
const application = Application.start()
application.register("example", ExampleController)
Ключевые моменты:
data-controller связывает элемент с контроллером.data-action определяет, какое событие вызовет метод
контроллера.data-*-target задаёт точки привязки для манипуляций
DOM.После регистрации контроллера в приложении Stimulus, важно убедиться, что контроллер корректно инициализируется:
test("Controller initializes with correct value", () => {
const controllerElement = document.querySelector("[data-controller='example']")
const controller = controllerElement.controller // доступ к контроллеру через объект Stimulus
expect(controller.value).toBe("42")
expect(controller.outputTarget.textContent).toBe("")
})
Выделенные моменты:
data-*-value автоматически доступны через
свойства контроллера.Stimulus активно использует actions, поэтому важной частью интеграционного теста является эмуляция событий:
test("Click triggers doSomething method", () => {
const button = document.querySelector("button")
const output = document.querySelector("[data-example-target='output']")
button.click()
expect(output.textContent).toBe("Action performed")
})
Особенности:
.click() для имитации
пользовательского действия.Stimulus позволяет реагировать на изменение атрибутов через
MutationObserver или value observers. Проверка
таких реакций требует модификации атрибутов и ожидания обновления
состояния:
test("Value change updates output", () => {
const controllerElement = document.querySelector("[data-controller='example']")
controllerElement.setAttribute("data-example-value", "100")
const controller = controllerElement.controller
controller.refresh() // вручную вызываем observer, если используется Jest с jsdom
expect(controller.outputTarget.textContent).toBe("Value updated to 100")
})
MutationObserver в jsdom может не срабатывать
автоматически, поэтому часто требуется вручную инициировать
обновление.Для интеграционных тестов важно создавать функции для повторного создания DOM и инициализации приложений Stimulus:
function setupController(html, controllerClass) {
document.body.innerHTML = html
const application = Application.start()
application.register("example", controllerClass)
return document.querySelector("[data-controller='example']").controller
}
Преимущества:
setTimeout или fetch, применять
await и jest.runAllTimers().focus, hover) нужно симулировать
вручную.MutationObserver в Jest часто требует принудительного
вызова observe() или использования
MutationObserver.mock.getBoundingClientRect), необходимо создавать моки, чтобы
контроллер получал корректные значения.Интеграционные тесты Stimulus строятся вокруг инициализации контроллера, эмуляции событий DOM и проверки target’ов и значений. Они демонстрируют реальное поведение интерфейса и позволяют выявлять ошибки в связке JavaScript и HTML. Стратегически важно поддерживать чистоту DOM, переиспользуемость HTML-шаблонов и корректное управление асинхронными процессами.