]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: add tests
authordaiwei <daiwei521@126.com>
Wed, 16 Apr 2025 13:28:36 +0000 (21:28 +0800)
committerdaiwei <daiwei521@126.com>
Wed, 16 Apr 2025 13:28:36 +0000 (21:28 +0800)
packages/runtime-dom/__tests__/customElement.spec.ts
packages/runtime-dom/src/apiCustomElement.ts

index df438d47eeeadabc0854871d233ea241b2e48021..fa14f6d48f79fc5f788350209f3a8d3f62f03cef 100644 (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', () => {
index 5cab16ad6790fe45fc16a8d2e9fdcfb3c86b1e5a..ebd75b252ad15a76a62a49106582a4a320edeaa9 100644 (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)
       }
     }
   }