|
|
@@ -20,7 +20,9 @@ import {
|
|
|
onBeforeUnmount,
|
|
|
createTextVNode,
|
|
|
SetupContext,
|
|
|
- createApp
|
|
|
+ createApp,
|
|
|
+ FunctionalComponent,
|
|
|
+ renderList
|
|
|
} from '@vue/runtime-test'
|
|
|
import { PatchFlags, SlotFlags } from '@vue/shared'
|
|
|
import { SuspenseImpl } from '../src/components/Suspense'
|
|
|
@@ -821,4 +823,62 @@ describe('renderer: optimized mode', () => {
|
|
|
await nextTick()
|
|
|
expect(inner(root)).toBe('<div><div>true</div></div>')
|
|
|
})
|
|
|
+
|
|
|
+ // #3881
|
|
|
+ // root cause: fragment inside a compiled slot passed to component which
|
|
|
+ // programmatically invokes the slot. The entire slot should de-opt but
|
|
|
+ // the fragment was incorretly put in optimized mode which causes it to skip
|
|
|
+ // updates for its inner components.
|
|
|
+ test('fragments inside programmatically invoked compiled slot should de-opt properly', async () => {
|
|
|
+ const Parent: FunctionalComponent = (_, { slots }) => slots.default!()
|
|
|
+ const Dummy = () => 'dummy'
|
|
|
+
|
|
|
+ const toggle = ref(true)
|
|
|
+ const force = ref(0)
|
|
|
+
|
|
|
+ const app = createApp({
|
|
|
+ render() {
|
|
|
+ if (!toggle.value) {
|
|
|
+ return null
|
|
|
+ }
|
|
|
+ return h(
|
|
|
+ Parent,
|
|
|
+ { n: force.value },
|
|
|
+ {
|
|
|
+ default: withCtx(
|
|
|
+ () => [
|
|
|
+ createVNode('ul', null, [
|
|
|
+ (openBlock(),
|
|
|
+ createBlock(
|
|
|
+ Fragment,
|
|
|
+ null,
|
|
|
+ renderList(1, item => {
|
|
|
+ return createVNode('li', null, [createVNode(Dummy)])
|
|
|
+ }),
|
|
|
+ 64 /* STABLE_FRAGMENT */
|
|
|
+ ))
|
|
|
+ ])
|
|
|
+ ],
|
|
|
+ undefined,
|
|
|
+ true
|
|
|
+ ),
|
|
|
+ _: 1 /* STABLE */
|
|
|
+ }
|
|
|
+ )
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ app.mount(root)
|
|
|
+
|
|
|
+ // force a patch
|
|
|
+ force.value++
|
|
|
+ await nextTick()
|
|
|
+ expect(inner(root)).toBe(`<ul><li>dummy</li></ul>`)
|
|
|
+
|
|
|
+ // unmount
|
|
|
+ toggle.value = false
|
|
|
+ await nextTick()
|
|
|
+ // should successfully unmount without error
|
|
|
+ expect(inner(root)).toBe(`<!---->`)
|
|
|
+ })
|
|
|
})
|