Skip to content

Commit 3ec274b

Browse files
committed
test(render): add unit test for rendererFragment
1 parent 0f45875 commit 3ec274b

File tree

2 files changed

+124
-3
lines changed

2 files changed

+124
-3
lines changed

packages/runtime-core/__tests__/rendererFragment.spec.ts

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,13 @@ import {
1313
createTextVNode,
1414
createBlock,
1515
openBlock,
16-
createCommentVNode
16+
createCommentVNode,
17+
withCtx,
18+
createElementBlock,
19+
ref,
20+
renderSlot
1721
} from '@vue/runtime-test'
18-
import { PatchFlags } from '@vue/shared'
22+
import { PatchFlags, SlotFlags } from '@vue/shared'
1923
import { renderList } from '../src/helpers/renderList'
2024

2125
describe('renderer: fragment', () => {
@@ -351,4 +355,121 @@ describe('renderer: fragment', () => {
351355
render(renderFn(['two', 'one']), root)
352356
expect(serializeInner(root)).toBe(`text<div>two</div>text<div>one</div>`)
353357
})
358+
359+
// #9200
360+
test('stable fragment in unstable slot', () => {
361+
const root = nodeOps.createElement('div')
362+
363+
const items = ref([{ field1: 'one', field2: 'two' as string | undefined }])
364+
365+
const textBlock = 'text-block'
366+
const vIfBlock = 'v-if-block'
367+
368+
const Comp = {
369+
render(ctx: any) {
370+
return (
371+
openBlock(true),
372+
createElementBlock(
373+
Fragment,
374+
null,
375+
renderList(items.value, (item, i) => {
376+
return (
377+
openBlock(),
378+
createElementBlock('div', { key: i }, [
379+
(openBlock(true),
380+
createElementBlock(
381+
Fragment,
382+
null,
383+
renderList(['field1', 'field2'] as const, field => {
384+
return (
385+
openBlock(),
386+
createElementBlock('span', { key: field }, [
387+
renderSlot(
388+
ctx.$slots,
389+
'default',
390+
{
391+
value: item[field],
392+
field: field
393+
},
394+
() => [
395+
item[field]
396+
? (openBlock(),
397+
createElementBlock(
398+
Fragment,
399+
{ key: 0 },
400+
[createTextVNode('xxx')],
401+
PatchFlags.STABLE_FRAGMENT
402+
))
403+
: (openBlock(),
404+
createElementBlock(
405+
Fragment,
406+
{ key: 1 },
407+
[createTextVNode('yyy')],
408+
PatchFlags.STABLE_FRAGMENT
409+
))
410+
]
411+
)
412+
])
413+
)
414+
}),
415+
PatchFlags.KEYED_FRAGMENT
416+
))
417+
])
418+
)
419+
}),
420+
PatchFlags.KEYED_FRAGMENT
421+
)
422+
)
423+
}
424+
}
425+
426+
const hoisted1 = { key: 0 }
427+
const hoisted2 = { key: 0 }
428+
const hoisted3 = { key: 1 }
429+
430+
const renderFn = () => {
431+
return (
432+
openBlock(true),
433+
createVNode(Comp, null, {
434+
default: withCtx(
435+
({ field, value }: { field: string; value: any }) => [
436+
field === 'field1'
437+
? (openBlock(), createElementBlock('div', hoisted1, textBlock))
438+
: field === 'field2'
439+
? (openBlock(),
440+
createElementBlock(
441+
Fragment,
442+
{ key: 1 },
443+
[
444+
value
445+
? (openBlock(),
446+
createElementBlock('div', hoisted2, vIfBlock))
447+
: createCommentVNode('v-if', true),
448+
value
449+
? (openBlock(),
450+
createElementBlock('div', hoisted3, vIfBlock))
451+
: createCommentVNode('v-if', true)
452+
],
453+
PatchFlags.STABLE_FRAGMENT
454+
))
455+
: createCommentVNode('v-if', true)
456+
]
457+
),
458+
_: SlotFlags.STABLE
459+
})
460+
)
461+
}
462+
463+
render(renderFn(), root)
464+
expect(serializeInner(root)).toBe(
465+
`<div><span><div>${textBlock}</div></span><span><div>${vIfBlock}</div><div>${vIfBlock}</div></span></div>`
466+
)
467+
468+
items.value = [{ field1: 'one', field2: undefined }]
469+
470+
render(renderFn(), root)
471+
expect(serializeInner(root)).toBe(
472+
`<div><span><div>${textBlock}</div></span><span>yyy</span></div>`
473+
)
474+
})
354475
})

packages/runtime-core/src/renderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,7 @@ function baseCreateRenderer(
11001100
// of renderSlot() with no valid children
11011101
n1.dynamicChildren &&
11021102
// #9200 in some case stable fragment in deep unstable slot
1103-
n1?.children?.length === n2?.children?.length
1103+
n1.dynamicChildren.length === dynamicChildren.length
11041104
) {
11051105
// a stable fragment (template root or <template v-for>) doesn't need to
11061106
// patch children order, but it may contain dynamicChildren.

0 commit comments

Comments
 (0)