Skip to content

Commit cbacde5

Browse files
committed
chore: add more cases
1 parent c1efbc2 commit cbacde5

File tree

2 files changed

+122
-18
lines changed

2 files changed

+122
-18
lines changed

packages/runtime-vapor/__tests__/hydration.spec.ts

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,6 +2942,106 @@ describe('Vapor Mode hydration', () => {
29422942
`"<!--teleport start anchor--><span>baz</span><span class="baz"></span><!--teleport anchor-->"`,
29432943
)
29442944
})
2945+
2946+
test('multiple + integration', async () => {
2947+
const data = ref({
2948+
msg: ref('foo'),
2949+
fn1: vi.fn(),
2950+
fn2: vi.fn(),
2951+
})
2952+
2953+
const code = `
2954+
<teleport to="#teleport2">
2955+
<span>{{data.msg}}</span>
2956+
<span :class="data.msg" @click="data.fn1"></span>
2957+
</teleport>
2958+
<teleport to="#teleport2">
2959+
<span>{{data.msg}}2</span>
2960+
<span :class="data.msg + 2" @click="data.fn2"></span>
2961+
</teleport>`
2962+
2963+
const serverComp = compile(
2964+
`<template>${code}</template>`,
2965+
data,
2966+
undefined,
2967+
{
2968+
vapor: true,
2969+
ssr: true,
2970+
},
2971+
)
2972+
2973+
const teleportContainer = document.createElement('div')
2974+
teleportContainer.id = 'teleport2'
2975+
const ctx = {} as any
2976+
const mainHtml = await VueServerRenderer.renderToString(
2977+
runtimeDom.createSSRApp(serverComp),
2978+
ctx,
2979+
)
2980+
expect(mainHtml).toMatchInlineSnapshot(
2981+
`"<!--[--><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--><!--]-->"`,
2982+
)
2983+
2984+
const teleportHtml = ctx.teleports!['#teleport2']
2985+
expect(teleportHtml).toMatchInlineSnapshot(
2986+
`"<!--teleport start anchor--><span>foo</span><span class="foo"></span><!--teleport anchor--><!--teleport start anchor--><span>foo2</span><span class="foo2"></span><!--teleport anchor-->"`,
2987+
)
2988+
2989+
teleportContainer.innerHTML = teleportHtml
2990+
document.body.appendChild(teleportContainer)
2991+
2992+
const { frag, container } = await mountWithHydration(mainHtml, code, data)
2993+
2994+
const teleports = frag as any as TeleportFragment[]
2995+
const teleport1 = teleports[0]
2996+
const teleport2 = teleports[1]
2997+
expect(teleport1.anchor).toBe(container.childNodes[2])
2998+
expect(teleport2.anchor).toBe(container.childNodes[4])
2999+
3000+
expect(teleport1.target).toBe(teleportContainer)
3001+
expect(teleport1.targetStart).toBe(teleportContainer.childNodes[0])
3002+
expect((teleport1.nodes as Node[])[0]).toBe(
3003+
teleportContainer.childNodes[1],
3004+
)
3005+
expect(teleport1.targetAnchor).toBe(teleportContainer.childNodes[3])
3006+
3007+
expect(teleport2.target).toBe(teleportContainer)
3008+
expect(teleport2.targetStart).toBe(teleportContainer.childNodes[4])
3009+
expect((teleport2.nodes as Node[])[0]).toBe(
3010+
teleportContainer.childNodes[5],
3011+
)
3012+
expect(teleport2.targetAnchor).toBe(teleportContainer.childNodes[7])
3013+
3014+
expect(container.innerHTML).toMatchInlineSnapshot(
3015+
`"<!--[--><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--><!--]-->"`,
3016+
)
3017+
3018+
// event handler
3019+
triggerEvent('click', teleportContainer.querySelector('.foo')!)
3020+
expect(data.value.fn1).toHaveBeenCalled()
3021+
3022+
triggerEvent('click', teleportContainer.querySelector('.foo2')!)
3023+
expect(data.value.fn2).toHaveBeenCalled()
3024+
3025+
data.value.msg = 'bar'
3026+
await nextTick()
3027+
expect(formatHtml(teleportContainer.innerHTML)).toMatchInlineSnapshot(
3028+
`"<!--teleport start anchor--><span>bar</span><span class="bar"></span><!--teleport anchor--><!--teleport start anchor--><span>bar2</span><span class="bar2"></span><!--teleport anchor-->"`,
3029+
)
3030+
})
3031+
3032+
test('disabled', async () => {})
3033+
3034+
test('disabled + as component root', async () => {})
3035+
3036+
test('as component root', async () => {})
3037+
3038+
test('nested', async () => {})
3039+
3040+
test('unmount (full integration)', async () => {})
3041+
3042+
test('unmount (mismatch + full integration)', async () => {})
3043+
3044+
test('target change (mismatch + full integration)', async () => {})
29453045
})
29463046

29473047
describe.todo('Suspense')

packages/runtime-vapor/src/components/Teleport.ts

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,7 @@ import {
99
warn,
1010
} from '@vue/runtime-dom'
1111
import { type Block, type BlockFn, insert, remove } from '../block'
12-
import {
13-
child,
14-
createComment,
15-
createTextNode,
16-
next,
17-
querySelector,
18-
} from '../dom/node'
12+
import { createComment, createTextNode, querySelector } from '../dom/node'
1913
import {
2014
type LooseRawProps,
2115
type LooseRawSlots,
@@ -228,19 +222,17 @@ export class TeleportFragment extends VaporFragment {
228222
))
229223
if (target) {
230224
const disabled = isTeleportDisabled(this.resolvedProps!)
231-
const targetNode = (target as TeleportTargetElement)._lpa || child(target)
225+
const targetNode =
226+
(target as TeleportTargetElement)._lpa || target.firstChild
232227
if (disabled) {
233228
this.placeholder = currentHydrationNode!
234-
let nextNode = next(this.placeholder)
229+
let nextNode = this.placeholder.nextSibling!
235230
setCurrentHydrationNode(nextNode)
236-
while (nextNode && !isComment(nextNode, 'teleport end')) {
237-
nextNode = next(nextNode)
238-
}
239-
this.anchor = nextNode
231+
this.anchor = locateTeleportEndAnchor(nextNode)!
240232
this.targetStart = targetNode
241-
this.targetAnchor = targetNode && next(targetNode)
233+
this.targetAnchor = targetNode && targetNode.nextSibling!
242234
} else {
243-
this.anchor = next(currentHydrationNode!)
235+
this.anchor = locateTeleportEndAnchor()!
244236
let targetAnchor = targetNode
245237
while (targetAnchor) {
246238
if (targetAnchor && targetAnchor.nodeType === 8) {
@@ -249,13 +241,13 @@ export class TeleportFragment extends VaporFragment {
249241
} else if ((targetAnchor as Comment).data === 'teleport anchor') {
250242
this.targetAnchor = targetAnchor
251243
;(target as TeleportTargetElement)._lpa =
252-
this.targetAnchor && next(this.targetAnchor)
244+
this.targetAnchor && this.targetAnchor.nextSibling!
253245
break
254246
}
255247
}
256-
targetAnchor = next(targetAnchor)
248+
targetAnchor = targetAnchor.nextSibling!
257249
}
258-
setCurrentHydrationNode(targetNode && next(targetNode))
250+
setCurrentHydrationNode(targetNode && targetNode.nextSibling!)
259251
}
260252

261253
this.initChildren()
@@ -269,3 +261,15 @@ export function isVaporTeleport(
269261
): value is typeof VaporTeleportImpl {
270262
return value === VaporTeleportImpl
271263
}
264+
265+
function locateTeleportEndAnchor(
266+
node: Node = currentHydrationNode!,
267+
): Node | null {
268+
while (node) {
269+
if (isComment(node, 'teleport end')) {
270+
return node
271+
}
272+
node = node.nextSibling as Node
273+
}
274+
return null
275+
}

0 commit comments

Comments
 (0)