|
|
@ -1641,6 +1641,141 @@ describe('Suspense', () => { |
|
|
|
expect(serializeInner(root)).toBe(expected) |
|
|
|
}) |
|
|
|
|
|
|
|
//#8678
|
|
|
|
test('nested suspense (child suspense update before parent suspense resolve)', async () => { |
|
|
|
const calls: string[] = [] |
|
|
|
|
|
|
|
const InnerA = defineAsyncComponent( |
|
|
|
{ |
|
|
|
setup: () => { |
|
|
|
calls.push('innerA created') |
|
|
|
onMounted(() => { |
|
|
|
calls.push('innerA mounted') |
|
|
|
}) |
|
|
|
return () => h('div', 'innerA') |
|
|
|
}, |
|
|
|
}, |
|
|
|
10, |
|
|
|
) |
|
|
|
|
|
|
|
const InnerB = defineAsyncComponent( |
|
|
|
{ |
|
|
|
setup: () => { |
|
|
|
calls.push('innerB created') |
|
|
|
onMounted(() => { |
|
|
|
calls.push('innerB mounted') |
|
|
|
}) |
|
|
|
return () => h('div', 'innerB') |
|
|
|
}, |
|
|
|
}, |
|
|
|
10, |
|
|
|
) |
|
|
|
|
|
|
|
const OuterA = defineAsyncComponent( |
|
|
|
{ |
|
|
|
setup: (_, { slots }: any) => { |
|
|
|
calls.push('outerA created') |
|
|
|
onMounted(() => { |
|
|
|
calls.push('outerA mounted') |
|
|
|
}) |
|
|
|
return () => |
|
|
|
h(Fragment, null, [h('div', 'outerA'), slots.default?.()]) |
|
|
|
}, |
|
|
|
}, |
|
|
|
5, |
|
|
|
) |
|
|
|
|
|
|
|
const OuterB = defineAsyncComponent( |
|
|
|
{ |
|
|
|
setup: (_, { slots }: any) => { |
|
|
|
calls.push('outerB created') |
|
|
|
onMounted(() => { |
|
|
|
calls.push('outerB mounted') |
|
|
|
}) |
|
|
|
return () => |
|
|
|
h(Fragment, null, [h('div', 'outerB'), slots.default?.()]) |
|
|
|
}, |
|
|
|
}, |
|
|
|
5, |
|
|
|
) |
|
|
|
|
|
|
|
const outerToggle = ref(false) |
|
|
|
const innerToggle = ref(false) |
|
|
|
|
|
|
|
/** |
|
|
|
* <Suspense> |
|
|
|
* <component :is="outerToggle ? outerB : outerA"> |
|
|
|
* <Suspense> |
|
|
|
* <component :is="innerToggle ? innerB : innerA" /> |
|
|
|
* </Suspense> |
|
|
|
* </component> |
|
|
|
* </Suspense> |
|
|
|
*/ |
|
|
|
const Comp = { |
|
|
|
setup() { |
|
|
|
return () => |
|
|
|
h(Suspense, null, { |
|
|
|
default: [ |
|
|
|
h(outerToggle.value ? OuterB : OuterA, null, { |
|
|
|
default: () => |
|
|
|
h(Suspense, null, { |
|
|
|
default: h(innerToggle.value ? InnerB : InnerA), |
|
|
|
}), |
|
|
|
}), |
|
|
|
], |
|
|
|
fallback: h('div', 'fallback outer'), |
|
|
|
}) |
|
|
|
}, |
|
|
|
} |
|
|
|
|
|
|
|
const root = nodeOps.createElement('div') |
|
|
|
render(h(Comp), root) |
|
|
|
expect(serializeInner(root)).toBe(`<div>fallback outer</div>`) |
|
|
|
|
|
|
|
// mount outer component
|
|
|
|
await Promise.all(deps) |
|
|
|
await nextTick() |
|
|
|
|
|
|
|
expect(serializeInner(root)).toBe(`<div>outerA</div><!---->`) |
|
|
|
expect(calls).toEqual([`outerA created`, `outerA mounted`]) |
|
|
|
|
|
|
|
// mount inner component
|
|
|
|
await Promise.all(deps) |
|
|
|
await nextTick() |
|
|
|
expect(serializeInner(root)).toBe(`<div>outerA</div><div>innerA</div>`) |
|
|
|
|
|
|
|
expect(calls).toEqual([ |
|
|
|
'outerA created', |
|
|
|
'outerA mounted', |
|
|
|
'innerA created', |
|
|
|
'innerA mounted', |
|
|
|
]) |
|
|
|
|
|
|
|
calls.length = 0 |
|
|
|
deps.length = 0 |
|
|
|
|
|
|
|
// toggle both outer and inner components
|
|
|
|
outerToggle.value = true |
|
|
|
innerToggle.value = true |
|
|
|
await nextTick() |
|
|
|
|
|
|
|
await Promise.all(deps) |
|
|
|
await nextTick() |
|
|
|
expect(serializeInner(root)).toBe(`<div>outerB</div><!---->`) |
|
|
|
|
|
|
|
await Promise.all(deps) |
|
|
|
await nextTick() |
|
|
|
expect(serializeInner(root)).toBe(`<div>outerB</div><div>innerB</div>`) |
|
|
|
|
|
|
|
// innerB only mount once
|
|
|
|
expect(calls).toEqual([ |
|
|
|
'outerB created', |
|
|
|
'outerB mounted', |
|
|
|
'innerB created', |
|
|
|
'innerB mounted', |
|
|
|
]) |
|
|
|
}) |
|
|
|
|
|
|
|
// #6416
|
|
|
|
test('KeepAlive with Suspense', async () => { |
|
|
|
const Async = defineAsyncComponent({ |
|
|
|