Skip to content

Commit fdf67c0

Browse files
feat: add ability to stub teleport (#1087)
* feat: ✨ Add stubbing support for teleport * refactor: ♻️ Disable teleport stub by default * docs: 📝 Add note about stubbing teleport * fix: 🐛 Fix children warning for stubbed teleport * chore: lint Co-authored-by: Lachlan Miller <[email protected]>
1 parent 1ca7549 commit fdf67c0

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

docs/guide/advanced/teleport.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Vue 3 comes with a new built-in component: `<Teleport>`, which allows components
44

55
Here are some strategies and techniques for testing components using `<Teleport>`.
66

7+
::: tip
8+
If you want to test the rest of your component, ignoring teleport, you can stub `teleport` by passing `teleport: true` in the [global stubs option](../../api/#global-stubs).
9+
:::
10+
711
## Example
812

913
In this example we are testing a `<Navbar>` component. It renders a `<Signup>` component inside of a `<Teleport>`. The `target` prop of `<Teleport>` is an element located outside of the `<Navbar>` component.

src/stubs.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
transformVNodeArgs,
33
Transition,
44
TransitionGroup,
5+
Teleport,
56
h,
67
ComponentPublicInstance,
78
defineComponent,
@@ -74,6 +75,18 @@ const createTransitionStub = ({ name }: StubOptions) => {
7475
})
7576
}
7677

78+
const createTeleportStub = ({ name }: StubOptions) => {
79+
const render = (ctx: ComponentPublicInstance) => {
80+
return h(name, {}, ctx.$slots)
81+
}
82+
83+
return defineComponent({
84+
name,
85+
compatConfig: { MODE: 3, RENDER_FUNCTION: false },
86+
render
87+
})
88+
}
89+
7790
const resolveComponentStubByName = (componentName: string, stubs: Stubs) => {
7891
if (Array.isArray(stubs) && stubs.length) {
7992
// ['Foo', 'Bar'] => { Foo: true, Bar: true }
@@ -158,7 +171,7 @@ export function stubComponents(
158171

159172
transformVNodeArgs((args, instance: ComponentInternalInstance | null) => {
160173
const [nodeType, props, children, patchFlag, dynamicProps] = args
161-
const type = nodeType as VNodeTypes
174+
const type = nodeType as VNodeTypes | typeof Teleport
162175

163176
// stub transition by default via config.global.stubs
164177
if (type === Transition && 'transition' in stubs && stubs['transition']) {
@@ -186,6 +199,17 @@ export function stubComponents(
186199
]
187200
}
188201

202+
// stub teleport by default via config.global.stubs
203+
if (type === Teleport && 'teleport' in stubs && stubs['teleport']) {
204+
return [
205+
createTeleportStub({
206+
name: 'teleport-stub'
207+
}),
208+
undefined,
209+
() => children
210+
]
211+
}
212+
189213
if (isComponent(type) || isFunctionalComponent(type)) {
190214
if (shouldNotStub(type)) {
191215
return args

tests/mountingOptions/global.stubs.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,34 @@ describe('mounting options: stubs', () => {
419419
expect(wrapper.find('#content').exists()).toBe(true)
420420
})
421421

422+
it('does not stub teleport by default', () => {
423+
const Comp = {
424+
template: `<teleport to="body"><div id="content" /></teleport>`
425+
}
426+
const wrapper = mount(Comp)
427+
428+
expect(wrapper.html()).toBe(
429+
'<!--teleport start-->\n' + '<!--teleport end-->'
430+
)
431+
})
432+
433+
it('opts in to stubbing teleport ', () => {
434+
const Comp = {
435+
template: `<teleport to="body"><div id="content" /></teleport>`
436+
}
437+
const wrapper = mount(Comp, {
438+
global: {
439+
stubs: {
440+
teleport: true
441+
}
442+
}
443+
})
444+
445+
expect(wrapper.html()).toBe(
446+
'<teleport-stub>\n' + ' <div id="content"></div>\n' + '</teleport-stub>'
447+
)
448+
})
449+
422450
it('stubs component by key prior before name', () => {
423451
const MyComponent = defineComponent({
424452
name: 'MyComponent',

0 commit comments

Comments
 (0)