Description
Subject of the issue
When using teleport, there's a weird inconsistency between using teleport in the template from the component under test and a child component.
Consider the following component (https://github.com/Joralf/vue-teleport/blob/main/tests/unit/TeleportInComponent.vue)
<template>
<div @click="toggleVisibility" data-testid="toggleVisibility"></div>
<Teleport to="#modal">
<Modal v-model:isVisible="visible">
<Button></Button>
</Modal>
</Teleport>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import Button from './Button.vue';
import Modal from './Modal.vue';
export default defineComponent({
components: {
Button,
Modal,
},
setup() {
const visible = ref<boolean>(false)
const toggleVisibility = (() => {
visible.value = !visible.value
})
return { visible, toggleVisibility}
}
})
</script>
When toggling the modal and inspecting whether the Button is actually rendered, both get()
and getComponent
can find the Button. See tests here: https://github.com/Joralf/vue-teleport/blob/main/tests/unit/TeleportInComponent.spec.ts
When you move the Teleport functionality to the Modal component like so: https://github.com/Joralf/vue-teleport/blob/main/tests/unit/TeleportInModal.vue, the getComponent()
method will still be able to find the button, but the get()
method will not. See tests here: https://github.com/Joralf/vue-teleport/blob/main/tests/unit/TeleportInModal.spec.ts#L37
<template>
<div @click="toggleVisibility" data-testid="toggleVisibility"></div>
<ModalWithTeleport v-model:isVisible="visible">
<Button></Button>
</ModalWithTeleport>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import Button from './Button.vue';
import ModalWithTeleport from './ModalWithTeleport.vue';
export default defineComponent({
components: {
Button,
ModalWithTeleport,
},
setup() {
const visible = ref<boolean>(false)
const toggleVisibility = (() => {
visible.value = !visible.value
})
return { visible, toggleVisibility}
}
})
</script>
Steps to reproduce
I've created a small repository here that tests teleport with wrapper.get()
and wrapper.getComponent()
to show the difference between the two:
https://github.com/Joralf/vue-teleport
You can run npm ci
and then npm runt test:unit
to see the different components under test.
Expected behaviour
I would expect wrapper.get()
to work the same regardless of whether the teleport is inside template of the Subject under test or inside a child component. I.e.: this test should pass: https://github.com/Joralf/vue-teleport/blob/main/tests/unit/TeleportInModal.spec.ts#L37
Actual behaviour
When using teleport inside a child component wrapper.get()
cannot find the element you're looking for inside the teleported content.
Possible Solution
If this is expected behaviour I'd recommend to add a warning(?) to the documentation on testing teleport here: https://next.vue-test-utils.vuejs.org/guide/advanced/teleport.html#interacting-with-the-teleported-component, cause in this example you're using the get()
method to find the elements inside the teleported html, which doesn't work when you move the teleport outside your actual component?
test('teleport', async () => {
const wrapper = mount(Navbar)
const signup = wrapper.getComponent(Signup)
await signup.get('input').setValue('valid_username')
await signup.get('form').trigger('submit.prevent')
expect(signup.emitted().signup[0]).toEqual(['valid_username'])
})