]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: add tests
authordaiwei <daiwei521@126.com>
Fri, 21 Mar 2025 07:42:17 +0000 (15:42 +0800)
committerdaiwei <daiwei521@126.com>
Fri, 21 Mar 2025 07:42:17 +0000 (15:42 +0800)
packages/runtime-vapor/__tests__/components/Teleport.spec.ts
packages/runtime-vapor/src/components/Teleport.ts

index 373d170bd550efb9ea1ddd61ea7e03420e20808d..bc77be2dc014b8369b380788278cf4cb2fe09e74 100644 (file)
@@ -3,7 +3,12 @@ import {
   type VaporComponent,
   createComponent as originalCreateComponent,
 } from '../../src/component'
-import { VaporTeleport, template } from '@vue/runtime-vapor'
+import {
+  VaporTeleport,
+  createTemplateRefSetter,
+  setInsertionState,
+  template,
+} from '@vue/runtime-vapor'
 
 import { makeRender } from '../_utils'
 import { nextTick, onBeforeUnmount, onUnmounted, ref, shallowRef } from 'vue'
@@ -192,50 +197,219 @@ function runSharedTests(deferMode: boolean): void {
     expect(target.innerHTML).toBe('')
   })
 
-  test.todo(
-    'descendent component should be unmounted when teleport is disabled and unmounted',
-    async () => {
-      const root = document.createElement('div')
-      const beforeUnmount = vi.fn()
-      const unmounted = vi.fn()
-      const { component: Comp } = define({
-        setup() {
-          onBeforeUnmount(beforeUnmount)
-          onUnmounted(unmounted)
-          return [template('<p>')(), template('<p>')()]
-        },
-      })
+  test('descendent component should be unmounted when teleport is disabled and unmounted', async () => {
+    const root = document.createElement('div')
+    const beforeUnmount = vi.fn()
+    const unmounted = vi.fn()
+    const { component: Comp } = define({
+      setup() {
+        onBeforeUnmount(beforeUnmount)
+        onUnmounted(unmounted)
+        return [template('<p>')(), template('<p>')()]
+      },
+    })
 
-      const { app } = define({
-        setup() {
-          const n0 = createComponent(
-            VaporTeleport,
-            {
-              to: () => null,
-              disabled: () => true,
-            },
-            {
-              default: () => createComponent(Comp),
-            },
-          )
-          return [n0]
-        },
-      }).create()
-      app.mount(root)
+    const { app } = define({
+      setup() {
+        const n0 = createComponent(
+          VaporTeleport,
+          {
+            to: () => null,
+            disabled: () => true,
+          },
+          {
+            default: () => createComponent(Comp),
+          },
+        )
+        return [n0]
+      },
+    }).create()
+    app.mount(root)
 
-      expect(beforeUnmount).toHaveBeenCalledTimes(0)
-      expect(unmounted).toHaveBeenCalledTimes(0)
+    expect(beforeUnmount).toHaveBeenCalledTimes(0)
+    expect(unmounted).toHaveBeenCalledTimes(0)
 
-      app.unmount()
-      expect(beforeUnmount).toHaveBeenCalledTimes(1)
-      expect(unmounted).toHaveBeenCalledTimes(1)
-    },
-  )
+    app.unmount()
+    await nextTick()
+    expect(beforeUnmount).toHaveBeenCalledTimes(1)
+    expect(unmounted).toHaveBeenCalledTimes(1)
+  })
+
+  test('multiple teleport with same target', async () => {
+    const target = document.createElement('div')
+    const root = document.createElement('div')
+
+    const child1 = shallowRef(template('<div>one</div>')())
+    const child2 = shallowRef(template('two')())
+
+    const { mount } = define({
+      setup() {
+        const n0 = template('<div></div>')()
+        setInsertionState(n0 as any)
+        createComponent(
+          VaporTeleport,
+          {
+            to: () => target,
+          },
+          {
+            default: () => child1.value,
+          },
+        )
+        createComponent(
+          VaporTeleport,
+          {
+            to: () => target,
+          },
+          {
+            default: () => child2.value,
+          },
+        )
+        return [n0]
+      },
+    }).create()
+    mount(root)
+    expect(root.innerHTML).toBe('<div><!--teleport--><!--teleport--></div>')
+    expect(target.innerHTML).toBe('<div>one</div>two')
+
+    // update existing content
+    child1.value = [
+      template('<div>one</div>')(),
+      template('<div>two</div>')(),
+    ] as any
+    child2.value = [template('three')()] as any
+    await nextTick()
+    expect(target.innerHTML).toBe('<div>one</div><div>two</div>three')
+
+    // toggling
+    child1.value = [] as any
+    await nextTick()
+    expect(root.innerHTML).toBe('<div><!--teleport--><!--teleport--></div>')
+    expect(target.innerHTML).toBe('three')
+
+    // toggle back
+    child1.value = [
+      template('<div>one</div>')(),
+      template('<div>two</div>')(),
+    ] as any
+    child2.value = [template('three')()] as any
+    await nextTick()
+    expect(root.innerHTML).toBe('<div><!--teleport--><!--teleport--></div>')
+    // should append
+    expect(target.innerHTML).toBe('<div>one</div><div>two</div>three')
+
+    // toggle the other teleport
+    child2.value = [] as any
+    await nextTick()
+    expect(root.innerHTML).toBe('<div><!--teleport--><!--teleport--></div>')
+    expect(target.innerHTML).toBe('<div>one</div><div>two</div>')
+  })
+
+  test('should work when using template ref as target', async () => {
+    const root = document.createElement('div')
+    const target = ref<HTMLElement | null>(null)
+    const disabled = ref(true)
+
+    const { mount } = define({
+      setup() {
+        const setTemplateRef = createTemplateRefSetter()
+        const n0 = template('<div></div>')() as any
+        setTemplateRef(n0, target)
+
+        const n1 = createComponent(
+          VaporTeleport,
+          {
+            to: () => target.value,
+            disabled: () => disabled.value,
+          },
+          {
+            default: () => template('<div>teleported</div>')(),
+          },
+        )
+        return [n0, n1]
+      },
+    }).create()
+    mount(root)
+
+    expect(root.innerHTML).toBe(
+      '<div></div><div>teleported</div><!--teleport-->',
+    )
+    disabled.value = false
+    await nextTick()
+    expect(root.innerHTML).toBe(
+      '<div><div>teleported</div></div><!--teleport-->',
+    )
+  })
+
+  test('disabled', async () => {
+    const target = document.createElement('div')
+    const root = document.createElement('div')
+
+    const disabled = ref(false)
+    const { mount } = define({
+      setup() {
+        const n0 = createComponent(
+          VaporTeleport,
+          {
+            to: () => target,
+            disabled: () => disabled.value,
+          },
+          {
+            default: () => template('<div>teleported</div>')(),
+          },
+        )
+        const n1 = template('<div>root</div>')()
+        return [n0, n1]
+      },
+    }).create()
+    mount(root)
+
+    expect(root.innerHTML).toBe('<!--teleport--><div>root</div>')
+    expect(target.innerHTML).toBe('<div>teleported</div>')
+
+    disabled.value = true
+    await nextTick()
+    expect(root.innerHTML).toBe(
+      '<!--teleport start--><div>teleported</div><!--teleport end--><!--teleport--><div>root</div>',
+    )
+    expect(target.innerHTML).toBe('')
+
+    // toggle back
+    disabled.value = false
+    await nextTick()
+    expect(root.innerHTML).toBe(
+      '<!--teleport start--><!--teleport end--><!--teleport--><div>root</div>',
+    )
+    expect(target.innerHTML).toBe('<div>teleported</div>')
+  })
+
+  test.todo('moving teleport while enabled', async () => {
+    const target = document.createElement('div')
+    const root = document.createElement('div')
+
+    const child1 = createComponent(
+      VaporTeleport,
+      { to: () => target },
+      { default: () => template('<div>teleported</div>')() },
+    )
+    const child2 = template('<div>root</div>')()
+
+    const children = shallowRef([child1, child2])
+    const { mount } = define({
+      setup() {
+        return children.value
+      },
+    }).create()
+    mount(root)
+
+    expect(root.innerHTML).toBe('<!--teleport--><div>root</div>')
+    expect(target.innerHTML).toBe('<div>teleported</div>')
+
+    children.value = [child2, child1]
+    await nextTick()
+    expect(root.innerHTML).toBe('<div>root</div><!--teleport-->')
+    expect(target.innerHTML).toBe('<div>teleported</div>')
+  })
 
-  test.todo('multiple teleport with same target', async () => {})
-  test.todo('should work when using template ref as target', async () => {})
-  test.todo('disabled', async () => {})
-  test.todo('moving teleport while enabled', async () => {})
   test.todo('moving teleport while disabled', async () => {})
   test.todo('should work with block tree', async () => {})
   test.todo(
index e12ad4d87ec52fa21094e8c69bab1333813af222..b0da34540369a91121d238e29702a96bb7554461 100644 (file)
@@ -59,14 +59,14 @@ export class TeleportFragment extends VaporFragment {
   }
 
   update(props: TeleportProps, children: Block): void {
+    const parent = this.anchor.parentNode
     // teardown previous
-    if (this.currentParent && this.nodes) {
-      remove(this.nodes, this.currentParent)
+    if (this.nodes && (parent || this.currentParent)) {
+      remove(this.nodes, this.currentParent! || parent)
     }
 
     this.nodes = children
     const disabled = isTeleportDisabled(props)
-    const parent = this.anchor.parentNode
 
     const mount = (parent: ParentNode, anchor: Node | null) => {
       insert(this.nodes, (this.currentParent = parent), anchor)