Мокирование зависимостей — это изоляция компонентов и модулей от их реальных внешних зависимостей с целью тестирования логики в контролируемых условиях. В контексте Riot.js это особенно важно, так как компоненты тесно связаны с состоянием, событиями, HTTP-запросами и сторонними сервисами. Без моков тесты становятся нестабильными, медленными и зависимыми от внешней среды.
Ключевая идея заключается в замене реальных реализаций зависимостей на предсказуемые подставные объекты, функции или модули, которые полностью контролируются тестом.
В реальных приложениях Riot-компоненты редко существуют изолированно. Наиболее распространённые зависимости:
fetch, axios)Каждый из этих типов требует собственного подхода к мокированию.
Самый простой и часто используемый вариант — подмена функций. В Riot.js логика часто выносится в отдельные модули, которые импортируются в компонент.
// api.js
export function loadUsers() {
return fetch('/api/users').then(r => r.json())
}
В компоненте:
import { loadUsers } FROM './api'
export default {
async onMounted() {
this.users = await loadUsers()
}
}
Для тестирования такой компонент должен получать управляемую версию
loadUsers. Это достигается через мокирование модуля на
уровне тестовой среды.
Пример с использованием Jest:
jest.mock('./api', () => ({
loadUsers: jest.fn()
}))
После этого поведение зависимости задаётся явно:
import { loadUsers } from './api'
loadUsers.mockResolvedValue([
{ id: 1, name: 'Alice' }
])
Компонент работает с подставными данными, не выполняя реальных HTTP-запросов.
Асинхронность в Riot.js встречается повсеместно: загрузка данных, debounce, таймеры. Для управления временем используются поддельные таймеры.
jest.useFakeTimers()
Пример логики в компоненте:
this.timeoutId = setTimeout(() => {
this.visible = true
}, 1000)
В тесте:
jest.advanceTimersByTime(1000)
Это позволяет проверить состояние компонента без ожидания реального времени, что критично для быстрых и детерминированных тестов.
Riot.js не навязывает конкретный state manager, поэтому часто используется собственная реализация или простой event bus.
// bus.js
import mitt from 'mitt'
export const bus = mitt()
Компоненты подписываются на события:
bus.on('login', user => {
this.user = user
})
В тестах реальный bus заменяется на мок:
jest.mock('./bus', () => ({
bus: {
on: jest.fn(),
emit: jest.fn()
}
}))
Это позволяет:
Компоненты Riot.js взаимодействуют с DOM напрямую или через
this.root. В тестовой среде (например, jsdom) доступны
базовые DOM API, но некоторые возможности требуют мокирования:
localStorageIntersectionObserverResizeObservermatchMediaПример мокирования localStorage:
Object.defineProperty(window, 'localStorage', {
value: {
getItem: jest.fn(),
setItem: jest.fn()
}
})
Такой подход позволяет тестировать логику сохранения состояния без реального хранилища.
Жёсткие импорты усложняют тестирование. Более гибкий подход — передача зависимостей через параметры или опции компонента.
export default function createComponent(api) {
return {
async onMounted() {
this.data = await api.load()
}
}
}
В тесте:
const apiMock = {
load: jest.fn().mockResolvedValue([1, 2, 3])
}
const component = createComponent(apiMock)
Такой подход:
При тестировании контейнерных компонентов часто нет необходимости рендерить реальных потомков. Их можно заменить заглушками.
const ChildStub = {
template: '<div></div>'
}
Это позволяет сосредоточиться на логике родительского компонента, не затрагивая внутреннее устройство дочерних.
Мокирование бесполезно без проверки факта использования зависимости. Основные проверки:
Пример:
expect(loadUsers).toHaveBeenCalledTimes(1)
expect(loadUsers).toHaveBeenCalledWith({ LIMIT: 10 })
Такие проверки подтверждают корректность интеграции компонента с внешней логикой.
Избыточное мокирование Подмена слишком большого количества зависимостей приводит к тестированию искусственной системы, не имеющей связи с реальным кодом.
Мокирование внутренней логики Не следует мокировать функции, которые являются частью тестируемого поведения.
Зависимость тестов от реализации Тесты не должны знать, как именно компонент реализует логику, а только что он делает.
Грамотно выстроенное мокирование:
В экосистеме Riot.js, где разработчик сам определяет структуру приложения, мокирование становится не просто техникой тестирования, а инструментом проектирования и контроля сложности.