Files
agent-skills/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md
Jason Woltje f5792c40be feat: Complete fleet — 94 skills across 10+ domains
Pulled ALL skills from 15 source repositories:
- anthropics/skills: 16 (docs, design, MCP, testing)
- obra/superpowers: 14 (TDD, debugging, agents, planning)
- coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth)
- better-auth/skills: 5 (auth patterns)
- vercel-labs/agent-skills: 5 (React, design, Vercel)
- antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo)
- Plus 13 individual skills from various repos

Mosaic Stack is not limited to coding — the Orchestrator and
subagents serve coding, business, design, marketing, writing,
logistics, analysis, and more.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 16:27:42 -06:00

4.0 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Teleported Content Requires Special Testing Approach MEDIUM Vue Test Utils cannot find teleported content using standard wrapper.find() methods gotcha
vue3
teleport
testing
vue-test-utils

Teleported Content Requires Special Testing Approach

Impact: MEDIUM - Vue Test Utils scopes queries to the mounted component. Teleported content renders outside the component's DOM tree, so wrapper.find() cannot locate it. This leads to failing tests and confusion.

Task Checklist

  • Stub Teleport in unit tests to keep content in component tree
  • Use document.body queries for integration tests with real Teleport
  • Consider using getComponent() instead of DOM queries for teleported components

Problem - Standard Testing Fails:

<!-- Modal.vue -->
<template>
  <button @click="open = true">Open</button>
  <Teleport to="body">
    <div v-if="open" class="modal" data-testid="modal">
      <input type="text" data-testid="modal-input" />
    </div>
  </Teleport>
</template>
// Modal.spec.ts - BROKEN
import { mount } from '@vue/test-utils'
import Modal from './Modal.vue'

test('modal input exists', async () => {
  const wrapper = mount(Modal)
  await wrapper.find('button').trigger('click')

  // FAILS: Teleported content is not in wrapper's DOM tree
  expect(wrapper.find('[data-testid="modal-input"]').exists()).toBe(true)
})

Solution 1 - Stub Teleport:

import { mount } from '@vue/test-utils'
import Modal from './Modal.vue'

test('modal input exists', async () => {
  const wrapper = mount(Modal, {
    global: {
      stubs: {
        // Stub teleport to render content inline
        Teleport: true
      }
    }
  })

  await wrapper.find('button').trigger('click')

  // Works: Content renders inside wrapper
  expect(wrapper.find('[data-testid="modal-input"]').exists()).toBe(true)
})

Solution 2 - Query Document Body:

import { mount } from '@vue/test-utils'
import Modal from './Modal.vue'

test('modal renders to body', async () => {
  const wrapper = mount(Modal, {
    attachTo: document.body  // Required for Teleport to work
  })

  await wrapper.find('button').trigger('click')

  // Query the actual DOM
  const modal = document.querySelector('[data-testid="modal"]')
  expect(modal).toBeTruthy()

  const input = document.querySelector('[data-testid="modal-input"]')
  expect(input).toBeTruthy()

  // Cleanup
  wrapper.unmount()
})

Solution 3 - Custom Teleport Stub with Content Access:

import { mount, config } from '@vue/test-utils'
import { h, Teleport } from 'vue'
import Modal from './Modal.vue'

// Custom stub that renders content in a testable way
const TeleportStub = {
  setup(props, { slots }) {
    return () => h('div', { class: 'teleport-stub' }, slots.default?.())
  }
}

test('modal with custom stub', async () => {
  const wrapper = mount(Modal, {
    global: {
      stubs: {
        Teleport: TeleportStub
      }
    }
  })

  await wrapper.find('button').trigger('click')

  // Content is inside .teleport-stub
  expect(wrapper.find('.teleport-stub [data-testid="modal-input"]').exists()).toBe(true)
})

Testing Vue Final Modal and UI Libraries

Libraries like Vue Final Modal use Teleport internally, causing test failures:

// Problem: Vue Final Modal teleports to body
import { VueFinalModal } from 'vue-final-modal'

test('modal content', async () => {
  const wrapper = mount(MyComponent, {
    global: {
      stubs: {
        // Stub the modal component to avoid teleport issues
        VueFinalModal: true
      }
    }
  })
})

E2E Testing (Cypress, Playwright)

E2E tests query the real DOM, so Teleport works naturally:

// Cypress
it('opens modal', () => {
  cy.visit('/page-with-modal')
  cy.get('button').click()

  // Works: Cypress queries the real DOM
  cy.get('[data-testid="modal"]').should('be.visible')
})

Reference