|
@@ -26,6 +26,7 @@ import {
|
|
|
shallowRef,
|
|
shallowRef,
|
|
|
} from '@vue/runtime-test'
|
|
} from '@vue/runtime-test'
|
|
|
import type { KeepAliveProps } from '../../src/components/KeepAlive'
|
|
import type { KeepAliveProps } from '../../src/components/KeepAlive'
|
|
|
|
|
+import { queuePostFlushCb } from '../../src/scheduler'
|
|
|
|
|
|
|
|
const timeout = (n: number = 0) => new Promise(r => setTimeout(r, n))
|
|
const timeout = (n: number = 0) => new Promise(r => setTimeout(r, n))
|
|
|
|
|
|
|
@@ -431,6 +432,74 @@ describe('KeepAlive', () => {
|
|
|
expect(serializeInner(root)).toBe(`<main>C</main>`)
|
|
expect(serializeInner(root)).toBe(`<main>C</main>`)
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
|
|
+ test('should keep deferred branch updates pending when re-activation is immediately reversed', async () => {
|
|
|
|
|
+ const mountedA = vi.fn()
|
|
|
|
|
+ const mountedB = vi.fn()
|
|
|
|
|
+ const visible = ref(true)
|
|
|
|
|
+
|
|
|
|
|
+ const A = defineComponent({
|
|
|
|
|
+ name: 'A',
|
|
|
|
|
+ setup() {
|
|
|
|
|
+ onMounted(mountedA)
|
|
|
|
|
+ return () => h('span', 'Comp A')
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const B = defineComponent({
|
|
|
|
|
+ name: 'B',
|
|
|
|
|
+ setup() {
|
|
|
|
|
+ onMounted(mountedB)
|
|
|
|
|
+ return () => h('span', 'Comp B')
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const comp = shallowRef(A)
|
|
|
|
|
+ const Home = defineComponent({
|
|
|
|
|
+ name: 'Home',
|
|
|
|
|
+ setup() {
|
|
|
|
|
+ return () => h('main', [h(KeepAlive, null, [h(comp.value)])])
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ const App = defineComponent({
|
|
|
|
|
+ setup() {
|
|
|
|
|
+ return () => h(KeepAlive, null, [visible.value ? h(Home) : null])
|
|
|
|
|
+ },
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ render(h(App), root)
|
|
|
|
|
+ expect(serializeInner(root)).toBe(`<main><span>Comp A</span></main>`)
|
|
|
|
|
+ expect(mountedA).toHaveBeenCalledTimes(1)
|
|
|
|
|
+ expect(mountedB).toHaveBeenCalledTimes(0)
|
|
|
|
|
+
|
|
|
|
|
+ visible.value = false
|
|
|
|
|
+ await nextTick()
|
|
|
|
|
+ expect(serializeInner(root)).toBe(`<!---->`)
|
|
|
|
|
+
|
|
|
|
|
+ comp.value = B
|
|
|
|
|
+ await nextTick()
|
|
|
|
|
+ expect(serializeInner(root)).toBe(`<!---->`)
|
|
|
|
|
+ expect(mountedB).toHaveBeenCalledTimes(0)
|
|
|
|
|
+
|
|
|
|
|
+ const deactivateAfterActivate = vi.fn(() => {
|
|
|
|
|
+ visible.value = false
|
|
|
|
|
+ }) as any
|
|
|
|
|
+ deactivateAfterActivate.id = -1
|
|
|
|
|
+
|
|
|
|
|
+ visible.value = true
|
|
|
|
|
+ queuePostFlushCb(deactivateAfterActivate)
|
|
|
|
|
+ await nextTick()
|
|
|
|
|
+
|
|
|
|
|
+ expect(serializeInner(root)).toBe(`<!---->`)
|
|
|
|
|
+ expect(deactivateAfterActivate).toHaveBeenCalledTimes(1)
|
|
|
|
|
+ expect(mountedB).toHaveBeenCalledTimes(0)
|
|
|
|
|
+
|
|
|
|
|
+ visible.value = true
|
|
|
|
|
+ await nextTick()
|
|
|
|
|
+ expect(serializeInner(root)).toBe(`<main><span>Comp B</span></main>`)
|
|
|
|
|
+ expect(mountedB).toHaveBeenCalledTimes(1)
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
async function assertNameMatch(props: KeepAliveProps) {
|
|
async function assertNameMatch(props: KeepAliveProps) {
|
|
|
const outerRef = ref(true)
|
|
const outerRef = ref(true)
|
|
|
const viewRef = ref('one')
|
|
const viewRef = ref('one')
|