Механизмы provide и inject в Vue используются для передачи данных между компонентами без необходимости передавать их через props на каждом уровне. В контексте тестирования это особенно важно, так как позволяет имитировать контексты зависимостей и проверять поведение компонентов, зависящих от внешних сервисов, настроек или состояния.
В Vue компонент может объявлять значения через provide,
а дочерние компоненты могут получать эти значения с помощью
inject. Пример синтаксиса:
// Родительский компонент
export default {
provide() {
return {
apiService: this.apiService
};
},
data() {
return {
apiService: { fetchData: () => 'данные' }
};
}
}
// Дочерний компонент
export default {
inject: ['apiService'],
mounted() {
console.log(this.apiService.fetchData()); // 'данные'
}
}
В тестах важно уметь подменять эти зависимости, чтобы компонент тестировался в изоляции.
Vue Test Utils позволяет передавать provide через опцию
global.provide при монтировании компонента с помощью
mount или shallowMount.
import { mount } from '@vue/test-utils';
import ChildComponent from '@/components/ChildComponent.vue';
const mockApiService = {
fetchData: jest.fn(() => 'тестовые данные')
};
const wrapper = mount(ChildComponent, {
global: {
provide: {
apiService: mockApiService
}
}
});
expect(wrapper.vm.apiService.fetchData()).toBe('тестовые данные');
expect(mockApiService.fetchData).toHaveBeenCalled();
Ключевые моменты:
global.provide.В большинстве случаев provide используется для сервисов, методов или реактивных состояний. В тестах часто требуется проверять, что функция была вызвана с правильными аргументами.
const mockFunction = jest.fn();
const wrapper = mount(ChildComponent, {
global: {
provide: {
doSomething: mockFunction
}
}
});
wrapper.find('button').trigger('click');
expect(mockFunction).toHaveBeenCalledTimes(1);
Особенность: даже если provide содержит функцию, Vue Test Utils корректно сохраняет контекст и позволяет работать с реактивными или обычными функциями.
Vue 3 позволяет передавать реактивные объекты через
provide, используя reactive или ref. В тестах
это дает возможность проверять реактивность компонентов.
import { reactive } from 'vue';
import { mount } from '@vue/test-utils';
import ChildComponent from '@/components/ChildComponent.vue';
const state = reactive({ count: 0 });
const wrapper = mount(ChildComponent, {
global: {
provide: {
counterState: state
}
}
});
expect(wrapper.text()).toContain('0');
state.count++;
await wrapper.vm.$nextTick();
expect(wrapper.text()).toContain('1');
Выводы по реактивному provide:
Если компонент находится глубоко в дереве и зависит от provide верхнего уровня, его можно протестировать без необходимости монтировать всех родителей:
const wrapper = mount(DeepChildComponent, {
global: {
provide: {
userService: {
getUser: () => ({ name: 'Тестовый пользователь' })
}
}
}
});
expect(wrapper.text()).toContain('Тестовый пользователь');
Преимущество:
Часто важно отслеживать вызовы методов, предоставляемых через provide. Jest позволяет создавать моки и шпионы для этих целей:
const mockService = {
fetchData: jest.fn(() => 'ответ')
};
const wrapper = mount(ChildComponent, {
global: {
provide: {
apiService: mockService
}
}
});
wrapper.vm.apiService.fetchData();
expect(mockService.fetchData).toHaveBeenCalledTimes(1);
При использовании shallowMount компоненты-потомки
рендерятся как заглушки, но provide/inject работает корректно. Это дает
возможность тестировать логику дочернего компонента без рендеринга всей
иерархии.
import { shallowMount } from '@vue/test-utils';
const wrapper = shallowMount(ChildComponent, {
global: {
provide: {
value: 42
}
}
});
expect(wrapper.vm.value).toBe(42);
Использование provide и inject в тестах Vue Test Utils позволяет создавать точные, изолированные тесты компонентов, управлять зависимостями и проверять реактивное поведение, не полагаясь на полное дерево компонентов. Это критически важно для построения стабильной и предсказуемой тестовой среды.