+++ /dev/null
-<script src="../../dist/vue.global.js"></script>
-
-<my-element
- ><template shadowrootmode="open"><button>1</button></template></my-element
->
-<my-element-async
- ><template shadowrootmode="open"
- ><button>1</button></template
- ></my-element-async
->
-
-<script>
- const {
- h,
- ref,
- defineSSRCustomElement,
- defineAsyncComponent,
- onMounted,
- useHost,
- } = Vue
-
- const def = {
- setup() {
- const count = ref(1)
- const el = useHost()
- onMounted(() => (el.style.border = '1px solid red'))
-
- return () => h('button', { onClick: () => count.value++ }, count.value)
- },
- }
-
- customElements.define('my-element', defineSSRCustomElement(def))
- customElements.define(
- 'my-element-async',
- defineSSRCustomElement(
- defineAsyncComponent(
- () =>
- new Promise(r => {
- window.resolve = () => r(def)
- }),
- ),
- ),
- )
-</script>
const { page, click, text } = setupPuppeteer()
+beforeEach(async () => {
+ await page().addScriptTag({
+ path: path.resolve(__dirname, '../../dist/vue.global.js'),
+ })
+})
+
+async function setContent(html: string) {
+ await page().setContent(`<div id="app">${html}</div>`)
+}
+
// this must be tested in actual Chrome because jsdom does not support
// declarative shadow DOM
test('ssr custom element hydration', async () => {
- await page().goto(
- `file://${path.resolve(__dirname, './ssr-custom-element.html')}`,
+ await setContent(
+ `<my-element><template shadowrootmode="open"><button>1</button></template></my-element><my-element-async><template shadowrootmode="open"><button>1</button></template></my-element-async>`,
)
+ await page().evaluate(() => {
+ const {
+ h,
+ ref,
+ defineSSRCustomElement,
+ defineAsyncComponent,
+ onMounted,
+ useHost,
+ } = (window as any).Vue
+
+ const def = {
+ setup() {
+ const count = ref(1)
+ const el = useHost()
+ onMounted(() => (el.style.border = '1px solid red'))
+
+ return () => h('button', { onClick: () => count.value++ }, count.value)
+ },
+ }
+
+ customElements.define('my-element', defineSSRCustomElement(def))
+ customElements.define(
+ 'my-element-async',
+ defineSSRCustomElement(
+ defineAsyncComponent(
+ () =>
+ new Promise(r => {
+ ;(window as any).resolve = () => r(def)
+ }),
+ ),
+ ),
+ )
+ })
+
function getColor() {
return page().evaluate(() => {
return [
await assertInteraction('my-element')
await assertInteraction('my-element-async')
})
+
+// #11641
+test('pass key to custom element', async () => {
+ const messages: string[] = []
+ page().on('console', e => messages.push(e.text()))
+
+ await setContent(
+ `<!--[--><my-element str="1"><template shadowrootmode="open"><div>1</div></template></my-element><!--]-->`,
+ )
+ await page().evaluate(() => {
+ const {
+ h,
+ ref,
+ defineSSRCustomElement,
+ onBeforeUnmount,
+ onMounted,
+ createSSRApp,
+ renderList,
+ } = (window as any).Vue
+
+ const MyElement = defineSSRCustomElement({
+ props: {
+ str: String,
+ },
+ setup(props: any) {
+ onMounted(() => {
+ console.log('child mounted')
+ })
+ onBeforeUnmount(() => {
+ console.log('child unmount')
+ })
+ return () => h('div', props.str)
+ },
+ })
+ customElements.define('my-element', MyElement)
+
+ createSSRApp({
+ setup() {
+ const arr = ref(['1'])
+ // pass key to custom element
+ return () =>
+ renderList(arr.value, (i: string) =>
+ h('my-element', { key: i, str: i }, null),
+ )
+ },
+ }).mount('#app')
+ })
+
+ expect(messages.includes('child mounted')).toBe(true)
+ expect(messages.includes('child unmount')).toBe(false)
+ expect(await text('my-element >>> div')).toBe('1')
+})