expect(`Hydration children mismatch`).toHaveBeenWarned()
})
+ test('children mismatch is checked once when removing excess nodes', () => {
+ const hasAttribute = vi.spyOn(Element.prototype, 'hasAttribute')
+
+ try {
+ const { container } = mountWithHydration(
+ `<div><span>foo</span><span>bar</span><span>baz</span></div>`,
+ () => h('div', [h('span', 'foo')]),
+ )
+ const el = container.firstChild as Element
+ const allowMismatchCheckCount = hasAttribute.mock.calls.filter(
+ ([key], i) =>
+ key === 'data-allow-mismatch' &&
+ hasAttribute.mock.contexts[i] === el,
+ ).length
+
+ expect(container.innerHTML).toBe('<div><span>foo</span></div>')
+ expect(`Hydration children mismatch`).toHaveBeenWarnedTimes(1)
+ expect(allowMismatchCheckCount).toBe(1)
+ } finally {
+ hasAttribute.mockRestore()
+ }
+ })
+
+ test('children mismatch is checked once when mounting missing nodes', () => {
+ const hasAttribute = vi.spyOn(Element.prototype, 'hasAttribute')
+
+ try {
+ const { container } = mountWithHydration(`<div></div>`, () =>
+ h('div', [h('span', 'foo'), h('span', 'bar'), h('span', 'baz')]),
+ )
+ const el = container.firstChild as Element
+ const allowMismatchCheckCount = hasAttribute.mock.calls.filter(
+ ([key], i) =>
+ key === 'data-allow-mismatch' &&
+ hasAttribute.mock.contexts[i] === el,
+ ).length
+
+ expect(container.innerHTML).toBe(
+ '<div><span>foo</span><span>bar</span><span>baz</span></div>',
+ )
+ expect(`Hydration children mismatch`).toHaveBeenWarnedTimes(1)
+ expect(allowMismatchCheckCount).toBe(1)
+ } finally {
+ hasAttribute.mockRestore()
+ }
+ })
+
test('complete mismatch', () => {
const { container } = mountWithHydration(
`<div><span>foo</span><span>bar</span></div>`,
slotScopeIds,
optimized,
)
- let hasWarned = false
+ if (next && !isMismatchAllowed(el, MismatchTypes.CHILDREN)) {
+ ;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
+ warn(
+ `Hydration children mismatch on`,
+ el,
+ `\nServer rendered element contains more child nodes than client vdom.`,
+ )
+ logMismatchError()
+ }
while (next) {
- if (!isMismatchAllowed(el, MismatchTypes.CHILDREN)) {
- if (
- (__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
- !hasWarned
- ) {
- warn(
- `Hydration children mismatch on`,
- el,
- `\nServer rendered element contains more child nodes than client vdom.`,
- )
- hasWarned = true
- }
- logMismatchError()
- }
-
// The SSRed DOM contains more nodes than it should. Remove them.
const cur = next
next = next.nextSibling
optimized = optimized || !!parentVNode.dynamicChildren
const children = parentVNode.children as VNode[]
const l = children.length
- let hasWarned = false
+ let hasCheckedMismatch = false
for (let i = 0; i < l; i++) {
const vnode = optimized
? children[i]
// because server rendered HTML won't contain a text node
insert((vnode.el = createText('')), container)
} else {
- if (!isMismatchAllowed(container, MismatchTypes.CHILDREN)) {
- if (
- (__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
- !hasWarned
- ) {
- warn(
- `Hydration children mismatch on`,
- container,
- `\nServer rendered element contains fewer child nodes than client vdom.`,
- )
- hasWarned = true
+ if (!hasCheckedMismatch) {
+ hasCheckedMismatch = true
+ if (!isMismatchAllowed(container, MismatchTypes.CHILDREN)) {
+ ;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
+ warn(
+ `Hydration children mismatch on`,
+ container,
+ `\nServer rendered element contains fewer child nodes than client vdom.`,
+ )
+ logMismatchError()
}
- logMismatchError()
}
// the SSRed DOM didn't contain enough nodes. Mount the missing ones.