feat(runtime-dom): support async component in defineCustomElement

close #4261
This commit is contained in:
Evan You
2021-08-06 19:15:55 -04:00
parent 1994f1200d
commit c421fb91b2
4 changed files with 177 additions and 47 deletions

View File

@@ -1,4 +1,5 @@
import {
defineAsyncComponent,
defineCustomElement,
h,
inject,
@@ -300,4 +301,96 @@ describe('defineCustomElement', () => {
expect(style.textContent).toBe(`div { color: red; }`)
})
})
describe('async', () => {
test('should work', async () => {
const loaderSpy = jest.fn()
const E = defineCustomElement(
defineAsyncComponent(() => {
loaderSpy()
return Promise.resolve({
props: ['msg'],
styles: [`div { color: red }`],
render(this: any) {
return h('div', null, this.msg)
}
})
})
)
customElements.define('my-el-async', E)
container.innerHTML =
`<my-el-async msg="hello"></my-el-async>` +
`<my-el-async msg="world"></my-el-async>`
await new Promise(r => setTimeout(r))
// loader should be called only once
expect(loaderSpy).toHaveBeenCalledTimes(1)
const e1 = container.childNodes[0] as VueElement
const e2 = container.childNodes[1] as VueElement
// should inject styles
expect(e1.shadowRoot!.innerHTML).toBe(
`<div>hello</div><style>div { color: red }</style>`
)
expect(e2.shadowRoot!.innerHTML).toBe(
`<div>world</div><style>div { color: red }</style>`
)
// attr
e1.setAttribute('msg', 'attr')
await nextTick()
expect((e1 as any).msg).toBe('attr')
expect(e1.shadowRoot!.innerHTML).toBe(
`<div>attr</div><style>div { color: red }</style>`
)
// props
expect(`msg` in e1).toBe(true)
;(e1 as any).msg = 'prop'
expect(e1.getAttribute('msg')).toBe('prop')
expect(e1.shadowRoot!.innerHTML).toBe(
`<div>prop</div><style>div { color: red }</style>`
)
})
test('set DOM property before resolve', async () => {
const E = defineCustomElement(
defineAsyncComponent(() => {
return Promise.resolve({
props: ['msg'],
render(this: any) {
return h('div', this.msg)
}
})
})
)
customElements.define('my-el-async-2', E)
const e1 = new E()
// set property before connect
e1.msg = 'hello'
const e2 = new E()
container.appendChild(e1)
container.appendChild(e2)
// set property after connect but before resolve
e2.msg = 'world'
await new Promise(r => setTimeout(r))
expect(e1.shadowRoot!.innerHTML).toBe(`<div>hello</div>`)
expect(e2.shadowRoot!.innerHTML).toBe(`<div>world</div>`)
e1.msg = 'world'
expect(e1.shadowRoot!.innerHTML).toBe(`<div>world</div>`)
e2.msg = 'hello'
expect(e2.shadowRoot!.innerHTML).toBe(`<div>hello</div>`)
})
})
})