import {
child,
createIf,
insert,
renderEffect,
template,
// @ts-expect-error
withDirectives,
} from '../src'
import { nextTick, ref } from '@vue/runtime-dom'
import type { Mock } from 'vitest'
import { makeRender } from './_utils'
import { unmountComponent } from '../src/component'
import { setElementText } from '../src/dom/prop'
const define = makeRender()
describe('createIf', () => {
test('basic', async () => {
// mock this template:
//
//
{{counter}}
//
zero
//
let spyIfFn: Mock
let spyElseFn: Mock
const count = ref(0)
const spyConditionFn = vi.fn(() => count.value)
// templates can be reused through caching.
const t0 = template('')
const t1 = template('')
const t2 = template('zero
')
const { host } = define(() => {
const n0 = t0()
insert(
createIf(
spyConditionFn,
// v-if
(spyIfFn ||= vi.fn(() => {
const n2 = t1()
renderEffect(() => {
setElementText(n2, count.value)
})
return n2
})),
// v-else
(spyElseFn ||= vi.fn(() => {
const n4 = t2()
return n4
})),
),
n0 as any as ParentNode,
)
return n0
}).render()
expect(host.innerHTML).toBe('')
expect(spyConditionFn).toHaveBeenCalledTimes(1)
expect(spyIfFn!).toHaveBeenCalledTimes(0)
expect(spyElseFn!).toHaveBeenCalledTimes(1)
count.value++
await nextTick()
expect(host.innerHTML).toBe('')
expect(spyConditionFn).toHaveBeenCalledTimes(2)
expect(spyIfFn!).toHaveBeenCalledTimes(1)
expect(spyElseFn!).toHaveBeenCalledTimes(1)
count.value++
await nextTick()
expect(host.innerHTML).toBe('')
expect(spyConditionFn).toHaveBeenCalledTimes(3)
expect(spyIfFn!).toHaveBeenCalledTimes(1)
expect(spyElseFn!).toHaveBeenCalledTimes(1)
count.value = 0
await nextTick()
expect(host.innerHTML).toBe('')
expect(spyConditionFn).toHaveBeenCalledTimes(4)
expect(spyIfFn!).toHaveBeenCalledTimes(1)
expect(spyElseFn!).toHaveBeenCalledTimes(2)
})
test('should handle nested template', async () => {
// mock this template:
//
// Hello Vapor
//
const ok1 = ref(true)
const ok2 = ref(true)
const t0 = template('Vapor')
const t1 = template('Hello ')
const { host } = define(() => {
const n1 = createIf(
() => ok1.value,
() => {
const n2 = t1()
const n3 = createIf(
() => ok2.value,
() => {
const n4 = t0()
return n4
},
)
return [n2, n3]
},
)
return n1
}).render()
expect(host.innerHTML).toBe('Hello Vapor')
ok1.value = false
await nextTick()
expect(host.innerHTML).toBe('')
ok1.value = true
await nextTick()
expect(host.innerHTML).toBe('Hello Vapor')
ok2.value = false
await nextTick()
expect(host.innerHTML).toBe('Hello ')
ok1.value = false
await nextTick()
expect(host.innerHTML).toBe('')
})
test.todo('should work with directive hooks', async () => {
const calls: string[] = []
const show1 = ref(true)
const show2 = ref(true)
const update = ref(0)
const spyConditionFn1 = vi.fn(() => show1.value)
const spyConditionFn2 = vi.fn(() => show2.value)
const vDirective: any = {
created: (el: any, { value }: any) => calls.push(`${value} created`),
beforeMount: (el: any, { value }: any) =>
calls.push(`${value} beforeMount`),
mounted: (el: any, { value }: any) => calls.push(`${value} mounted`),
beforeUpdate: (el: any, { value }: any) =>
calls.push(`${value} beforeUpdate`),
updated: (el: any, { value }: any) => calls.push(`${value} updated`),
beforeUnmount: (el: any, { value }: any) =>
calls.push(`${value} beforeUnmount`),
unmounted: (el: any, { value }: any) => calls.push(`${value} unmounted`),
}
const t0 = template('')
const { instance } = define(() => {
const n1 = createIf(
spyConditionFn1,
() => {
const n2 = t0() as ParentNode
withDirectives(child(n2), [[vDirective, () => (update.value, '1')]])
return n2
},
() =>
createIf(
spyConditionFn2,
() => {
const n2 = t0() as ParentNode
withDirectives(child(n2), [[vDirective, () => '2']])
return n2
},
() => {
const n2 = t0() as ParentNode
withDirectives(child(n2), [[vDirective, () => '3']])
return n2
},
),
)
return [n1]
}).render()
await nextTick()
expect(calls).toEqual(['1 created', '1 beforeMount', '1 mounted'])
calls.length = 0
expect(spyConditionFn1).toHaveBeenCalledTimes(1)
expect(spyConditionFn2).toHaveBeenCalledTimes(0)
show1.value = false
await nextTick()
expect(calls).toEqual([
'1 beforeUnmount',
'2 created',
'2 beforeMount',
'1 unmounted',
'2 mounted',
])
calls.length = 0
expect(spyConditionFn1).toHaveBeenCalledTimes(2)
expect(spyConditionFn2).toHaveBeenCalledTimes(1)
show2.value = false
await nextTick()
expect(calls).toEqual([
'2 beforeUnmount',
'3 created',
'3 beforeMount',
'2 unmounted',
'3 mounted',
])
calls.length = 0
expect(spyConditionFn1).toHaveBeenCalledTimes(2)
expect(spyConditionFn2).toHaveBeenCalledTimes(2)
show1.value = true
await nextTick()
expect(calls).toEqual([
'3 beforeUnmount',
'1 created',
'1 beforeMount',
'3 unmounted',
'1 mounted',
])
calls.length = 0
expect(spyConditionFn1).toHaveBeenCalledTimes(3)
expect(spyConditionFn2).toHaveBeenCalledTimes(2)
update.value++
await nextTick()
expect(calls).toEqual(['1 beforeUpdate', '1 updated'])
calls.length = 0
expect(spyConditionFn1).toHaveBeenCalledTimes(3)
expect(spyConditionFn2).toHaveBeenCalledTimes(2)
unmountComponent(instance!)
expect(calls).toEqual(['1 beforeUnmount', '1 unmounted'])
expect(spyConditionFn1).toHaveBeenCalledTimes(3)
expect(spyConditionFn2).toHaveBeenCalledTimes(2)
})
})