diff --git a/packages/runtime-vapor/__tests__/hydration.spec.ts b/packages/runtime-vapor/__tests__/hydration.spec.ts new file mode 100644 index 000000000..7422f6e6d --- /dev/null +++ b/packages/runtime-vapor/__tests__/hydration.spec.ts @@ -0,0 +1,2314 @@ +// import { type SSRContext, renderToString } from '@vue/server-renderer' +import { createVaporSSRApp, renderEffect, setText, template } from '../src' +import { nextTick, ref } from '@vue/runtime-dom' + +function mountWithHydration(html: string, setup: () => any) { + const container = document.createElement('div') + container.innerHTML = html + const app = createVaporSSRApp({ + setup, + }) + app.mount(container) + return { + container, + } +} + +// const triggerEvent = (type: string, el: Element) => { +// const event = new Event(type) +// el.dispatchEvent(event) +// } + +describe('SSR hydration', () => { + beforeEach(() => { + document.body.innerHTML = '' + }) + + test('text', async () => { + const msg = ref('foo') + const t = template(' ') + const { container } = mountWithHydration('foo', () => { + const n = t() + renderEffect(() => setText(n as Text, msg.value)) + return n + }) + expect(container.textContent).toBe('foo') + msg.value = 'bar' + await nextTick() + expect(container.textContent).toBe('bar') + }) + + test('empty text', async () => { + const t0 = template('
', true) + const { container } = mountWithHydration('
', () => t0()) + expect(container.innerHTML).toBe('
') + expect(`Hydration children mismatch in
`).not.toHaveBeenWarned() + }) + + test('comment', () => { + const t0 = template('') + const { container } = mountWithHydration('', () => t0()) + expect(container.innerHTML).toBe('') + expect(`Hydration children mismatch in
`).not.toHaveBeenWarned() + }) + + // test('static before text', () => { + // const t0 = template(' A ') + // const t1 = template('foo bar') + // const t2 = template(' ') + // const msg = ref('hello') + // const { container } = mountWithHydration( + // ' A foo barhello', + // () => { + // const n0 = t0() + // const n1 = t1() + // const n2 = t2() + // const n3 = createTextNode() + // renderEffect(() => setText(n3, toDisplayString(msg.value))) + // return [n0, n1, n2, n3] + // }, + // ) + // }) + + // test('static (multiple elements)', () => { + // const staticContent = '
hello' + // const html = `
hi
` + staticContent + `
ho
` + + // const n1 = h('div', 'hi') + // const s = createStaticVNode('', 2) + // const n2 = h('div', 'ho') + + // const { container } = mountWithHydration(html, () => h('div', [n1, s, n2])) + + // const div = container.firstChild! + + // expect(n1.el).toBe(div.firstChild) + // expect(n2.el).toBe(div.lastChild) + // expect(s.el).toBe(div.childNodes[1]) + // expect(s.anchor).toBe(div.childNodes[2]) + // expect(s.children).toBe(staticContent) + // }) + + // // #6008 + // test('static (with text node as starting node)', () => { + // const html = ` A foo B` + // const { vnode, container } = mountWithHydration(html, () => + // createStaticVNode(` A foo B`, 3), + // ) + // expect(vnode.el).toBe(container.firstChild) + // expect(vnode.anchor).toBe(container.lastChild) + // expect(`Hydration node mismatch`).not.toHaveBeenWarned() + // }) + + // test('static with content adoption', () => { + // const html = ` A foo B` + // const { vnode, container } = mountWithHydration(html, () => + // createStaticVNode(``, 3), + // ) + // expect(vnode.el).toBe(container.firstChild) + // expect(vnode.anchor).toBe(container.lastChild) + // expect(vnode.children).toBe(html) + // expect(`Hydration node mismatch`).not.toHaveBeenWarned() + // }) + + // test('element with text children', async () => { + // const msg = ref('foo') + // const { vnode, container } = mountWithHydration( + // '
foo
', + // () => h('div', { class: msg.value }, msg.value), + // ) + // expect(vnode.el).toBe(container.firstChild) + // expect(container.firstChild!.textContent).toBe('foo') + // msg.value = 'bar' + // await nextTick() + // expect(container.innerHTML).toBe(`
bar
`) + // }) + + // // #7285 + // test('element with multiple continuous text vnodes', async () => { + // // should no mismatch warning + // const { container } = mountWithHydration('
foo0o
', () => + // h('div', ['fo', createTextVNode('o'), 0, 'o']), + // ) + // expect(container.textContent).toBe('foo0o') + // }) + + // test('element with elements children', async () => { + // const msg = ref('foo') + // const fn = vi.fn() + // const { vnode, container } = mountWithHydration( + // '
foo
', + // () => + // h('div', [ + // h('span', msg.value), + // h('span', { class: msg.value, onClick: fn }), + // ]), + // ) + // expect(vnode.el).toBe(container.firstChild) + // expect((vnode.children as VNode[])[0].el).toBe( + // container.firstChild!.childNodes[0], + // ) + // expect((vnode.children as VNode[])[1].el).toBe( + // container.firstChild!.childNodes[1], + // ) + + // // event handler + // triggerEvent('click', vnode.el.querySelector('.foo')!) + // expect(fn).toHaveBeenCalled() + + // msg.value = 'bar' + // await nextTick() + // expect(vnode.el.innerHTML).toBe(`bar`) + // }) + + // test('element with ref', () => { + // const el = ref() + // const { vnode, container } = mountWithHydration('
', () => + // h('div', { ref: el }), + // ) + // expect(vnode.el).toBe(container.firstChild) + // expect(el.value).toBe(vnode.el) + // }) + + // test('Fragment', async () => { + // const msg = ref('foo') + // const fn = vi.fn() + // const { vnode, container } = mountWithHydration( + // '
foo
', + // () => + // h('div', [ + // [ + // h('span', msg.value), + // [h('span', { class: msg.value, onClick: fn })], + // ], + // ]), + // ) + // expect(vnode.el).toBe(container.firstChild) + + // expect(vnode.el.innerHTML).toBe( + // `foo`, + // ) + + // // start fragment 1 + // const fragment1 = (vnode.children as VNode[])[0] + // expect(fragment1.el).toBe(vnode.el.childNodes[0]) + // const fragment1Children = fragment1.children as VNode[] + + // // first + // expect(fragment1Children[0].el!.tagName).toBe('SPAN') + // expect(fragment1Children[0].el).toBe(vnode.el.childNodes[1]) + + // // start fragment 2 + // const fragment2 = fragment1Children[1] + // expect(fragment2.el).toBe(vnode.el.childNodes[2]) + // const fragment2Children = fragment2.children as VNode[] + + // // second + // expect(fragment2Children[0].el!.tagName).toBe('SPAN') + // expect(fragment2Children[0].el).toBe(vnode.el.childNodes[3]) + + // // end fragment 2 + // expect(fragment2.anchor).toBe(vnode.el.childNodes[4]) + + // // end fragment 1 + // expect(fragment1.anchor).toBe(vnode.el.childNodes[5]) + + // // event handler + // triggerEvent('click', vnode.el.querySelector('.foo')!) + // expect(fn).toHaveBeenCalled() + + // msg.value = 'bar' + // await nextTick() + // expect(vnode.el.innerHTML).toBe( + // `bar`, + // ) + // }) + + // // #7285 + // test('Fragment (multiple continuous text vnodes)', async () => { + // // should no mismatch warning + // const { container } = mountWithHydration('fooo', () => [ + // 'fo', + // createTextVNode('o'), + // 'o', + // ]) + // expect(container.textContent).toBe('fooo') + // }) + + // test('Teleport', async () => { + // const msg = ref('foo') + // const fn = vi.fn() + // const teleportContainer = document.createElement('div') + // teleportContainer.id = 'teleport' + // teleportContainer.innerHTML = `foo` + // document.body.appendChild(teleportContainer) + + // const { vnode, container } = mountWithHydration( + // '', + // () => + // h(Teleport, { to: '#teleport' }, [ + // h('span', msg.value), + // h('span', { class: msg.value, onClick: fn }), + // ]), + // ) + + // expect(vnode.el).toBe(container.firstChild) + // expect(vnode.anchor).toBe(container.lastChild) + + // expect(vnode.target).toBe(teleportContainer) + // expect(vnode.targetStart).toBe(teleportContainer.childNodes[0]) + // expect((vnode.children as VNode[])[0].el).toBe( + // teleportContainer.childNodes[1], + // ) + // expect((vnode.children as VNode[])[1].el).toBe( + // teleportContainer.childNodes[2], + // ) + // expect(vnode.targetAnchor).toBe(teleportContainer.childNodes[3]) + + // // event handler + // triggerEvent('click', teleportContainer.querySelector('.foo')!) + // expect(fn).toHaveBeenCalled() + + // msg.value = 'bar' + // await nextTick() + // expect(teleportContainer.innerHTML).toBe( + // `bar`, + // ) + // }) + + // test('Teleport (multiple + integration)', async () => { + // const msg = ref('foo') + // const fn1 = vi.fn() + // const fn2 = vi.fn() + + // const Comp = () => [ + // h(Teleport, { to: '#teleport2' }, [ + // h('span', msg.value), + // h('span', { class: msg.value, onClick: fn1 }), + // ]), + // h(Teleport, { to: '#teleport2' }, [ + // h('span', msg.value + '2'), + // h('span', { class: msg.value + '2', onClick: fn2 }), + // ]), + // ] + + // const teleportContainer = document.createElement('div') + // teleportContainer.id = 'teleport2' + // const ctx: SSRContext = {} + // const mainHtml = await renderToString(h(Comp), ctx) + // expect(mainHtml).toMatchInlineSnapshot( + // `""`, + // ) + + // const teleportHtml = ctx.teleports!['#teleport2'] + // expect(teleportHtml).toMatchInlineSnapshot( + // `"foofoo2"`, + // ) + + // teleportContainer.innerHTML = teleportHtml + // document.body.appendChild(teleportContainer) + + // const { vnode, container } = mountWithHydration(mainHtml, Comp) + // expect(vnode.el).toBe(container.firstChild) + // const teleportVnode1 = (vnode.children as VNode[])[0] + // const teleportVnode2 = (vnode.children as VNode[])[1] + // expect(teleportVnode1.el).toBe(container.childNodes[1]) + // expect(teleportVnode1.anchor).toBe(container.childNodes[2]) + // expect(teleportVnode2.el).toBe(container.childNodes[3]) + // expect(teleportVnode2.anchor).toBe(container.childNodes[4]) + + // expect(teleportVnode1.target).toBe(teleportContainer) + // expect(teleportVnode1.targetStart).toBe(teleportContainer.childNodes[0]) + // expect((teleportVnode1 as any).children[0].el).toBe( + // teleportContainer.childNodes[1], + // ) + // expect(teleportVnode1.targetAnchor).toBe(teleportContainer.childNodes[3]) + + // expect(teleportVnode2.target).toBe(teleportContainer) + // expect(teleportVnode2.targetStart).toBe(teleportContainer.childNodes[4]) + // expect((teleportVnode2 as any).children[0].el).toBe( + // teleportContainer.childNodes[5], + // ) + // expect(teleportVnode2.targetAnchor).toBe(teleportContainer.childNodes[7]) + + // // // event handler + // triggerEvent('click', teleportContainer.querySelector('.foo')!) + // expect(fn1).toHaveBeenCalled() + + // triggerEvent('click', teleportContainer.querySelector('.foo2')!) + // expect(fn2).toHaveBeenCalled() + + // msg.value = 'bar' + // await nextTick() + // expect(teleportContainer.innerHTML).toMatchInlineSnapshot( + // `"barbar2"`, + // ) + // }) + + // test('Teleport (disabled)', async () => { + // const msg = ref('foo') + // const fn1 = vi.fn() + // const fn2 = vi.fn() + + // const Comp = () => [ + // h('div', 'foo'), + // h(Teleport, { to: '#teleport3', disabled: true }, [ + // h('span', msg.value), + // h('span', { class: msg.value, onClick: fn1 }), + // ]), + // h('div', { class: msg.value + '2', onClick: fn2 }, 'bar'), + // ] + + // const teleportContainer = document.createElement('div') + // teleportContainer.id = 'teleport3' + // const ctx: SSRContext = {} + // const mainHtml = await renderToString(h(Comp), ctx) + // expect(mainHtml).toMatchInlineSnapshot( + // `"
foo
foo
bar
"`, + // ) + + // const teleportHtml = ctx.teleports!['#teleport3'] + // expect(teleportHtml).toMatchInlineSnapshot( + // `""`, + // ) + + // teleportContainer.innerHTML = teleportHtml + // document.body.appendChild(teleportContainer) + + // const { vnode, container } = mountWithHydration(mainHtml, Comp) + // expect(vnode.el).toBe(container.firstChild) + // const children = vnode.children as VNode[] + + // expect(children[0].el).toBe(container.childNodes[1]) + + // const teleportVnode = children[1] + // expect(teleportVnode.el).toBe(container.childNodes[2]) + // expect((teleportVnode.children as VNode[])[0].el).toBe( + // container.childNodes[3], + // ) + // expect((teleportVnode.children as VNode[])[1].el).toBe( + // container.childNodes[4], + // ) + // expect(teleportVnode.anchor).toBe(container.childNodes[5]) + // expect(children[2].el).toBe(container.childNodes[6]) + + // expect(teleportVnode.target).toBe(teleportContainer) + // expect(teleportVnode.targetStart).toBe(teleportContainer.childNodes[0]) + // expect(teleportVnode.targetAnchor).toBe(teleportContainer.childNodes[1]) + + // // // event handler + // triggerEvent('click', container.querySelector('.foo')!) + // expect(fn1).toHaveBeenCalled() + + // triggerEvent('click', container.querySelector('.foo2')!) + // expect(fn2).toHaveBeenCalled() + + // msg.value = 'bar' + // await nextTick() + // expect(container.innerHTML).toMatchInlineSnapshot( + // `"
foo
bar
bar
"`, + // ) + // }) + + // // #6152 + // test('Teleport (disabled + as component root)', () => { + // const { container } = mountWithHydration( + // '
Parent fragment
Teleport content
', + // () => [ + // h('div', 'Parent fragment'), + // h(() => + // h(Teleport, { to: 'body', disabled: true }, [ + // h('div', 'Teleport content'), + // ]), + // ), + // ], + // ) + // expect(document.body.innerHTML).toBe('') + // expect(container.innerHTML).toBe( + // '
Parent fragment
Teleport content
', + // ) + // expect( + // `Hydration completed but contains mismatches.`, + // ).not.toHaveBeenWarned() + // }) + + // test('Teleport (as component root)', () => { + // const teleportContainer = document.createElement('div') + // teleportContainer.id = 'teleport4' + // teleportContainer.innerHTML = `hello` + // document.body.appendChild(teleportContainer) + + // const wrapper = { + // render() { + // return h(Teleport, { to: '#teleport4' }, ['hello']) + // }, + // } + + // const { vnode, container } = mountWithHydration( + // '
', + // () => h('div', [h(wrapper), h('div')]), + // ) + // expect(vnode.el).toBe(container.firstChild) + // // component el + // const wrapperVNode = (vnode as any).children[0] + // const tpStart = container.firstChild?.firstChild + // const tpEnd = tpStart?.nextSibling + // expect(wrapperVNode.el).toBe(tpStart) + // expect(wrapperVNode.component.subTree.el).toBe(tpStart) + // expect(wrapperVNode.component.subTree.anchor).toBe(tpEnd) + // // next node hydrate properly + // const nextVNode = (vnode as any).children[1] + // expect(nextVNode.el).toBe(container.firstChild?.lastChild) + // }) + + // test('Teleport (nested)', () => { + // const teleportContainer = document.createElement('div') + // teleportContainer.id = 'teleport5' + // teleportContainer.innerHTML = `
child
` + // document.body.appendChild(teleportContainer) + + // const { vnode, container } = mountWithHydration( + // '', + // () => + // h(Teleport, { to: '#teleport5' }, [ + // h('div', [h(Teleport, { to: '#teleport5' }, [h('div', 'child')])]), + // ]), + // ) + + // expect(vnode.el).toBe(container.firstChild) + // expect(vnode.anchor).toBe(container.lastChild) + + // const childDivVNode = (vnode as any).children[0] + // const div = teleportContainer.childNodes[1] + // expect(childDivVNode.el).toBe(div) + // expect(vnode.targetAnchor).toBe(div?.nextSibling) + + // const childTeleportVNode = childDivVNode.children[0] + // expect(childTeleportVNode.el).toBe(div?.firstChild) + // expect(childTeleportVNode.anchor).toBe(div?.lastChild) + + // expect(childTeleportVNode.targetAnchor).toBe(teleportContainer.lastChild) + // expect(childTeleportVNode.children[0].el).toBe( + // teleportContainer.lastChild?.previousSibling, + // ) + // }) + + // test('with data-allow-mismatch component when using onServerPrefetch', async () => { + // const Comp = { + // template: ` + //
Comp2
+ // `, + // } + // let foo: any + // const App = { + // setup() { + // const flag = ref(true) + // foo = () => { + // flag.value = false + // } + // onServerPrefetch(() => (flag.value = false)) + // return { flag } + // }, + // components: { + // Comp, + // }, + // template: ` + // + // + // + // `, + // } + // // hydrate + // const container = document.createElement('div') + // container.innerHTML = await renderToString(h(App)) + // createSSRApp(App).mount(container) + // expect(container.innerHTML).toBe( + // '
Comp2
', + // ) + // foo() + // await nextTick() + // expect(container.innerHTML).toBe( + // '', + // ) + // }) + + // test('Teleport unmount (full integration)', async () => { + // const Comp1 = { + // template: ` + // + // Teleported Comp1 + // + // `, + // } + // const Comp2 = { + // template: ` + //
Comp2
+ // `, + // } + + // const toggle = ref(true) + // const App = { + // template: ` + //
+ // + // + //
+ // `, + // components: { + // Comp1, + // Comp2, + // }, + // setup() { + // return { toggle } + // }, + // } + + // const container = document.createElement('div') + // const teleportContainer = document.createElement('div') + // teleportContainer.id = 'target' + // document.body.appendChild(teleportContainer) + + // // server render + // const ctx: SSRContext = {} + // container.innerHTML = await renderToString(h(App), ctx) + // expect(container.innerHTML).toBe( + // '
', + // ) + // teleportContainer.innerHTML = ctx.teleports!['#target'] + + // // hydrate + // createSSRApp(App).mount(container) + // expect(container.innerHTML).toBe( + // '
', + // ) + // expect(teleportContainer.innerHTML).toBe( + // 'Teleported Comp1', + // ) + // expect(`Hydration children mismatch`).not.toHaveBeenWarned() + + // toggle.value = false + // await nextTick() + // expect(container.innerHTML).toBe('
Comp2
') + // expect(teleportContainer.innerHTML).toBe('') + // }) + + // test('Teleport unmount (mismatch + full integration)', async () => { + // const Comp1 = { + // template: ` + // + // Teleported Comp1 + // + // `, + // } + // const Comp2 = { + // template: ` + //
Comp2
+ // `, + // } + + // const toggle = ref(true) + // const App = { + // template: ` + //
+ // + // + //
+ // `, + // components: { + // Comp1, + // Comp2, + // }, + // setup() { + // return { toggle } + // }, + // } + + // const container = document.createElement('div') + // const teleportContainer = document.createElement('div') + // teleportContainer.id = 'target' + // document.body.appendChild(teleportContainer) + + // // server render + // container.innerHTML = await renderToString(h(App)) + // expect(container.innerHTML).toBe( + // '
', + // ) + // expect(teleportContainer.innerHTML).toBe('') + + // // hydrate + // createSSRApp(App).mount(container) + // expect(container.innerHTML).toBe( + // '
', + // ) + // expect(teleportContainer.innerHTML).toBe('Teleported Comp1') + // expect(`Hydration children mismatch`).toHaveBeenWarned() + + // toggle.value = false + // await nextTick() + // expect(container.innerHTML).toBe('
Comp2
') + // expect(teleportContainer.innerHTML).toBe('') + // }) + + // test('Teleport target change (mismatch + full integration)', async () => { + // const target = ref('#target1') + // const Comp = { + // template: ` + // + // Teleported + // + // `, + // setup() { + // return { target } + // }, + // } + + // const App = { + // template: ` + //
+ // + //
+ // `, + // components: { + // Comp, + // }, + // } + + // const container = document.createElement('div') + // const teleportContainer1 = document.createElement('div') + // teleportContainer1.id = 'target1' + // const teleportContainer2 = document.createElement('div') + // teleportContainer2.id = 'target2' + // document.body.appendChild(teleportContainer1) + // document.body.appendChild(teleportContainer2) + + // // server render + // container.innerHTML = await renderToString(h(App)) + // expect(container.innerHTML).toBe( + // '
', + // ) + // expect(teleportContainer1.innerHTML).toBe('') + // expect(teleportContainer2.innerHTML).toBe('') + + // // hydrate + // createSSRApp(App).mount(container) + // expect(container.innerHTML).toBe( + // '
', + // ) + // expect(teleportContainer1.innerHTML).toBe('Teleported') + // expect(teleportContainer2.innerHTML).toBe('') + // expect(`Hydration children mismatch`).toHaveBeenWarned() + + // target.value = '#target2' + // await nextTick() + // expect(teleportContainer1.innerHTML).toBe('') + // expect(teleportContainer2.innerHTML).toBe('Teleported') + // }) + + // // compile SSR + client render fn from the same template & hydrate + // test('full compiler integration', async () => { + // const mounted: string[] = [] + // const log = vi.fn() + // const toggle = ref(true) + + // const Child = { + // data() { + // return { + // count: 0, + // text: 'hello', + // style: { + // color: 'red', + // }, + // } + // }, + // mounted() { + // mounted.push('child') + // }, + // template: ` + //
+ // {{ count }} + // + // + // + // {{ text }} + // + //
+ // `, + // } + + // const App = { + // setup() { + // return { toggle } + // }, + // mounted() { + // mounted.push('parent') + // }, + // template: ` + //
+ // hello + // + // hello + //
`, + // components: { + // Child, + // }, + // methods: { + // log, + // }, + // } + + // const container = document.createElement('div') + // // server render + // container.innerHTML = await renderToString(h(App)) + // // hydrate + // createSSRApp(App).mount(container) + + // // assert interactions + // // 1. parent button click + // triggerEvent('click', container.querySelector('.parent-click')!) + // expect(log).toHaveBeenCalledWith('click') + + // // 2. child inc click + text interpolation + // const count = container.querySelector('.count') as HTMLElement + // expect(count.textContent).toBe(`0`) + // triggerEvent('click', container.querySelector('.inc')!) + // await nextTick() + // expect(count.textContent).toBe(`1`) + + // // 3. child color click + style binding + // expect(count.style.color).toBe('red') + // triggerEvent('click', container.querySelector('.change')!) + // await nextTick() + // expect(count.style.color).toBe('green') + + // // 4. child event emit + // triggerEvent('click', container.querySelector('.emit')!) + // expect(log).toHaveBeenCalledWith('child') + + // // 5. child v-model + // const text = container.querySelector('.text')! + // const input = container.querySelector('input')! + // expect(text.textContent).toBe('hello') + // input.value = 'bye' + // triggerEvent('input', input) + // await nextTick() + // expect(text.textContent).toBe('bye') + // }) + + // test('handle click error in ssr mode', async () => { + // const App = { + // setup() { + // const throwError = () => { + // throw new Error('Sentry Error') + // } + // return { throwError } + // }, + // template: ` + //
+ // + //
`, + // } + + // const container = document.createElement('div') + // // server render + // container.innerHTML = await renderToString(h(App)) + // // hydrate + // const app = createSSRApp(App) + // const handler = (app.config.errorHandler = vi.fn()) + // app.mount(container) + // // assert interactions + // // parent button click + // triggerEvent('click', container.querySelector('.parent-click')!) + // expect(handler).toHaveBeenCalled() + // }) + + // test('handle blur error in ssr mode', async () => { + // const App = { + // setup() { + // const throwError = () => { + // throw new Error('Sentry Error') + // } + // return { throwError } + // }, + // template: ` + //
+ // + //
`, + // } + + // const container = document.createElement('div') + // // server render + // container.innerHTML = await renderToString(h(App)) + // // hydrate + // const app = createSSRApp(App) + // const handler = (app.config.errorHandler = vi.fn()) + // app.mount(container) + // // assert interactions + // // parent blur event + // triggerEvent('blur', container.querySelector('.parent-click')!) + // expect(handler).toHaveBeenCalled() + // }) + + // test('Suspense', async () => { + // const AsyncChild = { + // async setup() { + // const count = ref(0) + // return () => + // h( + // 'span', + // { + // onClick: () => { + // count.value++ + // }, + // }, + // count.value, + // ) + // }, + // } + // const { vnode, container } = mountWithHydration('0', () => + // h(Suspense, () => h(AsyncChild)), + // ) + // expect(vnode.el).toBe(container.firstChild) + // // wait for hydration to finish + // await new Promise(r => setTimeout(r)) + // triggerEvent('click', container.querySelector('span')!) + // await nextTick() + // expect(container.innerHTML).toBe(`1`) + // }) + + // // #6638 + // test('Suspense + async component', async () => { + // let isSuspenseResolved = false + // let isSuspenseResolvedInChild: any + // const AsyncChild = defineAsyncComponent(() => + // Promise.resolve( + // defineComponent({ + // setup() { + // isSuspenseResolvedInChild = isSuspenseResolved + // const count = ref(0) + // return () => + // h( + // 'span', + // { + // onClick: () => { + // count.value++ + // }, + // }, + // count.value, + // ) + // }, + // }), + // ), + // ) + // const { vnode, container } = mountWithHydration('0', () => + // h( + // Suspense, + // { + // onResolve() { + // isSuspenseResolved = true + // }, + // }, + // () => h(AsyncChild), + // ), + // ) + // expect(vnode.el).toBe(container.firstChild) + // // wait for hydration to finish + // await new Promise(r => setTimeout(r)) + + // expect(isSuspenseResolvedInChild).toBe(false) + // expect(isSuspenseResolved).toBe(true) + + // // assert interaction + // triggerEvent('click', container.querySelector('span')!) + // await nextTick() + // expect(container.innerHTML).toBe(`1`) + // }) + + // test('Suspense (full integration)', async () => { + // const mountedCalls: number[] = [] + // const asyncDeps: Promise[] = [] + + // const AsyncChild = defineComponent({ + // props: ['n'], + // async setup(props) { + // const count = ref(props.n) + // onMounted(() => { + // mountedCalls.push(props.n) + // }) + // const p = new Promise(r => setTimeout(r, props.n * 10)) + // asyncDeps.push(p) + // await p + // return () => + // h( + // 'span', + // { + // onClick: () => { + // count.value++ + // }, + // }, + // count.value, + // ) + // }, + // }) + + // const done = vi.fn() + // const App = { + // template: ` + // + //
+ // + // + //
+ //
`, + // components: { + // AsyncChild, + // }, + // methods: { + // done, + // }, + // } + + // const container = document.createElement('div') + // // server render + // container.innerHTML = await renderToString(h(App)) + // expect(container.innerHTML).toMatchInlineSnapshot( + // `"
12
"`, + // ) + // // reset asyncDeps from ssr + // asyncDeps.length = 0 + // // hydrate + // createSSRApp(App).mount(container) + + // expect(mountedCalls.length).toBe(0) + // expect(asyncDeps.length).toBe(2) + + // // wait for hydration to complete + // await Promise.all(asyncDeps) + // await new Promise(r => setTimeout(r)) + + // // should flush buffered effects + // expect(mountedCalls).toMatchObject([1, 2]) + // expect(container.innerHTML).toMatch( + // `
12
`, + // ) + + // const span1 = container.querySelector('span')! + // triggerEvent('click', span1) + // await nextTick() + // expect(container.innerHTML).toMatch( + // `
22
`, + // ) + + // const span2 = span1.nextSibling as Element + // triggerEvent('click', span2) + // await nextTick() + // expect(container.innerHTML).toMatch( + // `
23
`, + // ) + // }) + + // test('async component', async () => { + // const spy = vi.fn() + // const Comp = () => + // h( + // 'button', + // { + // onClick: spy, + // }, + // 'hello!', + // ) + + // let serverResolve: any + // let AsyncComp = defineAsyncComponent( + // () => + // new Promise(r => { + // serverResolve = r + // }), + // ) + + // const App = { + // render() { + // return ['hello', h(AsyncComp), 'world'] + // }, + // } + + // // server render + // const htmlPromise = renderToString(h(App)) + // serverResolve(Comp) + // const html = await htmlPromise + // expect(html).toMatchInlineSnapshot( + // `"helloworld"`, + // ) + + // // hydration + // let clientResolve: any + // AsyncComp = defineAsyncComponent( + // () => + // new Promise(r => { + // clientResolve = r + // }), + // ) + + // const container = document.createElement('div') + // container.innerHTML = html + // createSSRApp(App).mount(container) + + // // hydration not complete yet + // triggerEvent('click', container.querySelector('button')!) + // expect(spy).not.toHaveBeenCalled() + + // // resolve + // clientResolve(Comp) + // await new Promise(r => setTimeout(r)) + + // // should be hydrated now + // triggerEvent('click', container.querySelector('button')!) + // expect(spy).toHaveBeenCalled() + // }) + + // test('update async wrapper before resolve', async () => { + // const Comp = { + // render() { + // return h('h1', 'Async component') + // }, + // } + // let serverResolve: any + // let AsyncComp = defineAsyncComponent( + // () => + // new Promise(r => { + // serverResolve = r + // }), + // ) + + // const toggle = ref(true) + // const App = { + // setup() { + // onMounted(() => { + // // change state, this makes updateComponent(AsyncComp) execute before + // // the async component is resolved + // toggle.value = false + // }) + + // return () => { + // return [toggle.value ? 'hello' : 'world', h(AsyncComp)] + // } + // }, + // } + + // // server render + // const htmlPromise = renderToString(h(App)) + // serverResolve(Comp) + // const html = await htmlPromise + // expect(html).toMatchInlineSnapshot( + // `"hello

Async component

"`, + // ) + + // // hydration + // let clientResolve: any + // AsyncComp = defineAsyncComponent( + // () => + // new Promise(r => { + // clientResolve = r + // }), + // ) + + // const container = document.createElement('div') + // container.innerHTML = html + // createSSRApp(App).mount(container) + + // // resolve + // clientResolve(Comp) + // await new Promise(r => setTimeout(r)) + + // // should be hydrated now + // expect(`Hydration node mismatch`).not.toHaveBeenWarned() + // expect(container.innerHTML).toMatchInlineSnapshot( + // `"world

Async component

"`, + // ) + // }) + + // test('hydrate safely when property used by async setup changed before render', async () => { + // const toggle = ref(true) + + // const AsyncComp = { + // async setup() { + // await new Promise(r => setTimeout(r, 10)) + // return () => h('h1', 'Async component') + // }, + // } + + // const AsyncWrapper = { + // render() { + // return h(AsyncComp) + // }, + // } + + // const SiblingComp = { + // setup() { + // toggle.value = false + // return () => h('span') + // }, + // } + + // const App = { + // setup() { + // return () => + // h( + // Suspense, + // {}, + // { + // default: () => [ + // h('main', {}, [ + // h(AsyncWrapper, { + // prop: toggle.value ? 'hello' : 'world', + // }), + // h(SiblingComp), + // ]), + // ], + // }, + // ) + // }, + // } + + // // server render + // const html = await renderToString(h(App)) + + // expect(html).toMatchInlineSnapshot( + // `"

Async component

"`, + // ) + + // expect(toggle.value).toBe(false) + + // // hydration + + // // reset the value + // toggle.value = true + // expect(toggle.value).toBe(true) + + // const container = document.createElement('div') + // container.innerHTML = html + // createSSRApp(App).mount(container) + + // await new Promise(r => setTimeout(r, 10)) + + // expect(toggle.value).toBe(false) + + // // should be hydrated now + // expect(container.innerHTML).toMatchInlineSnapshot( + // `"

Async component

"`, + // ) + // }) + + // test('hydrate safely when property used by deep nested async setup changed before render', async () => { + // const toggle = ref(true) + + // const AsyncComp = { + // async setup() { + // await new Promise(r => setTimeout(r, 10)) + // return () => h('h1', 'Async component') + // }, + // } + + // const AsyncWrapper = { render: () => h(AsyncComp) } + // const AsyncWrapperWrapper = { render: () => h(AsyncWrapper) } + + // const SiblingComp = { + // setup() { + // toggle.value = false + // return () => h('span') + // }, + // } + + // const App = { + // setup() { + // return () => + // h( + // Suspense, + // {}, + // { + // default: () => [ + // h('main', {}, [ + // h(AsyncWrapperWrapper, { + // prop: toggle.value ? 'hello' : 'world', + // }), + // h(SiblingComp), + // ]), + // ], + // }, + // ) + // }, + // } + + // // server render + // const html = await renderToString(h(App)) + + // expect(html).toMatchInlineSnapshot( + // `"

Async component

"`, + // ) + + // expect(toggle.value).toBe(false) + + // // hydration + + // // reset the value + // toggle.value = true + // expect(toggle.value).toBe(true) + + // const container = document.createElement('div') + // container.innerHTML = html + // createSSRApp(App).mount(container) + + // await new Promise(r => setTimeout(r, 10)) + + // expect(toggle.value).toBe(false) + + // // should be hydrated now + // expect(container.innerHTML).toMatchInlineSnapshot( + // `"

Async component

"`, + // ) + // }) + + // // #3787 + // test('unmount async wrapper before load', async () => { + // let resolve: any + // const AsyncComp = defineAsyncComponent( + // () => + // new Promise(r => { + // resolve = r + // }), + // ) + + // const show = ref(true) + // const root = document.createElement('div') + // root.innerHTML = '
async
' + + // createSSRApp({ + // render() { + // return h('div', [show.value ? h(AsyncComp) : h('div', 'hi')]) + // }, + // }).mount(root) + + // show.value = false + // await nextTick() + // expect(root.innerHTML).toBe('
hi
') + // resolve({}) + // }) + + // //#12362 + // test('nested async wrapper', async () => { + // const Toggle = defineAsyncComponent( + // () => + // new Promise(r => { + // r( + // defineComponent({ + // setup(_, { slots }) { + // const show = ref(false) + // onMounted(() => { + // nextTick(() => { + // show.value = true + // }) + // }) + // return () => + // withDirectives( + // h('div', null, [renderSlot(slots, 'default')]), + // [[vShow, show.value]], + // ) + // }, + // }) as any, + // ) + // }), + // ) + + // const Wrapper = defineAsyncComponent(() => { + // return new Promise(r => { + // r( + // defineComponent({ + // render(this: any) { + // return renderSlot(this.$slots, 'default') + // }, + // }) as any, + // ) + // }) + // }) + + // const count = ref(0) + // const fn = vi.fn() + // const Child = { + // setup() { + // onMounted(() => { + // fn() + // count.value++ + // }) + // return () => h('div', count.value) + // }, + // } + + // const App = { + // render() { + // return h(Toggle, null, { + // default: () => + // h(Wrapper, null, { + // default: () => + // h(Wrapper, null, { + // default: () => h(Child), + // }), + // }), + // }) + // }, + // } + + // const root = document.createElement('div') + // root.innerHTML = await renderToString(h(App)) + // expect(root.innerHTML).toMatchInlineSnapshot( + // `"
0
"`, + // ) + + // createSSRApp(App).mount(root) + // await nextTick() + // await nextTick() + // expect(root.innerHTML).toMatchInlineSnapshot( + // `"
1
"`, + // ) + // expect(fn).toBeCalledTimes(1) + // }) + + // test('unmount async wrapper before load (fragment)', async () => { + // let resolve: any + // const AsyncComp = defineAsyncComponent( + // () => + // new Promise(r => { + // resolve = r + // }), + // ) + + // const show = ref(true) + // const root = document.createElement('div') + // root.innerHTML = '
async
' + + // createSSRApp({ + // render() { + // return h('div', [show.value ? h(AsyncComp) : h('div', 'hi')]) + // }, + // }).mount(root) + + // show.value = false + // await nextTick() + // expect(root.innerHTML).toBe('
hi
') + // resolve({}) + // }) + + // test('elements with camel-case in svg ', () => { + // const { vnode, container } = mountWithHydration( + // '', + // () => h('animateTransform'), + // ) + // expect(vnode.el).toBe(container.firstChild) + // expect(`Hydration node mismatch`).not.toHaveBeenWarned() + // }) + + // test('SVG as a mount container', () => { + // const svgContainer = document.createElement('svg') + // svgContainer.innerHTML = '' + // const app = createSSRApp({ + // render: () => h('g'), + // }) + + // expect( + // ( + // app.mount(svgContainer).$.subTree as VNode & { + // el: Element + // } + // ).el instanceof SVGElement, + // ) + // }) + + // test('force hydrate prop with `.prop` modifier', () => { + // const { container } = mountWithHydration('', () => + // h('input', { + // type: 'checkbox', + // '.indeterminate': true, + // }), + // ) + // expect((container.firstChild! as any).indeterminate).toBe(true) + // }) + + // test('force hydrate input v-model with non-string value bindings', () => { + // const { container } = mountWithHydration( + // '', + // () => + // withDirectives( + // createVNode( + // 'input', + // { type: 'checkbox', 'true-value': true }, + // null, + // PatchFlags.PROPS, + // ['true-value'], + // ), + // [[vModelCheckbox, true]], + // ), + // ) + // expect((container.firstChild as any)._trueValue).toBe(true) + // }) + + // test('force hydrate checkbox with indeterminate', () => { + // const { container } = mountWithHydration( + // '', + // () => + // createVNode( + // 'input', + // { type: 'checkbox', indeterminate: '' }, + // null, + // PatchFlags.CACHED, + // ), + // ) + // expect((container.firstChild as any).indeterminate).toBe(true) + // }) + + // test('force hydrate select option with non-string value bindings', () => { + // const { container } = mountWithHydration( + // '', + // () => + // h('select', [ + // // hoisted because bound value is a constant... + // createVNode('option', { value: true }, null, -1 /* HOISTED */), + // ]), + // ) + // expect((container.firstChild!.firstChild as any)._value).toBe(true) + // }) + + // // #7203 + // test('force hydrate custom element with dynamic props', () => { + // class MyElement extends HTMLElement { + // foo = '' + // constructor() { + // super() + // } + // } + // customElements.define('my-element-7203', MyElement) + + // const msg = ref('bar') + // const container = document.createElement('div') + // container.innerHTML = '' + // const app = createSSRApp({ + // render: () => h('my-element-7203', { foo: msg.value }), + // }) + // app.mount(container) + // expect((container.firstChild as any).foo).toBe(msg.value) + // }) + + // // #5728 + // test('empty text node in slot', () => { + // const Comp = { + // render(this: any) { + // return renderSlot(this.$slots, 'default', {}, () => [ + // createTextVNode(''), + // ]) + // }, + // } + // const { container, vnode } = mountWithHydration('', () => + // h(Comp), + // ) + // expect(container.childNodes.length).toBe(3) + // const text = container.childNodes[1] + // expect(text.nodeType).toBe(3) + // expect(vnode.el).toBe(container.childNodes[0]) + // // component => slot fragment => text node + // expect((vnode as any).component?.subTree.children[0].el).toBe(text) + // }) + + // // #7215 + // test('empty text node', () => { + // const Comp = { + // render(this: any) { + // return h('p', ['']) + // }, + // } + // const { container } = mountWithHydration('

', () => h(Comp)) + // expect(container.childNodes.length).toBe(1) + // const p = container.childNodes[0] + // expect(p.childNodes.length).toBe(1) + // const text = p.childNodes[0] + // expect(text.nodeType).toBe(3) + // }) + + // // #11372 + // test('object style value tracking in prod', async () => { + // __DEV__ = false + // try { + // const style = reactive({ color: 'red' }) + // const Comp = { + // render(this: any) { + // return ( + // openBlock(), + // createElementBlock( + // 'div', + // { + // style: normalizeStyle(style), + // }, + // null, + // 4 /* STYLE */, + // ) + // ) + // }, + // } + // const { container } = mountWithHydration( + // `
`, + // () => h(Comp), + // ) + // style.color = 'green' + // await nextTick() + // expect(container.innerHTML).toBe(`
`) + // } finally { + // __DEV__ = true + // } + // }) + + // test('app.unmount()', async () => { + // const container = document.createElement('DIV') + // container.innerHTML = '' + // const App = defineComponent({ + // setup(_, { expose }) { + // const count = ref(0) + + // expose({ count }) + + // return () => + // h('button', { + // onClick: () => count.value++, + // }) + // }, + // }) + + // const app = createSSRApp(App) + // const vm = app.mount(container) + // await nextTick() + // expect((container as any)._vnode).toBeDefined() + // // @ts-expect-error - expose()'d properties are not available on vm type + // expect(vm.count).toBe(0) + + // app.unmount() + // expect((container as any)._vnode).toBe(null) + // }) + + // // #6637 + // test('stringified root fragment', () => { + // mountWithHydration(`
`, () => + // createStaticVNode(`
`, 1), + // ) + // expect(`mismatch`).not.toHaveBeenWarned() + // }) + + // test('transition appear', () => { + // const { vnode, container } = mountWithHydration( + // ``, + // () => + // h( + // Transition, + // { appear: true }, + // { + // default: () => h('div', 'foo'), + // }, + // ), + // ) + // expect(container.firstChild).toMatchInlineSnapshot(` + //
+ // foo + //
+ // `) + // expect(vnode.el).toBe(container.firstChild) + // expect(`mismatch`).not.toHaveBeenWarned() + // }) + + // test('transition appear with v-if', () => { + // const show = false + // const { vnode, container } = mountWithHydration( + // ``, + // () => + // h( + // Transition, + // { appear: true }, + // { + // default: () => (show ? h('div', 'foo') : createCommentVNode('')), + // }, + // ), + // ) + // expect(container.firstChild).toMatchInlineSnapshot('') + // expect(vnode.el).toBe(container.firstChild) + // expect(`mismatch`).not.toHaveBeenWarned() + // }) + + // test('transition appear with v-show', () => { + // const show = false + // const { vnode, container } = mountWithHydration( + // ``, + // () => + // h( + // Transition, + // { appear: true }, + // { + // default: () => + // withDirectives(createVNode('div', null, 'foo'), [[vShow, show]]), + // }, + // ), + // ) + // expect(container.firstChild).toMatchInlineSnapshot(` + // + // `) + // expect((container.firstChild as any)[vShowOriginalDisplay]).toBe('') + // expect(vnode.el).toBe(container.firstChild) + // expect(`mismatch`).not.toHaveBeenWarned() + // }) + + // test('transition appear w/ event listener', async () => { + // const container = document.createElement('div') + // container.innerHTML = `` + // createSSRApp({ + // data() { + // return { + // count: 0, + // } + // }, + // template: ` + // + // + // + // `, + // }).mount(container) + + // expect(container.firstChild).toMatchInlineSnapshot(` + // + // `) + + // triggerEvent('click', container.querySelector('button')!) + // await nextTick() + // expect(container.firstChild).toMatchInlineSnapshot(` + // + // `) + // }) + + // test('Suspense + transition appear', async () => { + // const { vnode, container } = mountWithHydration( + // ``, + // () => + // h(Suspense, {}, () => + // h( + // Transition, + // { appear: true }, + // { + // default: () => h('div', 'foo'), + // }, + // ), + // ), + // ) + + // expect(vnode.el).toBe(container.firstChild) + // // wait for hydration to finish + // await new Promise(r => setTimeout(r)) + + // expect(container.firstChild).toMatchInlineSnapshot(` + //
+ // foo + //
+ // `) + // await nextTick() + // expect(vnode.el).toBe(container.firstChild) + // }) + + // // #10607 + // test('update component stable slot (prod + optimized mode)', async () => { + // __DEV__ = false + // try { + // const container = document.createElement('div') + // container.innerHTML = `` + // const Comp = { + // render(this: any) { + // return ( + // openBlock(), + // createElementBlock('div', null, [ + // renderSlot(this.$slots, 'default'), + // ]) + // ) + // }, + // } + // const show = ref(false) + // const clicked = ref(false) + + // const Wrapper = { + // setup() { + // const items = ref([]) + // onMounted(() => { + // items.value = [1] + // }) + // return () => { + // return ( + // openBlock(), + // createBlock(Comp, null, { + // default: withCtx(() => [ + // createElementVNode('div', null, [ + // createElementVNode('div', null, [ + // clicked.value + // ? (openBlock(), + // createElementBlock('div', { key: 0 }, 'foo')) + // : createCommentVNode('v-if', true), + // ]), + // ]), + // createElementVNode( + // 'div', + // null, + // items.value.length, + // 1 /* TEXT */, + // ), + // ]), + // _: 1 /* STABLE */, + // }) + // ) + // } + // }, + // } + // createSSRApp({ + // components: { Wrapper }, + // data() { + // return { show } + // }, + // template: ``, + // }).mount(container) + + // await nextTick() + // expect(container.innerHTML).toBe( + // `
1
`, + // ) + + // show.value = true + // await nextTick() + // expect(async () => { + // clicked.value = true + // await nextTick() + // }).not.toThrow("Cannot read properties of null (reading 'insertBefore')") + + // await nextTick() + // expect(container.innerHTML).toBe( + // `
foo
1
`, + // ) + // } catch (e) { + // throw e + // } finally { + // __DEV__ = true + // } + // }) + + // describe('mismatch handling', () => { + // test('text node', () => { + // const { container } = mountWithHydration(`foo`, () => 'bar') + // expect(container.textContent).toBe('bar') + // expect(`Hydration text mismatch`).toHaveBeenWarned() + // }) + + // test('element text content', () => { + // const { container } = mountWithHydration(`
foo
`, () => + // h('div', 'bar'), + // ) + // expect(container.innerHTML).toBe('
bar
') + // expect(`Hydration text content mismatch`).toHaveBeenWarned() + // }) + + // test('not enough children', () => { + // const { container } = mountWithHydration(`
`, () => + // h('div', [h('span', 'foo'), h('span', 'bar')]), + // ) + // expect(container.innerHTML).toBe( + // '
foobar
', + // ) + // expect(`Hydration children mismatch`).toHaveBeenWarned() + // }) + + // test('too many children', () => { + // const { container } = mountWithHydration( + // `
foobar
`, + // () => h('div', [h('span', 'foo')]), + // ) + // expect(container.innerHTML).toBe('
foo
') + // expect(`Hydration children mismatch`).toHaveBeenWarned() + // }) + + // test('complete mismatch', () => { + // const { container } = mountWithHydration( + // `
foobar
`, + // () => h('div', [h('div', 'foo'), h('p', 'bar')]), + // ) + // expect(container.innerHTML).toBe('
foo

bar

') + // expect(`Hydration node mismatch`).toHaveBeenWarnedTimes(2) + // }) + + // test('fragment mismatch removal', () => { + // const { container } = mountWithHydration( + // `
foo
bar
`, + // () => h('div', [h('span', 'replaced')]), + // ) + // expect(container.innerHTML).toBe('
replaced
') + // expect(`Hydration node mismatch`).toHaveBeenWarned() + // }) + + // test('fragment not enough children', () => { + // const { container } = mountWithHydration( + // `
foo
baz
`, + // () => h('div', [[h('div', 'foo'), h('div', 'bar')], h('div', 'baz')]), + // ) + // expect(container.innerHTML).toBe( + // '
foo
bar
baz
', + // ) + // expect(`Hydration node mismatch`).toHaveBeenWarned() + // }) + + // test('fragment too many children', () => { + // const { container } = mountWithHydration( + // `
foo
bar
baz
`, + // () => h('div', [[h('div', 'foo')], h('div', 'baz')]), + // ) + // expect(container.innerHTML).toBe( + // '
foo
baz
', + // ) + // // fragment ends early and attempts to hydrate the extra
bar
+ // // as 2nd fragment child. + // expect(`Hydration text content mismatch`).toHaveBeenWarned() + // // excessive children removal + // expect(`Hydration children mismatch`).toHaveBeenWarned() + // }) + + // test('Teleport target has empty children', () => { + // const teleportContainer = document.createElement('div') + // teleportContainer.id = 'teleport' + // document.body.appendChild(teleportContainer) + + // mountWithHydration('', () => + // h(Teleport, { to: '#teleport' }, [h('span', 'value')]), + // ) + // expect(teleportContainer.innerHTML).toBe(`value`) + // expect(`Hydration children mismatch`).toHaveBeenWarned() + // }) + + // test('comment mismatch (element)', () => { + // const { container } = mountWithHydration(`
`, () => + // h('div', [createCommentVNode('hi')]), + // ) + // expect(container.innerHTML).toBe('
') + // expect(`Hydration node mismatch`).toHaveBeenWarned() + // }) + + // test('comment mismatch (text)', () => { + // const { container } = mountWithHydration(`
foobar
`, () => + // h('div', [createCommentVNode('hi')]), + // ) + // expect(container.innerHTML).toBe('
') + // expect(`Hydration node mismatch`).toHaveBeenWarned() + // }) + + // test('class mismatch', () => { + // mountWithHydration(`
`, () => + // h('div', { class: ['foo', 'bar'] }), + // ) + // mountWithHydration(`
`, () => + // h('div', { class: { foo: true, bar: true } }), + // ) + // mountWithHydration(`
`, () => + // h('div', { class: 'foo bar' }), + // ) + // // SVG classes + // mountWithHydration(``, () => + // h('svg', { class: 'foo bar' }), + // ) + // // class with different order + // mountWithHydration(`
`, () => + // h('div', { class: 'bar foo' }), + // ) + // expect(`Hydration class mismatch`).not.toHaveBeenWarned() + // mountWithHydration(`
`, () => + // h('div', { class: 'foo' }), + // ) + // expect(`Hydration class mismatch`).toHaveBeenWarned() + // }) + + // test('style mismatch', () => { + // mountWithHydration(`
`, () => + // h('div', { style: { color: 'red' } }), + // ) + // mountWithHydration(`
`, () => + // h('div', { style: `color:red;` }), + // ) + // mountWithHydration( + // `
`, + // () => h('div', { style: `font-size: 12px; color:red;` }), + // ) + // mountWithHydration(`
`, () => + // withDirectives(createVNode('div', { style: 'color: red' }, ''), [ + // [vShow, false], + // ]), + // ) + // expect(`Hydration style mismatch`).not.toHaveBeenWarned() + // mountWithHydration(`
`, () => + // h('div', { style: { color: 'green' } }), + // ) + // expect(`Hydration style mismatch`).toHaveBeenWarnedTimes(1) + // }) + + // test('style mismatch when no style attribute is present', () => { + // mountWithHydration(`
`, () => + // h('div', { style: { color: 'red' } }), + // ) + // expect(`Hydration style mismatch`).toHaveBeenWarnedTimes(1) + // }) + + // test('style mismatch w/ v-show', () => { + // mountWithHydration(`
`, () => + // withDirectives(createVNode('div', { style: 'color: red' }, ''), [ + // [vShow, false], + // ]), + // ) + // expect(`Hydration style mismatch`).not.toHaveBeenWarned() + // mountWithHydration(`
`, () => + // withDirectives(createVNode('div', { style: 'color: red' }, ''), [ + // [vShow, false], + // ]), + // ) + // expect(`Hydration style mismatch`).toHaveBeenWarnedTimes(1) + // }) + + // test('attr mismatch', () => { + // mountWithHydration(`
`, () => h('div', { id: 'foo' })) + // mountWithHydration(`
`, () => + // h('div', { spellcheck: '' }), + // ) + // mountWithHydration(`
`, () => h('div', { id: undefined })) + // // boolean + // mountWithHydration(`
`, () => + // h('select', { multiple: 'multiple' }), + // ) + // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned() + + // mountWithHydration(`
`, () => h('div', { id: 'foo' })) + // expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(1) + + // mountWithHydration(`
`, () => h('div', { id: 'foo' })) + // expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(2) + // }) + + // test('attr special case: textarea value', () => { + // mountWithHydration(``, () => + // h('textarea', { value: 'foo' }), + // ) + // mountWithHydration(``, () => + // h('textarea', { value: '' }), + // ) + // expect(`Hydration attribute mismatch`).not.toHaveBeenWarned() + + // mountWithHydration(``, () => + // h('textarea', { value: 'bar' }), + // ) + // expect(`Hydration attribute mismatch`).toHaveBeenWarned() + // }) + + // // #11873 + // test('