Skip to content

Commit 690f256

Browse files
committed
wip: test attr mismatch
1 parent e4fcb9d commit 690f256

File tree

2 files changed

+107
-51
lines changed

2 files changed

+107
-51
lines changed

packages/runtime-vapor/__tests__/hydration.spec.ts

Lines changed: 91 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3251,45 +3251,97 @@ describe('Vapor Mode hydration', () => {
32513251
expect(`Hydration style mismatch`).toHaveBeenWarned()
32523252
})
32533253

3254-
// test('attr mismatch', () => {
3255-
// mountWithHydration(`<div id="foo"></div>`, () => h('div', { id: 'foo' }))
3256-
// mountWithHydration(`<div spellcheck></div>`, () =>
3257-
// h('div', { spellcheck: '' }),
3258-
// )
3259-
// mountWithHydration(`<div></div>`, () => h('div', { id: undefined }))
3260-
// // boolean
3261-
// mountWithHydration(`<select multiple></div>`, () =>
3262-
// h('select', { multiple: true }),
3263-
// )
3264-
// mountWithHydration(`<select multiple></div>`, () =>
3265-
// h('select', { multiple: 'multiple' }),
3266-
// )
3267-
// expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
3268-
// mountWithHydration(`<div></div>`, () => h('div', { id: 'foo' }))
3269-
// expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(1)
3270-
// mountWithHydration(`<div id="bar"></div>`, () => h('div', { id: 'foo' }))
3271-
// expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(2)
3272-
// })
3273-
// test('attr special case: textarea value', () => {
3274-
// mountWithHydration(`<textarea>foo</textarea>`, () =>
3275-
// h('textarea', { value: 'foo' }),
3276-
// )
3277-
// mountWithHydration(`<textarea></textarea>`, () =>
3278-
// h('textarea', { value: '' }),
3279-
// )
3280-
// expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
3281-
// mountWithHydration(`<textarea>foo</textarea>`, () =>
3282-
// h('textarea', { value: 'bar' }),
3283-
// )
3284-
// expect(`Hydration attribute mismatch`).toHaveBeenWarned()
3285-
// })
3286-
// // #11873
3287-
// test('<textarea> with newlines at the beginning', async () => {
3288-
// const render = () => h('textarea', null, '\nhello')
3289-
// const html = await renderToString(createSSRApp({ render }))
3290-
// mountWithHydration(html, render)
3291-
// expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
3292-
// })
3254+
test('attr mismatch', async () => {
3255+
await mountWithHydration(
3256+
`<div id="foo"></div>`,
3257+
`<div :id="data"></div>`,
3258+
ref('foo'),
3259+
)
3260+
3261+
await mountWithHydration(
3262+
`<div spellcheck></div>`,
3263+
`<div :spellcheck="data"></div>`,
3264+
ref(''),
3265+
)
3266+
3267+
await mountWithHydration(
3268+
`<div></div>`,
3269+
`<div :id="data"></div>`,
3270+
ref(undefined),
3271+
)
3272+
3273+
// boolean
3274+
await mountWithHydration(
3275+
`<select multiple></div>`,
3276+
`<select :multiple="data"></select>`,
3277+
ref(true),
3278+
)
3279+
3280+
await mountWithHydration(
3281+
`<select multiple></div>`,
3282+
`<select :multiple="data"></select>`,
3283+
ref('multiple'),
3284+
)
3285+
3286+
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
3287+
await mountWithHydration(
3288+
`<div></div>`,
3289+
`<div :id="data"></div>`,
3290+
ref('foo'),
3291+
)
3292+
expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(1)
3293+
3294+
await mountWithHydration(
3295+
`<div id="bar"></div>`,
3296+
`<div :id="data"></div>`,
3297+
ref('foo'),
3298+
)
3299+
expect(`Hydration attribute mismatch`).toHaveBeenWarnedTimes(2)
3300+
})
3301+
3302+
test('attr special case: textarea value', async () => {
3303+
await mountWithHydration(
3304+
`<textarea>foo</textarea>`,
3305+
`<textarea :value="data"></textarea>`,
3306+
ref('foo'),
3307+
)
3308+
3309+
await mountWithHydration(
3310+
`<textarea></textarea>`,
3311+
`<textarea :value="data"></textarea>`,
3312+
ref(''),
3313+
)
3314+
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
3315+
3316+
await mountWithHydration(
3317+
`<textarea>foo</textarea>`,
3318+
`<textarea :value="data"></textarea>`,
3319+
ref('bar'),
3320+
)
3321+
expect(`Hydration attribute mismatch`).toHaveBeenWarned()
3322+
})
3323+
3324+
test('<textarea> with newlines at the beginning', async () => {
3325+
await mountWithHydration(
3326+
`<textarea>\nhello</textarea>`,
3327+
`<textarea :value="data"></textarea>`,
3328+
ref('\nhello'),
3329+
)
3330+
3331+
await mountWithHydration(
3332+
`<textarea>\nhello</textarea>`,
3333+
`<textarea v-text="data"></textarea>`,
3334+
ref('\nhello'),
3335+
)
3336+
3337+
await mountWithHydration(
3338+
`<textarea>\nhello</textarea>`,
3339+
`<textarea v-bind="data"></textarea>`,
3340+
ref({ textContent: '\nhello' }),
3341+
)
3342+
expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
3343+
})
3344+
32933345
// test('<pre> with newlines at the beginning', async () => {
32943346
// const render = () => h('pre', null, '\n')
32953347
// const html = await renderToString(createSSRApp({ render }))

packages/runtime-vapor/src/dom/prop.ts

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ export function setValue(el: TargetElement, value: any): void {
233233
if (
234234
(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
235235
isHydrating &&
236-
!attributeHasMismatch(el, 'value', value)
236+
!attributeHasMismatch(el, 'value', getClientText(el, value))
237237
) {
238238
return
239239
}
@@ -257,8 +257,9 @@ export function setValue(el: TargetElement, value: any): void {
257257
*/
258258
export function setText(el: Text & { $txt?: string }, value: string): void {
259259
if (isHydrating) {
260-
if (el.nodeValue == value) {
261-
el.$txt = value
260+
const clientText = getClientText(el.parentNode!, value)
261+
if (el.nodeValue == clientText) {
262+
el.$txt = clientText
262263
return
263264
}
264265

@@ -286,15 +287,7 @@ export function setElementText(
286287
): void {
287288
value = toDisplayString(value)
288289
if (isHydrating) {
289-
let clientText = value as string
290-
if (
291-
clientText[0] === '\n' &&
292-
((el as Element).tagName === 'PRE' ||
293-
(el as Element).tagName === 'TEXTAREA')
294-
) {
295-
clientText = clientText.slice(1)
296-
}
297-
290+
let clientText = getClientText(el, value as string)
298291
if (el.textContent === clientText) {
299292
el.$txt = clientText
300293
return
@@ -487,3 +480,14 @@ function attributeHasMismatch(el: any, key: string, value: any): boolean {
487480
}
488481
return false
489482
}
483+
484+
function getClientText(el: Node, value: string): string {
485+
if (
486+
value[0] === '\n' &&
487+
((el as Element).tagName === 'PRE' ||
488+
(el as Element).tagName === 'TEXTAREA')
489+
) {
490+
value = value.slice(1)
491+
}
492+
return value
493+
}

0 commit comments

Comments
 (0)