]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: port tests
authordaiwei <daiwei521@126.com>
Wed, 9 Apr 2025 13:47:00 +0000 (21:47 +0800)
committerdaiwei <daiwei521@126.com>
Wed, 9 Apr 2025 13:47:00 +0000 (21:47 +0800)
packages/runtime-vapor/__tests__/components/KeepAlive.spec.ts
packages/runtime-vapor/src/components/KeepAlive.ts

index 4cd8727f009e6bdc0112ad1bb41b65dab366084e..ae0bf090e24778d858b408774a4cf76c507bf458 100644 (file)
@@ -7,7 +7,7 @@ import {
   onUnmounted,
   ref,
 } from 'vue'
-import type { VaporComponent } from '../../src/component'
+import type { LooseRawProps, VaporComponent } from '../../src/component'
 import { makeRender } from '../_utils'
 import { VaporKeepAliveImpl as VaporKeepAlive } from '../../src/components/KeepAlive'
 import {
@@ -70,6 +70,13 @@ describe('VaporKeepAlive', () => {
         return n0
       },
     })
+    oneTestHooks = {
+      beforeMount: vi.fn(),
+      mounted: vi.fn(),
+      activated: vi.fn(),
+      deactivated: vi.fn(),
+      unmounted: vi.fn(),
+    }
     oneTest = defineVaporComponent({
       name: 'oneTest',
       setup() {
@@ -469,4 +476,215 @@ describe('VaporKeepAlive', () => {
     assertHookCalls(oneHooks, [1, 1, 4, 3, 0])
     assertHookCalls(twoHooks, [1, 1, 4, 4, 0]) // should remain inactive
   })
+
+  async function assertNameMatch(props: LooseRawProps) {
+    const outerRef = ref(true)
+    const viewRef = ref('one')
+    const { html } = define({
+      setup() {
+        return createIf(
+          () => outerRef.value,
+          () =>
+            createComponent(VaporKeepAlive, props, {
+              default: () => createDynamicComponent(() => views[viewRef.value]),
+            }),
+        )
+      },
+    }).render()
+
+    expect(html()).toBe(`<div>one</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 1, 0, 0])
+    assertHookCalls(twoHooks, [0, 0, 0, 0, 0])
+
+    viewRef.value = 'two'
+    await nextTick()
+    expect(html()).toBe(`<div>two</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 1, 1, 0])
+    assertHookCalls(twoHooks, [1, 1, 0, 0, 0])
+
+    viewRef.value = 'one'
+    await nextTick()
+    expect(html()).toBe(`<div>one</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 2, 1, 0])
+    assertHookCalls(twoHooks, [1, 1, 0, 0, 1])
+
+    viewRef.value = 'two'
+    await nextTick()
+    expect(html()).toBe(`<div>two</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 2, 2, 0])
+    assertHookCalls(twoHooks, [2, 2, 0, 0, 1])
+
+    // teardown
+    outerRef.value = false
+    await nextTick()
+    expect(html()).toBe(`<!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 2, 2, 1])
+    assertHookCalls(twoHooks, [2, 2, 0, 0, 2])
+  }
+
+  async function assertNameMatchWithFlag(props: LooseRawProps) {
+    const outerRef = ref(true)
+    const viewRef = ref('one')
+    const { html } = define({
+      setup() {
+        return createIf(
+          () => outerRef.value,
+          () =>
+            createComponent(VaporKeepAlive, props, {
+              default: () => createDynamicComponent(() => views[viewRef.value]),
+            }),
+        )
+      },
+    }).render()
+
+    expect(html()).toBe(`<div>one</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 1, 0, 0])
+    assertHookCalls(oneTestHooks, [0, 0, 0, 0, 0])
+    assertHookCalls(twoHooks, [0, 0, 0, 0, 0])
+
+    viewRef.value = 'oneTest'
+    await nextTick()
+    expect(html()).toBe(`<div>oneTest</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 1, 1, 0])
+    assertHookCalls(oneTestHooks, [1, 1, 1, 0, 0])
+    assertHookCalls(twoHooks, [0, 0, 0, 0, 0])
+
+    viewRef.value = 'two'
+    await nextTick()
+    expect(html()).toBe(`<div>two</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 1, 1, 0])
+    assertHookCalls(oneTestHooks, [1, 1, 1, 1, 0])
+    assertHookCalls(twoHooks, [1, 1, 0, 0, 0])
+
+    viewRef.value = 'one'
+    await nextTick()
+    expect(html()).toBe(`<div>one</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 2, 1, 0])
+    assertHookCalls(oneTestHooks, [1, 1, 1, 1, 0])
+    assertHookCalls(twoHooks, [1, 1, 0, 0, 1])
+
+    viewRef.value = 'oneTest'
+    await nextTick()
+    expect(html()).toBe(`<div>oneTest</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 2, 2, 0])
+    assertHookCalls(oneTestHooks, [1, 1, 2, 1, 0])
+    assertHookCalls(twoHooks, [1, 1, 0, 0, 1])
+
+    viewRef.value = 'two'
+    await nextTick()
+    expect(html()).toBe(`<div>two</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 2, 2, 0])
+    assertHookCalls(oneTestHooks, [1, 1, 2, 2, 0])
+    assertHookCalls(twoHooks, [2, 2, 0, 0, 1])
+
+    // teardown
+    outerRef.value = false
+    await nextTick()
+    expect(html()).toBe(`<!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 2, 2, 1])
+    assertHookCalls(oneTestHooks, [1, 1, 2, 2, 1])
+    assertHookCalls(twoHooks, [2, 2, 0, 0, 2])
+  }
+
+  async function assertNameMatchWithFlagExclude(props: LooseRawProps) {
+    const outerRef = ref(true)
+    const viewRef = ref('one')
+    const { html } = define({
+      setup() {
+        return createIf(
+          () => outerRef.value,
+          () =>
+            createComponent(VaporKeepAlive, props, {
+              default: () => createDynamicComponent(() => views[viewRef.value]),
+            }),
+        )
+      },
+    }).render()
+
+    expect(html()).toBe(`<div>one</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 0, 0, 0])
+    assertHookCalls(oneTestHooks, [0, 0, 0, 0, 0])
+    assertHookCalls(twoHooks, [0, 0, 0, 0, 0])
+
+    viewRef.value = 'oneTest'
+    await nextTick()
+    expect(html()).toBe(`<div>oneTest</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 0, 0, 1])
+    assertHookCalls(oneTestHooks, [1, 1, 0, 0, 0])
+    assertHookCalls(twoHooks, [0, 0, 0, 0, 0])
+
+    viewRef.value = 'two'
+    await nextTick()
+    expect(html()).toBe(`<div>two</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [1, 1, 0, 0, 1])
+    assertHookCalls(oneTestHooks, [1, 1, 0, 0, 1])
+    assertHookCalls(twoHooks, [1, 1, 1, 0, 0])
+
+    viewRef.value = 'one'
+    await nextTick()
+    expect(html()).toBe(`<div>one</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [2, 2, 0, 0, 1])
+    assertHookCalls(oneTestHooks, [1, 1, 0, 0, 1])
+    assertHookCalls(twoHooks, [1, 1, 1, 1, 0])
+
+    viewRef.value = 'oneTest'
+    await nextTick()
+    expect(html()).toBe(`<div>oneTest</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [2, 2, 0, 0, 2])
+    assertHookCalls(oneTestHooks, [2, 2, 0, 0, 1])
+    assertHookCalls(twoHooks, [1, 1, 1, 1, 0])
+
+    viewRef.value = 'two'
+    await nextTick()
+    expect(html()).toBe(`<div>two</div><!--dynamic-component--><!--if-->`)
+    assertHookCalls(oneHooks, [2, 2, 0, 0, 2])
+    assertHookCalls(oneTestHooks, [2, 2, 0, 0, 2])
+    assertHookCalls(twoHooks, [1, 1, 2, 1, 0])
+
+    // teardown
+    outerRef.value = false
+    await nextTick()
+    expect(html()).toBe(`<!--if-->`)
+    assertHookCalls(oneHooks, [2, 2, 0, 0, 2])
+    assertHookCalls(oneTestHooks, [2, 2, 0, 0, 2])
+    assertHookCalls(twoHooks, [1, 1, 2, 2, 1])
+  }
+
+  describe('props', () => {
+    test('include (string)', async () => {
+      await assertNameMatch({ include: () => 'one' })
+    })
+
+    test('include (regex)', async () => {
+      await assertNameMatch({ include: () => /^one$/ })
+    })
+
+    test('include (regex with g flag)', async () => {
+      await assertNameMatchWithFlag({ include: () => /one/g })
+    })
+
+    test('include (array)', async () => {
+      await assertNameMatch({ include: () => ['one'] })
+    })
+
+    test('exclude (string)', async () => {
+      await assertNameMatch({ exclude: () => 'two' })
+    })
+
+    test('exclude (regex)', async () => {
+      await assertNameMatch({ exclude: () => /^two$/ })
+    })
+
+    test('exclude (regex with a flag)', async () => {
+      await assertNameMatchWithFlagExclude({ exclude: () => /one/g })
+    })
+
+    test('exclude (array)', async () => {
+      await assertNameMatch({ exclude: () => ['two'] })
+    })
+
+    test('include + exclude', async () => {
+      await assertNameMatch({ include: () => 'one,two', exclude: () => 'two' })
+    })
+  })
 })
index f40a508a57a2830176c4cfc215c574b1374f17a9..45844180a0474a2b2169fc078aa549ecd2efb4f2 100644 (file)
@@ -64,13 +64,21 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
 
     const { include, exclude, max } = props
 
+    function shouldCache(instance: VaporComponentInstance) {
+      const name = getComponentName(instance.type)
+      return !(
+        (include && (!name || !matches(include, name))) ||
+        (exclude && name && matches(exclude, name))
+      )
+    }
+
     function cacheBlock() {
       // TODO suspense
       const currentBlock = keepAliveInstance.block!
       if (!isValidBlock(currentBlock)) return
 
       const block = getInnerBlock(currentBlock)!
-      if (!block) return
+      if (!block || !shouldCache(block)) return
 
       const key = block.type
       if (cache.has(key)) {
@@ -111,13 +119,16 @@ export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
         instance.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE
       }
 
-      const name = getComponentName(instance.type)
-      if (
-        !(
-          (include && (!name || !matches(include, name))) ||
-          (exclude && name && matches(exclude, name))
-        )
-      ) {
+      // const name = getComponentName(instance.type)
+      // if (
+      //   !(
+      //     (include && (!name || !matches(include, name))) ||
+      //     (exclude && name && matches(exclude, name))
+      //   )
+      // ) {
+      //   instance.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
+      // }
+      if (shouldCache(instance)) {
         instance.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
       }
     }