test: add tests

This commit is contained in:
daiwei 2025-04-16 21:28:36 +08:00
parent 68b2001055
commit 1a5ea558a5
2 changed files with 110 additions and 11 deletions

View File

@ -5,6 +5,10 @@ import {
Teleport,
type VueElement,
createApp,
createBlock,
createCommentVNode,
createElementBlock,
createElementVNode,
defineAsyncComponent,
defineComponent,
defineCustomElement,
@ -12,12 +16,14 @@ import {
inject,
nextTick,
onMounted,
openBlock,
provide,
ref,
render,
renderSlot,
useHost,
useShadowRoot,
withCtx,
} from '../src'
declare var __VUE_HMR_RUNTIME__: HMRRuntime
@ -1131,6 +1137,92 @@ describe('defineCustomElement', () => {
expect(target.innerHTML).toBe(`<span>default</span>`)
app.unmount()
})
//#13206
test('should update slotted children correctly w/ shadowRoot false', async () => {
const E = defineCustomElement(
defineComponent({
props: {
isShown: { type: Boolean, required: true },
},
render() {
return this.isShown
? h('div', { key: 0 }, [renderSlot(this.$slots, 'default')])
: null
},
}),
{ shadowRoot: false },
)
customElements.define('ce-shadow-root-false', E)
const Comp = defineComponent({
props: {
isShown: { type: Boolean, required: true },
},
render() {
return h('ce-shadow-root-false', { 'is-shown': this.isShown }, [
renderSlot(this.$slots, 'default'),
])
},
})
const isShown = ref(false)
const count = ref(0)
function click() {
isShown.value = !isShown.value
count.value++
}
const App = {
render() {
return (
openBlock(),
createBlock(
Comp,
{ isShown: isShown.value },
{
default: withCtx(() => [
createElementVNode('div', null, isShown.value, 1 /* TEXT */),
count.value > 1
? (openBlock(), createElementBlock('div', { key: 0 }, 'hi'))
: createCommentVNode('v-if', true),
]),
_: 1 /* STABLE */,
},
8 /* PROPS */,
['isShown'],
)
)
},
}
const container = document.createElement('div')
document.body.appendChild(container)
const app = createApp(App)
app.mount(container)
expect(container.innerHTML).toBe(
`<ce-shadow-root-false data-v-app=""><!----></ce-shadow-root-false>`,
)
click()
await nextTick()
expect(container.innerHTML).toBe(
`<ce-shadow-root-false data-v-app="" is-shown=""><div><div>true</div><!--v-if--></div></ce-shadow-root-false>`,
)
click()
await nextTick()
expect(container.innerHTML).toBe(
`<ce-shadow-root-false data-v-app=""><!----></ce-shadow-root-false>`,
)
click()
await nextTick()
expect(container.innerHTML).toBe(
`<ce-shadow-root-false data-v-app="" is-shown=""><div><div>true</div><div>hi</div></div></ce-shadow-root-false>`,
)
})
})
describe('helpers', () => {

View File

@ -665,9 +665,8 @@ export class VueElement
*/
_updateSlots(children: VNode[]): void {
children.forEach(child => {
this._slots![child.slotName!] = collectElements(
child.children as VNodeArrayChildren,
)
// slot children are always Fragments
this._slots![child.slotName!] = collectFragmentElements(child)
})
}
@ -725,16 +724,24 @@ export function useShadowRoot(): ShadowRoot | null {
return el && el.shadowRoot
}
function collectFragmentElements(child: VNode): Node[] {
return [
child.el as Node,
...collectElements(child.children as VNodeArrayChildren),
child.anchor as Node,
]
}
function collectElements(children: VNodeArrayChildren): Node[] {
const nodes: Node[] = []
for (const vnode of children) {
if (isArray(vnode)) {
nodes.push(...collectElements(vnode))
} else if (isVNode(vnode)) {
if (vnode.type === Fragment) {
nodes.push(...collectElements(vnode.children as VNodeArrayChildren))
} else if (vnode.el) {
nodes.push(vnode.el as Node)
for (const child of children) {
if (isArray(child)) {
nodes.push(...collectElements(child))
} else if (isVNode(child)) {
if (child.type === Fragment) {
nodes.push(...collectFragmentElements(child))
} else if (child.el) {
nodes.push(child.el as Node)
}
}
}