Browse Source

test(hmr): add test for reloading deactivated KeepAlive child

daiwei 1 month ago
parent
commit
bad6ec4081
1 changed files with 95 additions and 0 deletions
  1. 95 0
      packages/runtime-vapor/__tests__/hmr.spec.ts

+ 95 - 0
packages/runtime-vapor/__tests__/hmr.spec.ts

@@ -286,6 +286,101 @@ describe('hot module replacement', () => {
     expect(deactivatedSpy).toHaveBeenCalledTimes(1)
   })
 
+  test('reload deactivated KeepAlive child', async () => {
+    const root = document.createElement('div')
+    document.body.appendChild(root)
+    const childId = 'test-child-keep-alive-deactivated'
+    const oldUnmountSpy = vi.fn()
+    const oldActiveSpy = vi.fn()
+    const oldDeactivatedSpy = vi.fn()
+    const newUnmountSpy = vi.fn()
+    const newMountSpy = vi.fn()
+    const newActiveSpy = vi.fn()
+    const newDeactivatedSpy = vi.fn()
+
+    const Child = defineVaporComponent({
+      __hmrId: childId,
+      setup() {
+        onUnmounted(oldUnmountSpy)
+        onActivated(oldActiveSpy)
+        onDeactivated(oldDeactivatedSpy)
+        const count = ref(0)
+        return { count }
+      },
+      render: compileToFunction(`<div>{{ count }}</div>`),
+    })
+    createRecord(childId, Child as any)
+
+    const Parent = defineVaporComponent({
+      __hmrId: 'parentId-keep-alive-deactivated',
+      components: { Child },
+      setup() {
+        const toggle = ref(true)
+        return { toggle }
+      },
+      render: compileToFunction(
+        `<button @click="toggle = !toggle" />
+        <KeepAlive><Child v-if="toggle" /></KeepAlive>`,
+      ),
+    })
+
+    define(Parent).create().mount(root)
+    expect(root.innerHTML).toBe(`<button></button><div>0</div><!--if-->`)
+    expect(oldActiveSpy).toHaveBeenCalledTimes(1)
+    expect(oldDeactivatedSpy).toHaveBeenCalledTimes(0)
+    expect(oldUnmountSpy).toHaveBeenCalledTimes(0)
+
+    // deactivate and move child into KeepAlive cache
+    triggerEvent('click', root.children[0] as Element)
+    await nextTick()
+    expect(root.innerHTML).toBe(`<button></button><!--if-->`)
+    expect(oldDeactivatedSpy).toHaveBeenCalledTimes(1)
+    expect(oldUnmountSpy).toHaveBeenCalledTimes(0)
+
+    // reload while child is cached but inactive
+    reload(childId, {
+      __hmrId: childId,
+      __vapor: true,
+      setup() {
+        onMounted(newMountSpy)
+        onUnmounted(newUnmountSpy)
+        onActivated(newActiveSpy)
+        onDeactivated(newDeactivatedSpy)
+        const count = ref(1)
+        return { count }
+      },
+      render: compileToFunction(`<div>{{ count }}</div>`),
+    })
+    await nextTick()
+    expect(root.innerHTML).toBe(`<button></button><!--if-->`)
+    // old cached instance should be unmounted during KeepAlive HMR rerender
+    expect(oldUnmountSpy).toHaveBeenCalledTimes(1)
+
+    // re-activate should render the new component instance
+    triggerEvent('click', root.children[0] as Element)
+    await nextTick()
+    expect(root.innerHTML).toBe(`<button></button><div>1</div><!--if-->`)
+    expect(newMountSpy).toHaveBeenCalledTimes(1)
+    expect(newActiveSpy).toHaveBeenCalledTimes(1)
+    expect(newDeactivatedSpy).toHaveBeenCalledTimes(0)
+
+    // subsequent toggles should use KeepAlive cache for the new instance
+    triggerEvent('click', root.children[0] as Element)
+    await nextTick()
+    expect(root.innerHTML).toBe(`<button></button><!--if-->`)
+    expect(newMountSpy).toHaveBeenCalledTimes(1)
+    expect(newActiveSpy).toHaveBeenCalledTimes(1)
+    expect(newDeactivatedSpy).toHaveBeenCalledTimes(1)
+
+    triggerEvent('click', root.children[0] as Element)
+    await nextTick()
+    expect(root.innerHTML).toBe(`<button></button><div>1</div><!--if-->`)
+    expect(newMountSpy).toHaveBeenCalledTimes(1)
+    expect(newActiveSpy).toHaveBeenCalledTimes(2)
+    expect(newDeactivatedSpy).toHaveBeenCalledTimes(1)
+    expect(newUnmountSpy).toHaveBeenCalledTimes(0)
+  })
+
   test('reload KeepAlive slot in Transition', async () => {
     const root = document.createElement('div')
     document.body.appendChild(root)