1.0.0-beta.32
https://github.com/sduduzog/vue-composition-api-tsx-example
npm run test:unitThe component "HelloWorld" should be properly mounted.
The component doesn't mount with the following error:
Failed to mount component: template or render function not defined.
This is actually a cross-post from https://github.com/vuejs/composition-api/issues/151. I鈥檓 looking for help to resolve this issue where render functions returned from the composition api setup functions are not properly set while mounted through vue-test-utils.
At this point I鈥檓 wondering if vue-test-utils is the problem here or if it鈥檚 totally unrelated. And if it is, I would appreciate some guidance about where to look next to debug it.
I can't even get returning a render function from setup to work in a regular app. Is this even supported? It doesn't say it is here: https://github.com/vuejs/composition-api
I'll try pulling that repo. We should repro without TS; the less dependencies, the better.
Edit: I cloned that repo and ran yarn and got:
warning ../package.json: No license field
[1/4] 馃攳 Resolving packages...
[2/4] 馃殮 Fetching packages...
error An unexpected error occurred: "https://npm.codeo.co.za/@vue%2fcli-plugin-pwa/-/cli-plugin-pwa-4.2.2.tgz: Request failed \"401 Unauthorized\"".
info If you think this is a bug, please open a bug report with the information provided in "/Users/lachlan/code/dump/vue-composition-api-tsx-example/yarn-error.log".
馃
According to https://github.com/vuejs/composition-api#template-refs it doesnt. That will work for Vue 3 i think.
This is my understanding too - unless something has changed. It looks like some people have it working? Maybe the readme is outdated. From what I can tell Vue 2 does not expose h or createElement in the same way Vue 3 does. This definitely works in Vue 3, at least using regular h (which is basically what jsx is).
@dobromir-hristov @lmiller1990 I think that the docs you mention is specific to refs, no?
For me @vue/composition-api used with Vue 2 does support the setup function returning a render function (the code is at https://github.com/vuejs/composition-api/blob/3b7eadfbb3868fd2fc67b538ea8ded4af4905832/src/setup.ts#L176-L185), it also exports the createElement method required.
I have it working perfectly in the browser, but not when mounted through @vue/test-utils. You can see an exemple here: https://github.com/liip/chusho/blob/master/packages/chusho/src/components/CToggle/CToggle.ts#L64
Looks like they do some hackery relating to the render function like we do in VTU
I guess some kind of conflict. When I run in VTU, instead of the render function getting called, I get the uncalled render function. It looks like Compsition API expects to be hijacking the original render function, but instead they received our patched one (for shallowMount).
As a proof of concept I jumped into node_modules/@vue/test-utils/dist/vue-test-utils.js at on line 13500 or so, (search for function mount) I added:
function mount(component, options) {
if ( options === void 0 ) options = {};
component.render = component.setup() // <=========== this line
// .......
}
And it works as expected - VTU renders the component correctly in the test env. Not sure why, I guess VTU expects a render function to be defined (would need to investigate more). Calling setup isn't ideal since it would trigger API calls etc etc. We need to find some way to grab the returned render function out and assigning it to render.
This problem doesn't exist in Vue 3, since it handles this internally. Composition APi is a bit of hack (like VTU is also).
Alternatively we need to figure out how to resolve the conflict between Composition API and VTU.
I will keep thinking about this, hopefully this info gives someone else something to go on if they want to mess around! A fix for this could be either here or over in composition API.
@lmiller1990 thanks for your insights!
I just tried to create my own mount wrapper that would set the result of the setup method as the component render function but that seems to be a bit more complicated than expected.
function mountWithSetup(component, options = {}) {
component.render = component.setup(options.propsData || {}, {
data: {},
parent: {},
slots: {},
});
return mount(component, options);
}
I need to pass the parameters to the setup function (props and context). Props is pretty easy but context contains stuff like parent which is not accessible to me I think.
In addition, composition API seems to throw warnings then:
[vue-composition-api] "provide" get called outside of "setup()"
Fixing this would be nice, but not something I'm able to focus on now unfortunately, and not something we will be doing before v1 - mainly because most people writing tests using the composition API will be moving to Vue 3 (hopefully), which won't have this problem, since composition is built in natively.
If you do manage to get something working, happy to take a look.
Fix is coming for this soon! vuejs/composition-api#383
Most helpful comment
As a proof of concept I jumped into
node_modules/@vue/test-utils/dist/vue-test-utils.jsat on line 13500 or so, (search forfunction mount) I added:And it works as expected - VTU renders the component correctly in the test env. Not sure why, I guess VTU expects a render function to be defined (would need to investigate more). Calling
setupisn't ideal since it would trigger API calls etc etc. We need to find some way to grab the returned render function out and assigning it torender.This problem doesn't exist in Vue 3, since it handles this internally. Composition APi is a bit of hack (like VTU is also).
Alternatively we need to figure out how to resolve the conflict between Composition API and VTU.
I will keep thinking about this, hopefully this info gives someone else something to go on if they want to mess around! A fix for this could be either here or over in composition API.