Composables представляют собой функции, использующие Composition API для инкапсуляции реактивной логики и повторного её использования между компонентами. Тестирование composables отличается от тестирования компонентов, так как нет необходимости рендерить DOM, но важно правильно обрабатывать реактивность, эффекты и взаимодействие с другими composables или API.
Для тестирования composables используются:
ref, reactive,
computed) — для работы с реактивностью.Пример установки через npm:
npm install @vue/test-utils @vue/reactivity vitest
Типичный composable может выглядеть так:
import { ref, computed } from 'vue';
export function useCounter(initialValue = 0) {
const count = ref(initialValue);
const increment = () => {
count.value += 1;
};
const decrement = () => {
count.value -= 1;
};
const double = computed(() => count.value * 2);
return { count, increment, decrement, double };
}
Главные элементы, на которые обращаем внимание при тестировании:
ref,
reactive)computed)Vue Test Utils предоставляет возможность рендерить composables
напрямую через mount компонента-обертки или через
специализированные хелперы.
Простейший способ — создать минимальный компонент для использования composable:
import { mount } from '@vue/test-utils';
import { useCounter } from '@/composables/useCounter';
import { defineComponent } from 'vue';
const TestComponent = defineComponent({
setup() {
return useCounter();
},
template: `<div></div>`,
});
Теперь можно тестировать функциональность composable через экземпляр компонента:
test('increment увеличивает count', () => {
const wrapper = mount(TestComponent);
const { count, increment } = wrapper.vm;
expect(count).toBe(0);
increment();
expect(count).toBe(1);
});
setup() напрямуюДля упрощенного тестирования без рендера можно использовать функции
типа renderComposable из сторонних библиотек (например,
@vue/test-utils не имеет встроенной функции
renderComposable, но можно реализовать обертку через
mount), либо писать собственные утилиты:
import { reactive, nextTick } from 'vue';
function renderComposable(callback) {
let state;
const TestComponent = defineComponent({
setup() {
state = callback();
return state;
},
template: '<div></div>'
});
mount(TestComponent);
return state;
}
Пример использования:
const { count, increment } = renderComposable(() => useCounter(5));
expect(count.value).toBe(5);
increment();
expect(count.value).toBe(6);
Важно учитывать, что computed свойства автоматически отслеживают изменения зависимостей, поэтому при тестировании необходимо обновлять реактивные данные и проверять правильность вычислений:
test('computed double корректно обновляется', async () => {
const { count, increment, double } = renderComposable(() => useCounter(2));
expect(double.value).toBe(4);
increment();
await nextTick();
expect(double.value).toBe(6);
});
Использование nextTick() гарантирует, что Vue обработает
реактивные обновления перед проверкой результата.
Если composable использует watch или
watchEffect, необходимо правильно мокировать функции и
проверять вызовы:
import { watch } from 'vue';
function useWatcherDemo() {
const count = ref(0);
const spy = jest.fn();
watch(count, spy);
const increment = () => count.value++;
return { count, increment, spy };
}
test('watch срабатывает при изменении count', async () => {
const { count, increment, spy } = renderComposable(() => useWatcherDemo());
increment();
await nextTick();
expect(spy).toHaveBeenCalledWith(1, 0);
});
Composables часто используют внешние API или другие composables. Для тестов рекомендуется мокировать зависимости, чтобы тест был изолированным и детерминированным:
jest.mock('@/composables/useApi', () => ({
useApi: () => ({
fetchData: jest.fn().mockResolvedValue('mocked data')
})
}));
После этого можно тестировать composable без фактического вызова сетевых запросов.
nextTick() или
await wrapper.vm.$nextTick() при проверке реактивных
обновлений.Тестирование composables требует внимания к реактивности, правильного обращения с computed и watchers, а также грамотного мокирования внешних зависимостей. Благодаря чистой функции setup и отсутствию необходимости рендерить сложный DOM, тесты composables могут быть легкими, быстрыми и точными. Это обеспечивает уверенность в корректности бизнес-логики и повторяемости поведения Vue-приложения.