From d0cc4b37d0f0b2d6d20764386cc715bc0ed1ee8a Mon Sep 17 00:00:00 2001 From: Pick Date: Thu, 27 Aug 2020 00:17:21 +0800 Subject: [PATCH] test(runtime-core): add tests for componentSlots (#1940) --- .../__tests__/componentSlots.spec.ts | 198 +++++++++++++++++- 1 file changed, 196 insertions(+), 2 deletions(-) diff --git a/packages/runtime-core/__tests__/componentSlots.spec.ts b/packages/runtime-core/__tests__/componentSlots.spec.ts index ee856820..ecb548f2 100644 --- a/packages/runtime-core/__tests__/componentSlots.spec.ts +++ b/packages/runtime-core/__tests__/componentSlots.spec.ts @@ -1,7 +1,201 @@ -import { ref, render, h, nodeOps, nextTick } from '@vue/runtime-test' +import { + ref, + render, + h, + nodeOps, + nextTick, + getCurrentInstance +} from '@vue/runtime-test' +import { normalizeVNode } from '../src/vnode' +import { createSlots } from '../src/helpers/createSlots' describe('component: slots', () => { - // TODO more tests for slots normalization etc. + function renderWithSlots(slots: any): any { + let instance: any + const Comp = { + render() { + instance = getCurrentInstance() + return h('div') + } + } + + render(h(Comp, null, slots), nodeOps.createElement('div')) + return instance + } + + test('initSlots: instance.slots should be set correctly', () => { + const { slots } = renderWithSlots({ _: 1 }) + expect(slots).toMatchObject({ _: 1 }) + }) + + test('initSlots: should normalize object slots (when value is null, string, array)', () => { + const { slots } = renderWithSlots({ + _inner: '_inner', + foo: null, + header: 'header', + footer: ['f1', 'f2'] + }) + + expect( + '[Vue warn]: Non-function value encountered for slot "header". Prefer function slots for better performance.' + ).toHaveBeenWarned() + + expect( + '[Vue warn]: Non-function value encountered for slot "footer". Prefer function slots for better performance.' + ).toHaveBeenWarned() + + expect(slots).not.toHaveProperty('_inner') + expect(slots).not.toHaveProperty('foo') + expect(slots.header()).toMatchObject([normalizeVNode('header')]) + expect(slots.footer()).toMatchObject([ + normalizeVNode('f1'), + normalizeVNode('f2') + ]) + }) + + test('initSlots: should normalize object slots (when value is function)', () => { + let proxy: any + const Comp = { + render() { + proxy = getCurrentInstance() + return h('div') + } + } + + render( + h(Comp, null, { + header: () => 'header' + }), + nodeOps.createElement('div') + ) + + expect(proxy.slots.header()).toMatchObject([normalizeVNode('header')]) + }) + + test('initSlots: instance.slots should be set correctly (when vnode.shapeFlag is not SLOTS_CHILDREN)', () => { + const { slots } = renderWithSlots([h('span')]) + + expect( + '[Vue warn]: Non-function value encountered for default slot. Prefer function slots for better performance.' + ).toHaveBeenWarned() + + expect(slots.default()).toMatchObject([normalizeVNode(h('span'))]) + }) + + test('updateSlots: instance.slots should be update correctly (when slotType is number)', async () => { + const flag1 = ref(true) + + let instance: any + const Child = () => { + instance = getCurrentInstance() + return 'child' + } + + const Comp = { + setup() { + return () => [ + h( + Child, + null, + createSlots({ _: 2 as any }, [ + flag1.value + ? { + name: 'one', + fn: () => [h('span')] + } + : { + name: 'two', + fn: () => [h('div')] + } + ]) + ) + ] + } + } + render(h(Comp), nodeOps.createElement('div')) + + expect(instance.slots).toHaveProperty('one') + expect(instance.slots).not.toHaveProperty('two') + + flag1.value = false + await nextTick() + + expect(instance.slots).not.toHaveProperty('one') + expect(instance.slots).toHaveProperty('two') + }) + + test('updateSlots: instance.slots should be update correctly (when slotType is null)', async () => { + const flag1 = ref(true) + + let instance: any + const Child = () => { + instance = getCurrentInstance() + return 'child' + } + + const oldSlots = { + header: 'header' + } + const newSlots = { + footer: 'footer' + } + + const Comp = { + setup() { + return () => [ + h(Child, { n: flag1.value }, flag1.value ? oldSlots : newSlots) + ] + } + } + render(h(Comp), nodeOps.createElement('div')) + + expect(instance.slots).toHaveProperty('header') + expect(instance.slots).not.toHaveProperty('footer') + + flag1.value = false + await nextTick() + + expect( + '[Vue warn]: Non-function value encountered for slot "header". Prefer function slots for better performance.' + ).toHaveBeenWarned() + + expect( + '[Vue warn]: Non-function value encountered for slot "footer". Prefer function slots for better performance.' + ).toHaveBeenWarned() + + expect(instance.slots).not.toHaveProperty('header') + expect(instance.slots.footer()).toMatchObject([normalizeVNode('footer')]) + }) + + test('updateSlots: instance.slots should be update correctly (when vnode.shapeFlag is not SLOTS_CHILDREN)', async () => { + const flag1 = ref(true) + + let instance: any + const Child = () => { + instance = getCurrentInstance() + return 'child' + } + + const Comp = { + setup() { + return () => [ + h(Child, { n: flag1.value }, flag1.value ? ['header'] : ['footer']) + ] + } + } + render(h(Comp), nodeOps.createElement('div')) + + expect(instance.slots.default()).toMatchObject([normalizeVNode('header')]) + + flag1.value = false + await nextTick() + + expect( + '[Vue warn]: Non-function value encountered for default slot. Prefer function slots for better performance.' + ).toHaveBeenWarned() + + expect(instance.slots.default()).toMatchObject([normalizeVNode('footer')]) + }) test('should respect $stable flag', async () => { const flag1 = ref(1)