В современных приложениях Vue взаимодействие с сервером часто осуществляется через fetch API. Тестирование таких компонентов требует особого подхода, так как напрямую обращаться к реальному API в юнит-тестах нежелательно. Основная цель — изолировать компонент и проверять его поведение в ответ на разные сценарии запросов.
Для начала используется функция mount из Vue Test
Utils:
import { mount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'
const wrapper = mount(MyComponent)
Если компонент делает запрос к серверу при монтировании, важно
замокать fetch. Обычно это делается через
jest:
global.fetch = jest.fn()
Это позволяет полностью контролировать поведение fetch без реальных сетевых вызовов.
Чтобы протестировать успешный сценарий получения данных:
const mockData = { id: 1, name: 'Test Item' }
global.fetch.mockResolvedValueOnce({
ok: true,
json: async () => mockData
})
await wrapper.vm.loadData() // метод, который вызывает fetch
await wrapper.vm.$nextTick()
expect(wrapper.vm.item).toEqual(mockData)
expect(wrapper.find('.item-name').text()).toBe('Test Item')
Ключевые моменты:
mockResolvedValueOnce позволяет задать конкретный ответ
для одного вызова fetch.await wrapper.vm.$nextTick() необходим для
ожидания реактивного обновления DOM после изменения состояния
компонента.wrapper.vm.item) и
отображения в шаблоне (.item-name) гарантирует правильную
интеграцию данных.Обработка ошибок сервера или сетевых сбоев также должна тестироваться:
global.fetch.mockRejectedValueOnce(new Error('Network Error'))
await wrapper.vm.loadData()
await wrapper.vm.$nextTick()
expect(wrapper.vm.error).toBe('Network Error')
expect(wrapper.find('.error-message').exists()).toBe(true)
Особое внимание уделяется:
fetch.Если компонент делает несколько последовательных запросов,
jest позволяет задать их ответы по очереди:
global.fetch
.mockResolvedValueOnce({ ok: true, json: async () => ({ id: 1 }) })
.mockResolvedValueOnce({ ok: true, json: async () => ({ id: 2 }) })
await wrapper.vm.loadAllData()
await wrapper.vm.$nextTick()
expect(wrapper.vm.items).toHaveLength(2)
Это позволяет моделировать сценарии последовательного получения данных без обращения к реальному API.
Иногда в компоненте используются setTimeout или
setInterval для повторных запросов. В тестах нужно
контролировать таймеры через Jest:
jest.useFakeTimers()
wrapper.vm.pollData()
jest.advanceTimersByTime(5000)
await wrapper.vm.$nextTick()
expect(wrapper.vm.data).toBeDefined()
jest.useRealTimers()
Преимущество — тест становится предсказуемым и быстрым, без реального ожидания времени.
Важно убедиться, что fetch вызывается с правильным URL, методами и заголовками:
global.fetch.mockResolvedValueOnce({
ok: true,
json: async () => ({ success: true })
})
await wrapper.vm.sendData({ name: 'Item' })
expect(global.fetch).toHaveBeenCalledWith('/api/items', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Item' })
})
Ключевой момент: тестирование параметров запроса обеспечивает правильную интеграцию компонента с API.
Для крупных проектов удобно создавать отдельные утилиты для моков fetch:
export function mockFetchSuccess(data) {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: async () => data
})
}
export function mockFetchFailure(errorMessage) {
global.fetch = jest.fn().mockRejectedValue(new Error(errorMessage))
}
Это уменьшает повторяемость кода и повышает читаемость тестов.
При тестировании компонентов Vue с fetch API:
await wrapper.vm.$nextTick() для ожидания
обновлений DOM.data,
computed), так и отображение в шаблоне.Такой подход обеспечивает надежные, изолированные и предсказуемые тесты компонентов Vue, работающих с fetch API.