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'
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(