Vue-test-utils: named slots not rendering in children of other components with shallowMount

Created on 22 Jan 2020  ·  4Comments  ·  Source: vuejs/vue-test-utils

Version

1.0.0-beta.31

Reproduction link

https://github.com/vetruvet/vue-test-utils-child-with-slots-bug

Steps to reproduce

Install dependencies then npm test.

What is expected?

Expect all test cases in the spec to pass.

More specifically, I would expect components with named slots to render their slots regardless of where they are in the component hierarchy.

What is actually happening?

shallowMount test with a component with named slots inside of another component fails because it does not render its slots.

In cases where the component with named slots is not inside another component, the slot rendering works as expected.


In beta.30, none of the shallowMount tests using the component with two slots pass. I think this may have something to do with supporting the new v-slot syntax which was added in beta.31.

Potentially related to #1307, but it's not the same issue because that one does not relate to the new v-slot changes in beta.31. However, I think #1309 _may_ address this.

Most helpful comment

To elaborate, when using shallowMount, the default slot is rendered, but named slots are not. I would not be OK with not rendering any slots in stubbed child components, because then it will be impossible to test that the correct template is sent to the child. We can currently test for attributes and props using childWrapper.attributes() and childWrapper.props(), but nothing equivalent exists for templates. Using mount is not an option because that turns the unit test into an integration test, which means that all descendant children need to be set up properly in order for the component to mount.

As a workaround for now, explicitly setting the stubs: will render the named slots:

const wrapper = shallowMount(RootComponent, {
  stubs: { ChildComponent }
}

expect(wrapper.find(ChildComponent).text()).toContain('some text');

All 4 comments

I believe that is expected since shallowMount doesn't render children components, thus not rendering their slots. if you want to render them use the 'mount' function for deep mounting (aka mounting the parent and children components)
check the following link for details.
https://vue-test-utils.vuejs.org/api/#mount

I understand what you're saying, but that's not how vue test utils works right now. If you look at other test cases (specifically, in the "shallow mount" describe block) in my reproduction repo, it IS rendering slots in child components under some cases with shallowMount. My concern is the inconsistency of the rendering - I would be OK with it if it was either consistently rendering slots or not rendering them at all.

To elaborate, when using shallowMount, the default slot is rendered, but named slots are not. I would not be OK with not rendering any slots in stubbed child components, because then it will be impossible to test that the correct template is sent to the child. We can currently test for attributes and props using childWrapper.attributes() and childWrapper.props(), but nothing equivalent exists for templates. Using mount is not an option because that turns the unit test into an integration test, which means that all descendant children need to be set up properly in order for the component to mount.

As a workaround for now, explicitly setting the stubs: will render the named slots:

const wrapper = shallowMount(RootComponent, {
  stubs: { ChildComponent }
}

expect(wrapper.find(ChildComponent).text()).toContain('some text');

Would it make sense to provide a generic stub component similar to RouterLinkStub that takes options to define the stub behaviour? In that case we could pass in a list of named slots to render.

Was this page helpful?
0 / 5 - 0 ratings