wip: add tests + skip fragment end anchor

This commit is contained in:
daiwei 2025-04-24 09:26:33 +08:00
parent 04eadd859a
commit b5762b57ae
2 changed files with 194 additions and 2 deletions

View File

@ -264,6 +264,48 @@ describe('Vapor Mode hydration', () => {
) )
}) })
test('nested components with anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><components.Parent/></template>
`,
{
Parent: `<template><div><span/><components.Child/><span/></div></template>`,
Child: `<template><div>{{ data }}</div></template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div>foo</div><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div>bar</div><span></span></div>"`,
)
})
test('nested components with multi level anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><div><span></span><components.Parent/><span></span></div></template>
`,
{
Parent: `<template><div><span/><components.Child/><span/></div></template>`,
Child: `<template><div>{{ data }}</div></template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div><span></span><div>foo</div><span></span></div><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div><span></span><div>bar</div><span></span></div><span></span></div>"`,
)
})
test('consecutive components with anchor insertion', async () => { test('consecutive components with anchor insertion', async () => {
const { container, data } = await testHydration( const { container, data } = await testHydration(
`<template> `<template>
@ -290,6 +332,48 @@ describe('Vapor Mode hydration', () => {
) )
}) })
test('nested consecutive components with anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><components.Parent/></template>
`,
{
Parent: `<template><div><span/><components.Child/><components.Child/><span/></div></template>`,
Child: `<template><div>{{ data }}</div></template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div>foo</div><!--[[--><div>foo</div><!--]]--><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div>bar</div><!--[[--><div>bar</div><!--]]--><span></span></div>"`,
)
})
test('nested consecutive components with multi level anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><div><span></span><components.Parent/><span></span></div></template>
`,
{
Parent: `<template><div><span/><components.Child/><components.Child/><span/></div></template>`,
Child: `<template><div>{{ data }}</div></template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div><span></span><div>foo</div><!--[[--><div>foo</div><!--]]--><span></span></div><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div><span></span><div>bar</div><!--[[--><div>bar</div><!--]]--><span></span></div><span></span></div>"`,
)
})
test('mixed component and element with anchor insertion', async () => { test('mixed component and element with anchor insertion', async () => {
const { container, data } = await testHydration( const { container, data } = await testHydration(
`<template> `<template>
@ -369,6 +453,48 @@ describe('Vapor Mode hydration', () => {
) )
}) })
test('nested fragment component with anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><components.Parent/></template>
`,
{
Parent: `<template><div><span/><components.Child/><span/></div></template>`,
Child: `<template><div>{{ data }}</div>-{{ data }}-</template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><!--[--><div>foo</div>-foo-<!--]--><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><!--[--><div>bar</div>-bar-<!--]--><span></span></div>"`,
)
})
test('nested fragment component with multi level anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><div><span/><components.Parent/><span/></div></template>
`,
{
Parent: `<template><div><span/><components.Child/><span/></div></template>`,
Child: `<template><div>{{ data }}</div>-{{ data }}-</template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div><span></span><!--[--><div>foo</div>-foo-<!--]--><span></span></div><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div><span></span><!--[--><div>bar</div>-bar-<!--]--><span></span></div><span></span></div>"`,
)
})
test('consecutive fragment components with anchor insertion', async () => { test('consecutive fragment components with anchor insertion', async () => {
const { container, data } = await testHydration( const { container, data } = await testHydration(
`<template> `<template>
@ -395,6 +521,69 @@ describe('Vapor Mode hydration', () => {
) )
}) })
test('nested consecutive fragment components with anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><components.Parent/></template>
`,
{
Parent: `<template><div><span/><components.Child/><components.Child/><span/></div></template>`,
Child: `<template><div>{{ data }}</div>-{{ data }}-</template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><!--[--><div>foo</div>-foo-<!--]--><!--[[--><!--[--><div>foo</div>-foo-<!--]--><!--]]--><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><!--[--><div>bar</div>-bar-<!--]--><!--[[--><!--[--><div>bar</div>-bar-<!--]--><!--]]--><span></span></div>"`,
)
})
test('nested consecutive fragment components with multi level anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><div><span></span><components.Parent/><span></span></div></template>
`,
{
Parent: `<template><div><span/><components.Child/><components.Child/><span/></div></template>`,
Child: `<template><div>{{ data }}</div>-{{ data }}-</template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div><span></span><!--[--><div>foo</div>-foo-<!--]--><!--[[--><!--[--><div>foo</div>-foo-<!--]--><!--]]--><span></span></div><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><div><span></span><!--[--><div>bar</div>-bar-<!--]--><!--[[--><!--[--><div>bar</div>-bar-<!--]--><!--]]--><span></span></div><span></span></div>"`,
)
})
test('nested consecutive fragment components with root level anchor insertion', async () => {
const { container, data } = await testHydration(
`
<template><div><span></span><components.Parent/><span></span></div></template>
`,
{
Parent: `<template><components.Child/><components.Child/></template>`,
Child: `<template><div>{{ data }}</div>-{{ data }}-</template>`,
},
)
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><!--[--><!--[--><div>foo</div>-foo-<!--]--><!--[--><div>foo</div>-foo-<!--]--><!--]--><span></span></div>"`,
)
data.value = 'bar'
await nextTick()
expect(container.innerHTML).toMatchInlineSnapshot(
`"<div><span></span><!--[--><!--[--><div>bar</div>-bar-<!--]--><!--[--><div>bar</div>-bar-<!--]--><!--]--><span></span></div>"`,
)
})
test('mixed fragment component and element with anchor insertion', async () => { test('mixed fragment component and element with anchor insertion', async () => {
const { container, data } = await testHydration( const { container, data } = await testHydration(
`<template> `<template>

View File

@ -53,8 +53,11 @@ function __next(node: Node): Node {
} }
let n = node.nextSibling! let n = node.nextSibling!
// skip dynamic anchors and empty text nodes // skip if:
while (n && (isDynamicAnchor(n) || isEmptyText(n))) { // - dynamic anchors (<!--[[-->, <!--]]-->)
// - fragment end anchor (`<!--]-->`)
// - empty text nodes
while (n && (isDynamicAnchor(n) || isComment(n, ']') || isEmptyText(n))) {
n = n.nextSibling! n = n.nextSibling!
} }
return n return n