Is there a way to somehow pass component instances to the slots property of mount? The use case is, say I have a component that has a required property:
export default {
name: 'Message',
props: {
message: {
type: String,
required: true,
validator: value => value.length > 1
}
}
Then if in a test I wanna add a list of Message as the default slots, I cannot do it like it's documented: I'll get a "message" property is required error:
mount(MessageList, {
slots: {
default: messages
}
})
I tried using mount and getting the vm out of it, or also extending the component and using new Vue(...) but I get the error [Vue warn]: Failed to mount component: template or render function not defined.:
beforeEach(() => {
const indexes = [0, 1, 2]
const messages = indexes.map(i => mount(Message, {
propsData: { message: `Message ${i}` }
}).vm)
cmp = mount(MessageList, {
slots: {
default: messages
}
})
})
So, how's it possible to accomplish that?
There isn't currently a way to pass mounted components to slots.
There's some work being done in avoriaz to add the option to pass Wrappers as slots. But right now there's an unsolved bug - https://github.com/eddyerburgh/avoriaz/issues/113.
I'd like to add this functionality, but don't have time to work on this feature right now. I'd welcome a PR and could give you some guidance if you were willing to make one.
Thanks, right now I also don't have the time, but probably in the coming days I can get some and lend a hand in there. I'll contact you for that guidance in that case ;).
FYI, as a workaround, this seems to work:
mount(MessageList, {
slots: {
default: {
render(h) {
return h(Message, { props: { message: 'hey' } })
}
}
}
})
Hmm this doesn't seen to work for me. The component is created, but the props are undefined when I try to access them...
const table = mount(TableComponent, {
propsData: {
data: [
{ firstName: 'John', lastName: 'Lennon' },
{ firstName: 'Paul', lastName: 'McCartney' },
{ firstName: 'George', lastName: 'Harrison' },
{ firstName: 'Ringo', lastName: 'Starr' },
],
},
slots: {
default: {
render(h) {
return h(TableColumn, {
props: {
show: 'firstName',
label: 'First name',
},
});
},
},
},
});
console.log(table.vm.$slots.default[0].componentInstance.show);
try this:
const tableCol = table.find(TableColumn)
expect(tableCol.vm.show).toBe('firstName')
expect(tableCol.vm.label).toBe('First name')
We aren't going to implement this at the moment. You can pass a component, but not an instance.
@eddyerburgh Is this functionality anywhere on the roadmap? I have some functionality that can't really be tested without access to instance properties, and workarounds don't always work well.
It's not on the roadmap. I would review a PR if somebody wants to add it.
If anyone is looking for a workaround, try testing with another Component
let App = Vue.extend({
render (h) {
return h(Parent, {
props: {
// parent props
}
}, [
// slots
h(Child, {
props: {
// child props
}
})
])
}
})
it('has a button', () => {
let wrapper = mount(App)
console.log(wrapper.find(Parent).vm.$slots.default)
})
Oh snap, I just figured it out how to do it properly. Try this.
const localVue = createLocalVue()
localVue.component('child', Child)
const wrapper = mount(Parent, {
slots: {
default: `
<child foo="bar"><div>Lorem ipsum</div></child>
<child foo="qux"><div>Dolor sit amet</div></child>
`
},
localVue
})
localVue was there for the whole time but I kept trying to mount slots with createElement. Damn.
Most helpful comment
Oh snap, I just figured it out how to do it properly. Try this.
localVue was there for the whole time but I kept trying to mount slots with
createElement. Damn.