При тестировании компонентов Vue часто возникает необходимость проверять обработку ошибок при выполнении асинхронных запросов. Vue Test Utils предоставляет инструменты для эмуляции поведения компонентов в условиях, когда запросы к API завершаются с ошибкой. Основная цель таких тестов — убедиться, что компонент корректно реагирует на неудачные запросы, отображает сообщения об ошибке и не ломает пользовательский интерфейс.
jest.mockДля симуляции ошибок чаще всего используется мокирование модулей,
отвечающих за сетевые запросы. Например, если используется
axios, можно создать мок:
import axios from 'axios';
import { mount } from '@vue/test-utils';
import MyComponent from '@/components/MyComponent.vue';
jest.mock('axios');
test('отображает сообщение об ошибке при неудачном запросе', async () => {
axios.get.mockRejectedValue(new Error('Network Error'));
const wrapper = mount(MyComponent);
await wrapper.vm.fetchData();
expect(wrapper.text()).toContain('Ошибка загрузки данных');
});
В этом примере ключевой момент — использование
mockRejectedValue, которое позволяет имитировать отклонение
промиса и протестировать обработку ошибок внутри компонента.
После возникновения ошибки важно убедиться, что компонент находится в ожидаемом состоянии. Для этого проверяется:
expect(wrapper.vm.isLoading).toBe(false);
expect(wrapper.find('.error-message').exists()).toBe(true);
Если компонент использует уведомления, такие как Toast
или Snackbar, их также нужно проверять. Для этого можно
мокировать соответствующий модуль или метод:
jest.mock('@/plugins/toast', () => ({
showError: jest.fn(),
}));
import { showError } from '@/plugins/toast';
test('вызывает уведомление при ошибке', async () => {
axios.get.mockRejectedValue(new Error('API Error'));
const wrapper = mount(MyComponent);
await wrapper.vm.fetchData();
expect(showError).toHaveBeenCalledWith('Не удалось загрузить данные');
});
watch и computedОшибки могут возникать не только при прямых вызовах API, но и внутри
реактивных вычислений, завязанных на watch или
computed. В таких случаях тест должен имитировать изменение
данных и проверять обработку исключений:
test('обрабатывает ошибку при изменении свойства', async () => {
const wrapper = mount(MyComponent);
wrapper.setProps({ userId: 123 });
await wrapper.vm.$nextTick();
expect(wrapper.find('.error-message').text()).toBe('Ошибка при загрузке пользователя');
});
flushPromises для корректного ожидания ошибокПоскольку ошибки часто возникают асинхронно, стандартного
await wrapper.vm.method() может быть недостаточно. Для
гарантированного завершения всех промисов используют утилиту
flush-promises:
import flushPromises from 'flush-promises';
axios.get.mockRejectedValue(new Error('Server Error'));
const wrapper = mount(MyComponent);
wrapper.vm.fetchData();
await flushPromises();
expect(wrapper.find('.error-message').exists()).toBe(true);
Это позволяет тесту корректно дождаться обработки всех асинхронных операций, прежде чем проверять DOM.
Рекомендуется выносить обработку ошибок в отдельные методы или composables. Это упрощает тестирование, поскольку можно проверять логику отдельно от визуальной части:
test('метод handleError устанавливает сообщение и сбрасывает загрузку', () => {
const wrapper = mount(MyComponent);
wrapper.vm.handleError(new Error('Fail'));
expect(wrapper.vm.error).toBe('Fail');
expect(wrapper.vm.isLoading).toBe(false);
});
Такой подход повышает стабильность тестов и позволяет легко симулировать различные сценарии ошибок.
В сложных компонентах ошибки могут возникать одновременно в нескольких местах: при загрузке данных, отправке форм или подписке на веб-сокеты. В этих случаях тест должен имитировать все источники ошибок и проверять, что состояние компонента остаётся предсказуемым.
axios.get.mockRejectedValueOnce(new Error('Load Error'));
axios.post.mockRejectedValueOnce(new Error('Submit Error'));
const wrapper = mount(MyComponent);
await wrapper.vm.fetchData();
await wrapper.vm.submitForm();
expect(wrapper.vm.error).toContain('Load Error');
expect(wrapper.vm.error).toContain('Submit Error');
Такой подход обеспечивает полное покрытие сценариев, когда один и тот же компонент может столкнуться с множественными сбоями одновременно.
Ключ к надёжному тестированию ошибок — тщательная эмуляция всех
асинхронных действий и проверка реакции компонента на каждый сценарий.
Использование моков, flush-promises, изолированных методов
обработки ошибок и проверка состояния UI обеспечивает стабильные и
предсказуемые тесты даже в сложных компонентах Vue.