В Vue.js компоненты часто содержат методы, изменяющие состояние приложения или взаимодействующие с внешними сервисами. В контексте тестирования такие методы требуют особого внимания, поскольку их побочные эффекты могут влиять на результат тестов. Vue Test Utils предоставляет инструменты для точного контроля и изоляции таких методов.
Побочным эффектом считается любое действие метода, которое выходит за пределы его локального состояния. К типичным примерам относятся:
data или props компонента.$emit или глобальные
события.setTimeout,
setInterval) или асинхронных операций.Для тестирования важно отделять чистую логику от действий с побочными эффектами и обеспечивать возможность их мокирования.
Vue Test Utils позволяет контролировать внутреннее состояние
компонента через wrapper.vm. Пример метода с побочным
эффектом:
export default {
data() {
return { count: 0 };
},
methods: {
increment() {
this.count += 1;
}
}
}
Тестирование изменения состояния выполняется напрямую:
import { mount } from '@vue/test-utils';
import Counter from './Counter.vue';
test('increment увеличивает count', () => {
const wrapper = mount(Counter);
wrapper.vm.increment();
expect(wrapper.vm.count).toBe(1);
});
Ключевой момент: использование wrapper.vm позволяет
обращаться к экземпляру компонента и проверять значения
data без необходимости рендерить DOM.
$emitМетоды, вызывающие события, часто используются для уведомления родителя о состоянии компонента:
methods: {
submitForm() {
this.$emit('submit', { valid: true });
}
}
Тестирование:
test('submitForm вызывает событие submit', () => {
const wrapper = mount(MyForm);
wrapper.vm.submitForm();
expect(wrapper.emitted('submit')).toBeTruthy();
expect(wrapper.emitted('submit')[0]).toEqual([{ valid: true }]);
});
Vue Test Utils сохраняет историю вызовов событий, что позволяет проверять аргументы и количество вызовов.
Методы с сетевыми запросами или обращением к внешним сервисам требуют мокирования, чтобы тесты оставались детерминированными:
methods: {
async fetchData() {
const response = await this.$api.getData();
this.items = response.data;
}
}
Тестирование с моками:
test('fetchData обновляет items', async () => {
const mockData = { data: [1, 2, 3] };
const wrapper = mount(MyComponent, {
global: {
mocks: {
$api: {
getData: jest.fn().mockResolvedValue(mockData)
}
}
}
});
await wrapper.vm.fetchData();
expect(wrapper.vm.items).toEqual([1, 2, 3]);
expect(wrapper.vm.$api.getData).toHaveBeenCalled();
});
Использование global.mocks позволяет заменять глобальные
зависимости и отслеживать их вызовы, не затрагивая реальные сервисы.
Асинхронные методы часто комбинируют побочные эффекты с обновлением состояния. Важно правильно ожидать завершение промисов или рендеринг:
methods: {
async delayedIncrement() {
await new Promise(resolve => setTimeout(resolve, 100));
this.count += 1;
}
}
Тестирование:
test('delayedIncrement увеличивает count асинхронно', async () => {
jest.useFakeTimers();
const wrapper = mount(Counter);
wrapper.vm.delayedIncrement();
jest.advanceTimersByTime(100);
await wrapper.vm.$nextTick();
expect(wrapper.vm.count).toBe(1);
jest.useRealTimers();
});
Использование таймеров и $nextTick() гарантирует, что
побочные эффекты завершились до проверки состояния.
Методы, вызываемые в хуках жизненного цикла (mounted,
created), требуют отдельного подхода. Vue Test Utils
позволяет изолировать вызовы через shallowMount и
мокирование зависимостей:
mounted() {
this.loadInitialData();
}
Тестирование с моками:
test('loadInitialData вызывается при монтировании', () => {
const loadSpy = jest.fn();
shallowMount(MyComponent, {
methods: { loadInitialData: loadSpy }
});
expect(loadSpy).toHaveBeenCalled();
});
shallowMount предотвращает рендеринг дочерних
компонентов, что снижает влияние побочных эффектов и ускоряет тесты.
Для удобства тестирования методы с побочными эффектами лучше разделять на:
data, вызывающие $emit или API.Это позволяет тестировать чистую логику отдельно и мокировать побочные эффекты в интеграционных сценариях.
Методы с побочными эффектами в Vue требуют внимательного подхода:
использование wrapper.vm, $emit, глобальных
моков и контроля асинхронности позволяет изолировать и проверять каждое
действие, сохраняя тесты надежными и предсказуемыми.