|
|
@@ -7,617 +7,703 @@ import {
|
|
|
Text,
|
|
|
createApp,
|
|
|
defineComponent,
|
|
|
- h,
|
|
|
markRaw,
|
|
|
nextTick,
|
|
|
nodeOps,
|
|
|
+ h as originalH,
|
|
|
ref,
|
|
|
render,
|
|
|
serializeInner,
|
|
|
withDirectives,
|
|
|
} from '@vue/runtime-test'
|
|
|
import { Fragment, createCommentVNode, createVNode } from '../../src/vnode'
|
|
|
-import { compile, render as domRender } from 'vue'
|
|
|
+import { compile, createApp as createDOMApp, render as domRender } from 'vue'
|
|
|
|
|
|
describe('renderer: teleport', () => {
|
|
|
- test('should work', () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
-
|
|
|
- render(
|
|
|
- h(() => [
|
|
|
- h(Teleport, { to: target }, h('div', 'teleported')),
|
|
|
- h('div', 'root'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
-
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
+ describe('eager mode', () => {
|
|
|
+ runSharedTests(false)
|
|
|
})
|
|
|
|
|
|
- test('should work with SVG', async () => {
|
|
|
- const root = document.createElement('div')
|
|
|
- const svg = ref()
|
|
|
- const circle = ref()
|
|
|
+ describe('defer mode', () => {
|
|
|
+ runSharedTests(true)
|
|
|
|
|
|
- const Comp = defineComponent({
|
|
|
- setup() {
|
|
|
- return {
|
|
|
- svg,
|
|
|
- circle,
|
|
|
- }
|
|
|
- },
|
|
|
- template: `
|
|
|
- <svg ref="svg"></svg>
|
|
|
- <teleport :to="svg" v-if="svg">
|
|
|
- <circle ref="circle"></circle>
|
|
|
- </teleport>`,
|
|
|
- })
|
|
|
+ const h = originalH
|
|
|
|
|
|
- domRender(h(Comp), root)
|
|
|
+ test('should be able to target content appearing later than the teleport with defer', () => {
|
|
|
+ const root = document.createElement('div')
|
|
|
+ document.body.appendChild(root)
|
|
|
|
|
|
- await nextTick()
|
|
|
+ createDOMApp({
|
|
|
+ render() {
|
|
|
+ return [
|
|
|
+ h(Teleport, { to: '#target', defer: true }, h('div', 'teleported')),
|
|
|
+ h('div', { id: 'target' }),
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ }).mount(root)
|
|
|
|
|
|
- expect(root.innerHTML).toMatchInlineSnapshot(
|
|
|
- `"<svg><circle></circle></svg><!--teleport start--><!--teleport end-->"`,
|
|
|
- )
|
|
|
+ expect(root.innerHTML).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div id="target"><div>teleported</div></div>"`,
|
|
|
+ )
|
|
|
+ })
|
|
|
|
|
|
- expect(svg.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
|
|
|
- expect(circle.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
|
|
|
+ test('defer mode should work inside suspense', async () => {
|
|
|
+ const root = document.createElement('div')
|
|
|
+ document.body.appendChild(root)
|
|
|
+
|
|
|
+ let p: Promise<any>
|
|
|
+
|
|
|
+ const Comp = defineComponent({
|
|
|
+ template: `
|
|
|
+ <suspense>
|
|
|
+ <div>
|
|
|
+ <async />
|
|
|
+ <teleport defer to="#target-suspense">
|
|
|
+ <div ref="tel">teleported</div>
|
|
|
+ </teleport>
|
|
|
+ <div id="target-suspense" />
|
|
|
+ </div>
|
|
|
+ </suspense>`,
|
|
|
+ components: {
|
|
|
+ async: {
|
|
|
+ setup() {
|
|
|
+ p = Promise.resolve(() => 'async')
|
|
|
+ return p
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ domRender(h(Comp), root)
|
|
|
+ expect(root.innerHTML).toBe(`<!---->`)
|
|
|
+
|
|
|
+ await p!.then(() => Promise.resolve())
|
|
|
+ await nextTick()
|
|
|
+ expect(root.innerHTML).toBe(
|
|
|
+ `<div>` +
|
|
|
+ `async` +
|
|
|
+ `<!--teleport start--><!--teleport end-->` +
|
|
|
+ `<div id="target-suspense"><div>teleported</div></div>` +
|
|
|
+ `</div>`,
|
|
|
+ )
|
|
|
+ })
|
|
|
})
|
|
|
|
|
|
- test('should update target', async () => {
|
|
|
- const targetA = nodeOps.createElement('div')
|
|
|
- const targetB = nodeOps.createElement('div')
|
|
|
- const target = ref(targetA)
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
-
|
|
|
- render(
|
|
|
- h(() => [
|
|
|
- h(Teleport, { to: target.value }, h('div', 'teleported')),
|
|
|
- h('div', 'root'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
-
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(targetA)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(targetB)).toMatchInlineSnapshot(`""`)
|
|
|
-
|
|
|
- target.value = targetB
|
|
|
- await nextTick()
|
|
|
-
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(targetA)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(serializeInner(targetB)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
- })
|
|
|
+ function runSharedTests(deferMode: boolean) {
|
|
|
+ const h = (deferMode
|
|
|
+ ? (type: any, props: any, ...args: any[]) => {
|
|
|
+ if (type === Teleport) {
|
|
|
+ props.defer = true
|
|
|
+ }
|
|
|
+ return originalH(type, props, ...args)
|
|
|
+ }
|
|
|
+ : originalH) as unknown as typeof originalH
|
|
|
|
|
|
- test('should update children', async () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
- const children = ref([h('div', 'teleported')])
|
|
|
+ test('should work', () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
|
|
|
- render(
|
|
|
- h(() => h(Teleport, { to: target }, children.value)),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
+ render(
|
|
|
+ h(() => [
|
|
|
+ h(Teleport, { to: target }, h('div', 'teleported')),
|
|
|
+ h('div', 'root'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
|
|
|
- children.value = []
|
|
|
- await nextTick()
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+ })
|
|
|
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(`""`)
|
|
|
+ test('should work with SVG', async () => {
|
|
|
+ const root = document.createElement('div')
|
|
|
+ const svg = ref()
|
|
|
+ const circle = ref()
|
|
|
+
|
|
|
+ const Comp = defineComponent({
|
|
|
+ setup() {
|
|
|
+ return {
|
|
|
+ svg,
|
|
|
+ circle,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ template: `
|
|
|
+ <svg ref="svg"></svg>
|
|
|
+ <teleport :to="svg" v-if="svg">
|
|
|
+ <circle ref="circle"></circle>
|
|
|
+ </teleport>`,
|
|
|
+ })
|
|
|
+
|
|
|
+ domRender(h(Comp), root)
|
|
|
+
|
|
|
+ await nextTick()
|
|
|
+
|
|
|
+ expect(root.innerHTML).toMatchInlineSnapshot(
|
|
|
+ `"<svg><circle></circle></svg><!--teleport start--><!--teleport end-->"`,
|
|
|
+ )
|
|
|
|
|
|
- children.value = [createVNode(Text, null, 'teleported')]
|
|
|
- await nextTick()
|
|
|
+ expect(svg.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
|
|
|
+ expect(circle.value.namespaceURI).toBe('http://www.w3.org/2000/svg')
|
|
|
+ })
|
|
|
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(`"teleported"`)
|
|
|
- })
|
|
|
+ test('should update target', async () => {
|
|
|
+ const targetA = nodeOps.createElement('div')
|
|
|
+ const targetB = nodeOps.createElement('div')
|
|
|
+ const target = ref(targetA)
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
|
|
|
- test('should remove children when unmounted', () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
+ render(
|
|
|
+ h(() => [
|
|
|
+ h(Teleport, { to: target.value }, h('div', 'teleported')),
|
|
|
+ h('div', 'root'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(targetA)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(targetB)).toMatchInlineSnapshot(`""`)
|
|
|
+
|
|
|
+ target.value = targetB
|
|
|
+ await nextTick()
|
|
|
+
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(targetA)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(serializeInner(targetB)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+ })
|
|
|
+
|
|
|
+ test('should update children', async () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
+ const children = ref([h('div', 'teleported')])
|
|
|
|
|
|
- function testUnmount(props: any) {
|
|
|
render(
|
|
|
- h(() => [h(Teleport, props, h('div', 'teleported')), h('div', 'root')]),
|
|
|
+ h(() => h(Teleport, { to: target }, children.value)),
|
|
|
root,
|
|
|
)
|
|
|
expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- props.disabled ? `""` : `"<div>teleported</div>"`,
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+
|
|
|
+ children.value = []
|
|
|
+ await nextTick()
|
|
|
+
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(`""`)
|
|
|
+
|
|
|
+ children.value = [createVNode(Text, null, 'teleported')]
|
|
|
+ await nextTick()
|
|
|
+
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(`"teleported"`)
|
|
|
+ })
|
|
|
+
|
|
|
+ test('should remove children when unmounted', () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
+
|
|
|
+ function testUnmount(props: any) {
|
|
|
+ render(
|
|
|
+ h(() => [
|
|
|
+ h(Teleport, props, h('div', 'teleported')),
|
|
|
+ h('div', 'root'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ props.disabled ? `""` : `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+
|
|
|
+ render(null, root)
|
|
|
+ expect(serializeInner(target)).toBe('')
|
|
|
+ expect(target.children.length).toBe(0)
|
|
|
+ }
|
|
|
+
|
|
|
+ testUnmount({ to: target, disabled: false })
|
|
|
+ testUnmount({ to: target, disabled: true })
|
|
|
+ testUnmount({ to: null, disabled: true })
|
|
|
+ })
|
|
|
+
|
|
|
+ test('component with multi roots should be removed when unmounted', () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
+
|
|
|
+ const Comp = {
|
|
|
+ render() {
|
|
|
+ return [h('p'), h('p')]
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ render(
|
|
|
+ h(() => [h(Teleport, { to: target }, h(Comp)), h('div', 'root')]),
|
|
|
+ root,
|
|
|
)
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(`"<p></p><p></p>"`)
|
|
|
|
|
|
render(null, root)
|
|
|
expect(serializeInner(target)).toBe('')
|
|
|
- expect(target.children.length).toBe(0)
|
|
|
- }
|
|
|
+ })
|
|
|
|
|
|
- testUnmount({ to: target, disabled: false })
|
|
|
- testUnmount({ to: target, disabled: true })
|
|
|
- testUnmount({ to: null, disabled: true })
|
|
|
- })
|
|
|
+ // #6347
|
|
|
+ test('descendent component should be unmounted when teleport is disabled and unmounted', () => {
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
|
|
|
- test('component with multi roots should be removed when unmounted', () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
+ const CompWithHook = {
|
|
|
+ render() {
|
|
|
+ return [h('p'), h('p')]
|
|
|
+ },
|
|
|
+ beforeUnmount: vi.fn(),
|
|
|
+ unmounted: vi.fn(),
|
|
|
+ }
|
|
|
|
|
|
- const Comp = {
|
|
|
- render() {
|
|
|
- return [h('p'), h('p')]
|
|
|
- },
|
|
|
- }
|
|
|
+ render(
|
|
|
+ h(() => [h(Teleport, { to: null, disabled: true }, h(CompWithHook))]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(CompWithHook.beforeUnmount).toBeCalledTimes(0)
|
|
|
+ expect(CompWithHook.unmounted).toBeCalledTimes(0)
|
|
|
|
|
|
- render(
|
|
|
- h(() => [h(Teleport, { to: target }, h(Comp)), h('div', 'root')]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(`"<p></p><p></p>"`)
|
|
|
+ render(null, root)
|
|
|
|
|
|
- render(null, root)
|
|
|
- expect(serializeInner(target)).toBe('')
|
|
|
- })
|
|
|
+ expect(CompWithHook.beforeUnmount).toBeCalledTimes(1)
|
|
|
+ expect(CompWithHook.unmounted).toBeCalledTimes(1)
|
|
|
+ })
|
|
|
|
|
|
- // #6347
|
|
|
- test('descendent component should be unmounted when teleport is disabled and unmounted', () => {
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
-
|
|
|
- const CompWithHook = {
|
|
|
- render() {
|
|
|
- return [h('p'), h('p')]
|
|
|
- },
|
|
|
- beforeUnmount: vi.fn(),
|
|
|
- unmounted: vi.fn(),
|
|
|
- }
|
|
|
-
|
|
|
- render(
|
|
|
- h(() => [h(Teleport, { to: null, disabled: true }, h(CompWithHook))]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(CompWithHook.beforeUnmount).toBeCalledTimes(0)
|
|
|
- expect(CompWithHook.unmounted).toBeCalledTimes(0)
|
|
|
-
|
|
|
- render(null, root)
|
|
|
-
|
|
|
- expect(CompWithHook.beforeUnmount).toBeCalledTimes(1)
|
|
|
- expect(CompWithHook.unmounted).toBeCalledTimes(1)
|
|
|
- })
|
|
|
+ test('multiple teleport with same target', () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
|
|
|
- test('multiple teleport with same target', () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
-
|
|
|
- render(
|
|
|
- h('div', [
|
|
|
- h(Teleport, { to: target }, h('div', 'one')),
|
|
|
- h(Teleport, { to: target }, 'two'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
-
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<div><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--></div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(`"<div>one</div>two"`)
|
|
|
-
|
|
|
- // update existing content
|
|
|
- render(
|
|
|
- h('div', [
|
|
|
- h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
|
|
|
- h(Teleport, { to: target }, 'three'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>one</div><div>two</div>three"`,
|
|
|
- )
|
|
|
-
|
|
|
- // toggling
|
|
|
- render(h('div', [null, h(Teleport, { to: target }, 'three')]), root)
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<div><!----><!--teleport start--><!--teleport end--></div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(`"three"`)
|
|
|
-
|
|
|
- // toggle back
|
|
|
- render(
|
|
|
- h('div', [
|
|
|
- h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
|
|
|
- h(Teleport, { to: target }, 'three'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<div><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--></div>"`,
|
|
|
- )
|
|
|
- // should append
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"three<div>one</div><div>two</div>"`,
|
|
|
- )
|
|
|
-
|
|
|
- // toggle the other teleport
|
|
|
- render(
|
|
|
- h('div', [
|
|
|
- h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
|
|
|
- null,
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<div><!--teleport start--><!--teleport end--><!----></div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>one</div><div>two</div>"`,
|
|
|
- )
|
|
|
- })
|
|
|
+ render(
|
|
|
+ h('div', [
|
|
|
+ h(Teleport, { to: target }, h('div', 'one')),
|
|
|
+ h(Teleport, { to: target }, 'two'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
|
|
|
- test('should work when using template ref as target', async () => {
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
- const target = ref(null)
|
|
|
- const disabled = ref(true)
|
|
|
-
|
|
|
- const App = {
|
|
|
- setup() {
|
|
|
- return () =>
|
|
|
- h(Fragment, [
|
|
|
- h('div', { ref: target }),
|
|
|
- h(
|
|
|
- Teleport,
|
|
|
- { to: target.value, disabled: disabled.value },
|
|
|
- h('div', 'teleported'),
|
|
|
- ),
|
|
|
- ])
|
|
|
- },
|
|
|
- }
|
|
|
- render(h(App), root)
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<div></div><!--teleport start--><div>teleported</div><!--teleport end-->"`,
|
|
|
- )
|
|
|
-
|
|
|
- disabled.value = false
|
|
|
- await nextTick()
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<div><div>teleported</div></div><!--teleport start--><!--teleport end-->"`,
|
|
|
- )
|
|
|
- })
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<div><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--></div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>one</div>two"`,
|
|
|
+ )
|
|
|
|
|
|
- test('disabled', () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
-
|
|
|
- const renderWithDisabled = (disabled: boolean) => {
|
|
|
- return h(Fragment, [
|
|
|
- h(Teleport, { to: target, disabled }, h('div', 'teleported')),
|
|
|
- h('div', 'root'),
|
|
|
- ])
|
|
|
- }
|
|
|
-
|
|
|
- render(renderWithDisabled(false), root)
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
-
|
|
|
- render(renderWithDisabled(true), root)
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toBe(``)
|
|
|
-
|
|
|
- // toggle back
|
|
|
- render(renderWithDisabled(false), root)
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
- })
|
|
|
+ // update existing content
|
|
|
+ render(
|
|
|
+ h('div', [
|
|
|
+ h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
|
|
|
+ h(Teleport, { to: target }, 'three'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>one</div><div>two</div>three"`,
|
|
|
+ )
|
|
|
|
|
|
- test('moving teleport while enabled', () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
-
|
|
|
- render(
|
|
|
- h(Fragment, [
|
|
|
- h(Teleport, { to: target }, h('div', 'teleported')),
|
|
|
- h('div', 'root'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
-
|
|
|
- render(
|
|
|
- h(Fragment, [
|
|
|
- h('div', 'root'),
|
|
|
- h(Teleport, { to: target }, h('div', 'teleported')),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<div>root</div><!--teleport start--><!--teleport end-->"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
-
|
|
|
- render(
|
|
|
- h(Fragment, [
|
|
|
- h(Teleport, { to: target }, h('div', 'teleported')),
|
|
|
- h('div', 'root'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
- })
|
|
|
+ // toggling
|
|
|
+ render(h('div', [null, h(Teleport, { to: target }, 'three')]), root)
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<div><!----><!--teleport start--><!--teleport end--></div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(`"three"`)
|
|
|
|
|
|
- test('moving teleport while disabled', () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
-
|
|
|
- render(
|
|
|
- h(Fragment, [
|
|
|
- h(Teleport, { to: target, disabled: true }, h('div', 'teleported')),
|
|
|
- h('div', 'root'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toBe('')
|
|
|
-
|
|
|
- render(
|
|
|
- h(Fragment, [
|
|
|
- h('div', 'root'),
|
|
|
- h(Teleport, { to: target, disabled: true }, h('div', 'teleported')),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<div>root</div><!--teleport start--><div>teleported</div><!--teleport end-->"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toBe('')
|
|
|
-
|
|
|
- render(
|
|
|
- h(Fragment, [
|
|
|
- h(Teleport, { to: target, disabled: true }, h('div', 'teleported')),
|
|
|
- h('div', 'root'),
|
|
|
- ]),
|
|
|
- root,
|
|
|
- )
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toBe('')
|
|
|
- })
|
|
|
+ // toggle back
|
|
|
+ render(
|
|
|
+ h('div', [
|
|
|
+ h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
|
|
|
+ h(Teleport, { to: target }, 'three'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<div><!--teleport start--><!--teleport end--><!--teleport start--><!--teleport end--></div>"`,
|
|
|
+ )
|
|
|
+ // should append
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"three<div>one</div><div>two</div>"`,
|
|
|
+ )
|
|
|
|
|
|
- test('should work with block tree', async () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
- const disabled = ref(false)
|
|
|
+ // toggle the other teleport
|
|
|
+ render(
|
|
|
+ h('div', [
|
|
|
+ h(Teleport, { to: target }, [h('div', 'one'), h('div', 'two')]),
|
|
|
+ null,
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<div><!--teleport start--><!--teleport end--><!----></div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>one</div><div>two</div>"`,
|
|
|
+ )
|
|
|
+ })
|
|
|
|
|
|
- const App = {
|
|
|
- setup() {
|
|
|
- return {
|
|
|
- target: markRaw(target),
|
|
|
- disabled,
|
|
|
- }
|
|
|
- },
|
|
|
- render: compile(`
|
|
|
- <teleport :to="target" :disabled="disabled">
|
|
|
- <div>teleported</div><span>{{ disabled }}</span><span v-if="disabled"/>
|
|
|
- </teleport>
|
|
|
- <div>root</div>
|
|
|
- `),
|
|
|
- }
|
|
|
- render(h(App), root)
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div><span>false</span><!--v-if-->"`,
|
|
|
- )
|
|
|
-
|
|
|
- disabled.value = true
|
|
|
- await nextTick()
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><div>teleported</div><span>true</span><span></span><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toBe(``)
|
|
|
-
|
|
|
- // toggle back
|
|
|
- disabled.value = false
|
|
|
- await nextTick()
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div><span>false</span><!--v-if-->"`,
|
|
|
- )
|
|
|
- })
|
|
|
+ test('should work when using template ref as target', async () => {
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
+ const target = ref(null)
|
|
|
+ const disabled = ref(true)
|
|
|
+
|
|
|
+ const App = {
|
|
|
+ setup() {
|
|
|
+ return () =>
|
|
|
+ h(Fragment, [
|
|
|
+ h('div', { ref: target }),
|
|
|
+ h(
|
|
|
+ Teleport,
|
|
|
+ { to: target.value, disabled: disabled.value },
|
|
|
+ h('div', 'teleported'),
|
|
|
+ ),
|
|
|
+ ])
|
|
|
+ },
|
|
|
+ }
|
|
|
+ render(h(App), root)
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<div></div><!--teleport start--><div>teleported</div><!--teleport end-->"`,
|
|
|
+ )
|
|
|
|
|
|
- // #3497
|
|
|
- test(`the dir hooks of the Teleport's children should be called correctly`, async () => {
|
|
|
- const target = nodeOps.createElement('div')
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
- const toggle = ref(true)
|
|
|
- const dir = {
|
|
|
- mounted: vi.fn(),
|
|
|
- unmounted: vi.fn(),
|
|
|
- }
|
|
|
-
|
|
|
- const app = createApp({
|
|
|
- setup() {
|
|
|
- return () => {
|
|
|
- return toggle.value
|
|
|
- ? h(Teleport, { to: target }, [
|
|
|
- withDirectives(h('div', ['foo']), [[dir]]),
|
|
|
- ])
|
|
|
- : null
|
|
|
- }
|
|
|
- },
|
|
|
+ disabled.value = false
|
|
|
+ await nextTick()
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<div><div>teleported</div></div><!--teleport start--><!--teleport end-->"`,
|
|
|
+ )
|
|
|
})
|
|
|
- app.mount(root)
|
|
|
-
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
- `"<!--teleport start--><!--teleport end-->"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(`"<div>foo</div>"`)
|
|
|
- expect(dir.mounted).toHaveBeenCalledTimes(1)
|
|
|
- expect(dir.unmounted).toHaveBeenCalledTimes(0)
|
|
|
-
|
|
|
- toggle.value = false
|
|
|
- await nextTick()
|
|
|
- expect(serializeInner(root)).toMatchInlineSnapshot(`"<!---->"`)
|
|
|
- expect(serializeInner(target)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(dir.mounted).toHaveBeenCalledTimes(1)
|
|
|
- expect(dir.unmounted).toHaveBeenCalledTimes(1)
|
|
|
- })
|
|
|
|
|
|
- // #7835
|
|
|
- test(`ensure that target changes when disabled are updated correctly when enabled`, async () => {
|
|
|
- const root = nodeOps.createElement('div')
|
|
|
- const target1 = nodeOps.createElement('div')
|
|
|
- const target2 = nodeOps.createElement('div')
|
|
|
- const target3 = nodeOps.createElement('div')
|
|
|
- const target = ref(target1)
|
|
|
- const disabled = ref(true)
|
|
|
-
|
|
|
- const App = {
|
|
|
- setup() {
|
|
|
- return () =>
|
|
|
- h(Fragment, [
|
|
|
- h(
|
|
|
- Teleport,
|
|
|
- { to: target.value, disabled: disabled.value },
|
|
|
- h('div', 'teleported'),
|
|
|
- ),
|
|
|
- ])
|
|
|
- },
|
|
|
- }
|
|
|
- render(h(App), root)
|
|
|
- disabled.value = false
|
|
|
- await nextTick()
|
|
|
- expect(serializeInner(target1)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
- expect(serializeInner(target2)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(serializeInner(target3)).toMatchInlineSnapshot(`""`)
|
|
|
-
|
|
|
- disabled.value = true
|
|
|
- await nextTick()
|
|
|
- target.value = target2
|
|
|
- await nextTick()
|
|
|
- expect(serializeInner(target1)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(serializeInner(target2)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(serializeInner(target3)).toMatchInlineSnapshot(`""`)
|
|
|
-
|
|
|
- target.value = target3
|
|
|
- await nextTick()
|
|
|
- expect(serializeInner(target1)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(serializeInner(target2)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(serializeInner(target3)).toMatchInlineSnapshot(`""`)
|
|
|
-
|
|
|
- disabled.value = false
|
|
|
- await nextTick()
|
|
|
- expect(serializeInner(target1)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(serializeInner(target2)).toMatchInlineSnapshot(`""`)
|
|
|
- expect(serializeInner(target3)).toMatchInlineSnapshot(
|
|
|
- `"<div>teleported</div>"`,
|
|
|
- )
|
|
|
- })
|
|
|
+ test('disabled', () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
|
|
|
- //#9071
|
|
|
- test('toggle sibling node inside target node', async () => {
|
|
|
- const root = document.createElement('div')
|
|
|
- const show = ref(false)
|
|
|
- const App = defineComponent({
|
|
|
- setup() {
|
|
|
- return () => {
|
|
|
- return show.value
|
|
|
- ? h(Teleport, { to: root }, [h('div', 'teleported')])
|
|
|
- : h('div', 'foo')
|
|
|
- }
|
|
|
- },
|
|
|
+ const renderWithDisabled = (disabled: boolean) => {
|
|
|
+ return h(Fragment, [
|
|
|
+ h(Teleport, { to: target, disabled }, h('div', 'teleported')),
|
|
|
+ h('div', 'root'),
|
|
|
+ ])
|
|
|
+ }
|
|
|
+
|
|
|
+ render(renderWithDisabled(false), root)
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+
|
|
|
+ render(renderWithDisabled(true), root)
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toBe(``)
|
|
|
+
|
|
|
+ // toggle back
|
|
|
+ render(renderWithDisabled(false), root)
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
})
|
|
|
|
|
|
- domRender(h(App), root)
|
|
|
- expect(root.innerHTML).toMatchInlineSnapshot('"<div>foo</div>"')
|
|
|
+ test('moving teleport while enabled', () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
|
|
|
- show.value = true
|
|
|
- await nextTick()
|
|
|
+ render(
|
|
|
+ h(Fragment, [
|
|
|
+ h(Teleport, { to: target }, h('div', 'teleported')),
|
|
|
+ h('div', 'root'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
|
|
|
- expect(root.innerHTML).toMatchInlineSnapshot(
|
|
|
- '"<!--teleport start--><!--teleport end--><div>teleported</div>"',
|
|
|
- )
|
|
|
+ render(
|
|
|
+ h(Fragment, [
|
|
|
+ h('div', 'root'),
|
|
|
+ h(Teleport, { to: target }, h('div', 'teleported')),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<div>root</div><!--teleport start--><!--teleport end-->"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
|
|
|
- show.value = false
|
|
|
- await nextTick()
|
|
|
+ render(
|
|
|
+ h(Fragment, [
|
|
|
+ h(Teleport, { to: target }, h('div', 'teleported')),
|
|
|
+ h('div', 'root'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+ })
|
|
|
|
|
|
- expect(root.innerHTML).toMatchInlineSnapshot('"<div>foo</div>"')
|
|
|
- })
|
|
|
+ test('moving teleport while disabled', () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
|
|
|
- test('unmount previous sibling node inside target node', async () => {
|
|
|
- const root = document.createElement('div')
|
|
|
- const parentShow = ref(false)
|
|
|
- const childShow = ref(true)
|
|
|
-
|
|
|
- const Comp = {
|
|
|
- setup() {
|
|
|
- return () => h(Teleport, { to: root }, [h('div', 'foo')])
|
|
|
- },
|
|
|
- }
|
|
|
-
|
|
|
- const App = defineComponent({
|
|
|
- setup() {
|
|
|
- return () => {
|
|
|
- return parentShow.value
|
|
|
- ? h(Fragment, { key: 0 }, [
|
|
|
- childShow.value ? h(Comp) : createCommentVNode('v-if'),
|
|
|
- ])
|
|
|
- : createCommentVNode('v-if')
|
|
|
- }
|
|
|
- },
|
|
|
+ render(
|
|
|
+ h(Fragment, [
|
|
|
+ h(Teleport, { to: target, disabled: true }, h('div', 'teleported')),
|
|
|
+ h('div', 'root'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toBe('')
|
|
|
+
|
|
|
+ render(
|
|
|
+ h(Fragment, [
|
|
|
+ h('div', 'root'),
|
|
|
+ h(Teleport, { to: target, disabled: true }, h('div', 'teleported')),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<div>root</div><!--teleport start--><div>teleported</div><!--teleport end-->"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toBe('')
|
|
|
+
|
|
|
+ render(
|
|
|
+ h(Fragment, [
|
|
|
+ h(Teleport, { to: target, disabled: true }, h('div', 'teleported')),
|
|
|
+ h('div', 'root'),
|
|
|
+ ]),
|
|
|
+ root,
|
|
|
+ )
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><div>teleported</div><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toBe('')
|
|
|
})
|
|
|
|
|
|
- domRender(h(App), root)
|
|
|
- expect(root.innerHTML).toMatchInlineSnapshot('"<!--v-if-->"')
|
|
|
+ test('should work with block tree', async () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
+ const disabled = ref(false)
|
|
|
+
|
|
|
+ const App = {
|
|
|
+ setup() {
|
|
|
+ return {
|
|
|
+ target: markRaw(target),
|
|
|
+ disabled,
|
|
|
+ }
|
|
|
+ },
|
|
|
+ render: compile(`
|
|
|
+ <teleport :to="target" :disabled="disabled">
|
|
|
+ <div>teleported</div><span>{{ disabled }}</span><span v-if="disabled"/>
|
|
|
+ </teleport>
|
|
|
+ <div>root</div>
|
|
|
+ `),
|
|
|
+ }
|
|
|
+ render(h(App), root)
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div><span>false</span><!--v-if-->"`,
|
|
|
+ )
|
|
|
|
|
|
- parentShow.value = true
|
|
|
- await nextTick()
|
|
|
- expect(root.innerHTML).toMatchInlineSnapshot(
|
|
|
- '"<!--teleport start--><!--teleport end--><div>foo</div>"',
|
|
|
- )
|
|
|
+ disabled.value = true
|
|
|
+ await nextTick()
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><div>teleported</div><span>true</span><span></span><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toBe(``)
|
|
|
|
|
|
- parentShow.value = false
|
|
|
- await nextTick()
|
|
|
- expect(root.innerHTML).toMatchInlineSnapshot('"<!--v-if-->"')
|
|
|
- })
|
|
|
+ // toggle back
|
|
|
+ disabled.value = false
|
|
|
+ await nextTick()
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end--><div>root</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div><span>false</span><!--v-if-->"`,
|
|
|
+ )
|
|
|
+ })
|
|
|
+
|
|
|
+ // #3497
|
|
|
+ test(`the dir hooks of the Teleport's children should be called correctly`, async () => {
|
|
|
+ const target = nodeOps.createElement('div')
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
+ const toggle = ref(true)
|
|
|
+ const dir = {
|
|
|
+ mounted: vi.fn(),
|
|
|
+ unmounted: vi.fn(),
|
|
|
+ }
|
|
|
+
|
|
|
+ const app = createApp({
|
|
|
+ setup() {
|
|
|
+ return () => {
|
|
|
+ return toggle.value
|
|
|
+ ? h(Teleport, { to: target }, [
|
|
|
+ withDirectives(h('div', ['foo']), [[dir]]),
|
|
|
+ ])
|
|
|
+ : null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+ app.mount(root)
|
|
|
+
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(
|
|
|
+ `"<!--teleport start--><!--teleport end-->"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(`"<div>foo</div>"`)
|
|
|
+ await nextTick()
|
|
|
+ expect(dir.mounted).toHaveBeenCalledTimes(1)
|
|
|
+ expect(dir.unmounted).toHaveBeenCalledTimes(0)
|
|
|
+
|
|
|
+ toggle.value = false
|
|
|
+ await nextTick()
|
|
|
+ expect(serializeInner(root)).toMatchInlineSnapshot(`"<!---->"`)
|
|
|
+ expect(serializeInner(target)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(dir.mounted).toHaveBeenCalledTimes(1)
|
|
|
+ expect(dir.unmounted).toHaveBeenCalledTimes(1)
|
|
|
+ })
|
|
|
+
|
|
|
+ // #7835
|
|
|
+ test(`ensure that target changes when disabled are updated correctly when enabled`, async () => {
|
|
|
+ const root = nodeOps.createElement('div')
|
|
|
+ const target1 = nodeOps.createElement('div')
|
|
|
+ const target2 = nodeOps.createElement('div')
|
|
|
+ const target3 = nodeOps.createElement('div')
|
|
|
+ const target = ref(target1)
|
|
|
+ const disabled = ref(true)
|
|
|
+
|
|
|
+ const App = {
|
|
|
+ setup() {
|
|
|
+ return () =>
|
|
|
+ h(Fragment, [
|
|
|
+ h(
|
|
|
+ Teleport,
|
|
|
+ { to: target.value, disabled: disabled.value },
|
|
|
+ h('div', 'teleported'),
|
|
|
+ ),
|
|
|
+ ])
|
|
|
+ },
|
|
|
+ }
|
|
|
+ render(h(App), root)
|
|
|
+ disabled.value = false
|
|
|
+ await nextTick()
|
|
|
+ expect(serializeInner(target1)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+ expect(serializeInner(target2)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(serializeInner(target3)).toMatchInlineSnapshot(`""`)
|
|
|
+
|
|
|
+ disabled.value = true
|
|
|
+ await nextTick()
|
|
|
+ target.value = target2
|
|
|
+ await nextTick()
|
|
|
+ expect(serializeInner(target1)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(serializeInner(target2)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(serializeInner(target3)).toMatchInlineSnapshot(`""`)
|
|
|
+
|
|
|
+ target.value = target3
|
|
|
+ await nextTick()
|
|
|
+ expect(serializeInner(target1)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(serializeInner(target2)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(serializeInner(target3)).toMatchInlineSnapshot(`""`)
|
|
|
+
|
|
|
+ disabled.value = false
|
|
|
+ await nextTick()
|
|
|
+ expect(serializeInner(target1)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(serializeInner(target2)).toMatchInlineSnapshot(`""`)
|
|
|
+ expect(serializeInner(target3)).toMatchInlineSnapshot(
|
|
|
+ `"<div>teleported</div>"`,
|
|
|
+ )
|
|
|
+ })
|
|
|
+
|
|
|
+ //#9071
|
|
|
+ test('toggle sibling node inside target node', async () => {
|
|
|
+ const root = document.createElement('div')
|
|
|
+ const show = ref(false)
|
|
|
+ const App = defineComponent({
|
|
|
+ setup() {
|
|
|
+ return () => {
|
|
|
+ return show.value
|
|
|
+ ? h(Teleport, { to: root }, [h('div', 'teleported')])
|
|
|
+ : h('div', 'foo')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ domRender(h(App), root)
|
|
|
+ expect(root.innerHTML).toMatchInlineSnapshot('"<div>foo</div>"')
|
|
|
+
|
|
|
+ show.value = true
|
|
|
+ await nextTick()
|
|
|
+
|
|
|
+ expect(root.innerHTML).toMatchInlineSnapshot(
|
|
|
+ '"<!--teleport start--><!--teleport end--><div>teleported</div>"',
|
|
|
+ )
|
|
|
+
|
|
|
+ show.value = false
|
|
|
+ await nextTick()
|
|
|
+
|
|
|
+ expect(root.innerHTML).toMatchInlineSnapshot('"<div>foo</div>"')
|
|
|
+ })
|
|
|
+
|
|
|
+ test('unmount previous sibling node inside target node', async () => {
|
|
|
+ const root = document.createElement('div')
|
|
|
+ const parentShow = ref(false)
|
|
|
+ const childShow = ref(true)
|
|
|
+
|
|
|
+ const Comp = {
|
|
|
+ setup() {
|
|
|
+ return () => h(Teleport, { to: root }, [h('div', 'foo')])
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ const App = defineComponent({
|
|
|
+ setup() {
|
|
|
+ return () => {
|
|
|
+ return parentShow.value
|
|
|
+ ? h(Fragment, { key: 0 }, [
|
|
|
+ childShow.value ? h(Comp) : createCommentVNode('v-if'),
|
|
|
+ ])
|
|
|
+ : createCommentVNode('v-if')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ })
|
|
|
+
|
|
|
+ domRender(h(App), root)
|
|
|
+ expect(root.innerHTML).toMatchInlineSnapshot('"<!--v-if-->"')
|
|
|
+
|
|
|
+ parentShow.value = true
|
|
|
+ await nextTick()
|
|
|
+ expect(root.innerHTML).toMatchInlineSnapshot(
|
|
|
+ '"<!--teleport start--><!--teleport end--><div>foo</div>"',
|
|
|
+ )
|
|
|
+
|
|
|
+ parentShow.value = false
|
|
|
+ await nextTick()
|
|
|
+ expect(root.innerHTML).toMatchInlineSnapshot('"<!--v-if-->"')
|
|
|
+ })
|
|
|
+ }
|
|
|
})
|