Skip to content

Unexpected behaviour using get() combined with teleport #1905

Open
@Joralf

Description

@Joralf

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'])
})

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions