]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test(runtime-core): add tests for componentSlots (#1940)
authorPick <picknight@foxmail.com>
Wed, 26 Aug 2020 16:17:21 +0000 (00:17 +0800)
committerGitHub <noreply@github.com>
Wed, 26 Aug 2020 16:17:21 +0000 (12:17 -0400)
packages/runtime-core/__tests__/componentSlots.spec.ts

index ee856820cb6dd5bc059074a9474d0fba4a08536c..ecb548f210cfd7a669946edcd093543a17c756a8 100644 (file)
@@ -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)