Its currently very difficult to test composition api based components. Certainly simple components work, but more complex components have multiple issues. For example the provide/inject pattern as recommended in the @vue/composition-api docs, i.e.:
import { InjectionKey, inject, provide } from '@vue/composition-api'
import VueI18n from 'vue-i18n'
const i18nKey: InjectionKey<VueI18n> = Symbol('i18n')
export function provideI18N(i18n: VueI18n): void {
provide(i18nKey, i18n)
}
export function useI18N(): VueI18n {
return inject(i18nKey) as VueI18n
}
The provide function is used in a parent component, and the inject function is called in the setup function of the component that is to be tested.
Try to pass the provide function as part of the provide key of shallowMount or mount, i.e.
shallowMount(component, {
provide: { i18n: () => provideI18n(i18n) }
})
This does not work - you will encounter
[vue-composition-api] "provide" get called outside of "setup()"
or
Injection "Symbol(i18n)" not found
The solution would be to allow passing a custom setup function when mounting/shallowMounting, inside which the provide function can be called. This function can return mocked versions of the SetupContext object automatically, or allow custom overrides. Additionally it can allow for providing using the provide function, and passing spies in using the provide function.
mount(component, {
setup() {
....
return { attrs, root, parent, refs .... }
}})
Overriding setup may work (have not tried), however this will not work in Vue 3 - I don't think you can override setup (or any lifecycle hooks, for that matter). Overriding setup doesn't sound ideal to me either - that's a pretty important thing to test, does it make sense to stub it out? Composition API functions will have the majority of the code in setup.
What you are describing sounds like a bug with the provide mounting option - wouldn't it be better to just fix the provide mounting option to work correctly? Would that solve your problem?
Since the composition API is very new, there are likely a lot of bugs related to it and the usage with @vue/composition-api. We should fix these! Composition API is awesome.
Since the composition API is very new, there are likely a lot of bugs related to it and the usage with @vue/composition-api. We should fix these!
Should we tag them differently, so we can easily spot what bugs are compositionAPI-related? That would give us a hint when triaging them.
@lmiller1990 i wasn't suggesting overriding setup for the component being mounted, i suggested adding a setup function that wraps the component, "AS IF" it was mounted inside a root component that has provide functions etc.
@Goldziher right, I misunderstood. Yes, I think that is a good idea, that is more or less what I was thinking we should do to support provide. I wonder how provide knows if it is called in a setup function... 🤔
I once helped someone make a helper like function to test composable functions.
It was basically wrapping an empty Vue component for them, and injecting that function into it's setup.
If I remember it was used sort of like this:
import useStuff from './composables/useStuff'
const setupWrapper = createSetupWrapper(function setup(context){
const state = useStuff(context)
return state
})
const wrapper = mount(setupWrapper)
expect(wrapper.state).toBe('something')
We do have a test for composition API provides:
itDoNotRunIf(
!injectSupported,
'injects in a composition api component',
() => {
const localVue = createLocalVue()
localVue.use(VueCompositionApi)
const wrapper = mountingMethod(CompositionComponentWithInject, {
provide: { fromMount: '_' },
localVue
})
expect(wrapper.html()).to.contain('_')
}
)
<template>
<div>{{ fromMount }}</div>
</template>
<script>
import { createComponent, inject, ref } from '@vue/composition-api'
export default createComponent({
name: 'component-with-inject-composition',
setup: () => {
const fromMount = inject('fromMount')
const setInSetup = ref('created')
return {
fromMount,
setInSetup
}
}
})
</script>
Maybe you need to pass the symbol:
const i18nKey: InjectionKey<VueI18n> = Symbol('i18n')
mount(component, {
provide: { [i18nKey]: () => provideI18n(i18n) }
})
I'll test
Any luck?
This is working fine for me. Please post if you are still having a problem. I'll close it for now.
Is provide no longer a mounting option for vue-test-utils? i receive an error anytime i try and mount a component with provided data
it('should render', () => {
const wrapper = shallowMount(Modal, {
provide: {
keyState: ''
}
});
expect(wrapper.exists()).toBe(true);
});
Provide is still a thing. What error are you getting? Is ^ enough to reproduce?
I am not sure we have any tests around composition API + provide, just a few small tests. It's possible there is a bug in Composition API plugin + VTU.
If so, can you please open a new issue with info about it (you could tag me, too).