diff --git a/packages/runtime-vapor/__tests__/componentSlots.spec.ts b/packages/runtime-vapor/__tests__/componentSlots.spec.ts index db2171b583a..33b7f7f2f2f 100644 --- a/packages/runtime-vapor/__tests__/componentSlots.spec.ts +++ b/packages/runtime-vapor/__tests__/componentSlots.spec.ts @@ -103,41 +103,6 @@ describe('component: slots', () => { expect(instance.slots).toHaveProperty('two') }) - test('should work with createFlorSlots', async () => { - const loop = ref([1, 2, 3]) - - let instance: any - const Child = () => { - instance = currentInstance - return template('child')() - } - - const { render } = define({ - setup() { - return createComponent(Child, null, { - $: [ - () => - createForSlots(loop.value, (item, i) => ({ - name: item, - fn: () => template(item + i)(), - })), - ], - }) - }, - }) - render() - - expect(instance.slots).toHaveProperty('1') - expect(instance.slots).toHaveProperty('2') - expect(instance.slots).toHaveProperty('3') - loop.value.push(4) - await nextTick() - expect(instance.slots).toHaveProperty('4') - loop.value.shift() - await nextTick() - expect(instance.slots).not.toHaveProperty('1') - }) - // passes but no warning for slot invocation in vapor currently test.todo('should not warn when mounting another app in setup', () => { const Comp = defineVaporComponent({ @@ -1936,4 +1901,184 @@ describe('component: slots', () => { }) }) }) + + describe('createForSlots', () => { + test('should work', async () => { + const loop = ref([1, 2, 3]) + + let instance: any + const Child = () => { + instance = currentInstance + return template('child')() + } + + const { render } = define({ + setup() { + return createComponent(Child, null, { + $: [ + () => + createForSlots(loop.value, (item, i) => ({ + name: item, + fn: () => template(item + i)(), + })), + ], + }) + }, + }) + render() + + expect(instance.slots).toHaveProperty('1') + expect(instance.slots).toHaveProperty('2') + expect(instance.slots).toHaveProperty('3') + loop.value.push(4) + await nextTick() + expect(instance.slots).toHaveProperty('4') + loop.value.shift() + await nextTick() + expect(instance.slots).not.toHaveProperty('1') + }) + + test('should cache dynamic slot source result', async () => { + const items = ref([1, 2, 3]) + let callCount = 0 + + const getItems = () => { + callCount++ + return items.value + } + + let instance: any + const Child = defineVaporComponent(() => { + instance = currentInstance + // Create multiple slots to trigger multiple getSlot calls + const n1 = template('
')() + const n2 = template('')() + const n3 = template('')() + insert(createSlot('slot1'), n1 as any as ParentNode) + insert(createSlot('slot2'), n2 as any as ParentNode) + insert(createSlot('slot3'), n3 as any as ParentNode) + return [n1, n2, n3] + }) + + define({ + setup() { + return createComponent(Child, null, { + $: [ + () => + createForSlots(getItems(), (item, i) => ({ + name: 'slot' + item, + fn: () => template(String(item))(), + })), + ], + }) + }, + }).render() + + // getItems should only be called once + expect(callCount).toBe(1) + + expect(instance.slots).toHaveProperty('slot1') + expect(instance.slots).toHaveProperty('slot2') + expect(instance.slots).toHaveProperty('slot3') + }) + + test('should update when source changes', async () => { + const items = ref([1, 2]) + let callCount = 0 + + const getItems = () => { + callCount++ + return items.value + } + + let instance: any + const Child = defineVaporComponent(() => { + instance = currentInstance + const n1 = template('')() + const n2 = template('')() + const n3 = template('')() + insert(createSlot('slot1'), n1 as any as ParentNode) + insert(createSlot('slot2'), n2 as any as ParentNode) + insert(createSlot('slot3'), n3 as any as ParentNode) + return [n1, n2, n3] + }) + + define({ + setup() { + return createComponent(Child, null, { + $: [ + () => + createForSlots(getItems(), (item, i) => ({ + name: 'slot' + item, + fn: () => template(String(item))(), + })), + ], + }) + }, + }).render() + + expect(callCount).toBe(1) + expect(instance.slots).toHaveProperty('slot1') + expect(instance.slots).toHaveProperty('slot2') + expect(instance.slots).not.toHaveProperty('slot3') + + // Update items + items.value.push(3) + await nextTick() + + // Should be called again after source changes + expect(callCount).toBe(2) + expect(instance.slots).toHaveProperty('slot1') + expect(instance.slots).toHaveProperty('slot2') + expect(instance.slots).toHaveProperty('slot3') + }) + + test('should render slots correctly with caching', async () => { + const items = ref([1, 2, 3, 4, 5]) + + const Child = defineVaporComponent(() => { + const containers: any[] = [] + for (let i = 1; i <= 5; i++) { + const n = template('')() + insert(createSlot('slot' + i), n as any as ParentNode) + containers.push(n) + } + return containers + }) + + const { host } = define({ + setup() { + return createComponent(Child, null, { + $: [ + () => + createForSlots(items.value, item => ({ + name: 'slot' + item, + fn: () => template('content' + item)(), + })), + ], + }) + }, + }).render() + + expect(host.innerHTML).toBe( + '