diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts index c55a9ab6104..ffe54882b52 100644 --- a/packages/runtime-core/__tests__/hydration.spec.ts +++ b/packages/runtime-core/__tests__/hydration.spec.ts @@ -10,9 +10,13 @@ import { onMounted, defineAsyncComponent, defineComponent, - createTextVNode + createTextVNode, + createVNode, + withDirectives, + vModelCheckbox } from '@vue/runtime-dom' import { renderToString, SSRContext } from '@vue/server-renderer' +import { PatchFlags } from '../../shared/src' function mountWithHydration(html: string, render: () => any) { const container = document.createElement('div') @@ -761,6 +765,36 @@ describe('SSR hydration', () => { ) }) + 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 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) + }) + describe('mismatch handling', () => { test('text node', () => { const { container } = mountWithHydration(`foo`, () => 'bar') diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts index f4f7ea4795a..94c221db195 100644 --- a/packages/runtime-core/src/hydration.ts +++ b/packages/runtime-core/src/hydration.ts @@ -264,21 +264,28 @@ export function createHydrationFunctions( optimized: boolean ) => { optimized = optimized || !!vnode.dynamicChildren - const { props, patchFlag, shapeFlag, dirs } = vnode + const { type, props, patchFlag, shapeFlag, dirs } = vnode + // #4006 for form elements with non-string v-model value bindings + // e.g.