From: Evan You Date: Sun, 2 Feb 2025 07:53:04 +0000 (+0800) Subject: test(vapor): v-model runtime tests X-Git-Tag: v3.6.0-alpha.1~16^2~106 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f25e0d8632e50b7c2059fc5ad39d45918c28271;p=thirdparty%2Fvuejs%2Fcore.git test(vapor): v-model runtime tests --- diff --git a/packages/runtime-dom/src/directives/vModel.ts b/packages/runtime-dom/src/directives/vModel.ts index 256b915592..ee6cfcbab7 100644 --- a/packages/runtime-dom/src/directives/vModel.ts +++ b/packages/runtime-dom/src/directives/vModel.ts @@ -90,7 +90,7 @@ export const vModelTextInit = ( if (trim) { domValue = domValue.trim() } - if (number) { + if (number || el.type === 'number') { domValue = looseToNumber(domValue) } ;(set || (el as any)[assignKey])(domValue) @@ -359,7 +359,14 @@ function getCheckboxValue( checked: boolean, ) { const key = checked ? '_trueValue' : '_falseValue' - return key in el ? el[key] : checked + if (key in el) { + return el[key] + } + const attr = checked ? 'true-value' : 'false-value' + if (el.hasAttribute(attr)) { + return el.getAttribute(attr) + } + return checked } export const vModelDynamic: ObjectDirective< diff --git a/packages/runtime-vapor/__tests__/directives/vModel.spec.ts b/packages/runtime-vapor/__tests__/directives/vModel.spec.ts index 4a744a5f3b..5429cc1b3f 100644 --- a/packages/runtime-vapor/__tests__/directives/vModel.spec.ts +++ b/packages/runtime-vapor/__tests__/directives/vModel.spec.ts @@ -1,17 +1,16 @@ import { reactive, ref } from '@vue/reactivity' import { + applyCheckboxModel, + applyRadioModel, + applySelectModel, + applyTextModel, delegate, delegateEvents, on, setClass, - setDOMProp, + setProp, + setValue, template, - // @ts-expect-error - vModelDynamic, - // @ts-expect-error - vModelSelect, - // @ts-expect-error - withDirectives, } from '../../src' import { makeRender } from '../_utils' import { nextTick } from '@vue/runtime-dom' @@ -26,11 +25,11 @@ const triggerEvent = (type: string, el: Element) => { const setDOMProps = (el: any, props: Array<[key: string, value: any]>) => { props.forEach(prop => { const [key, value] = prop - key === 'class' ? setClass(el, value) : setDOMProp(el, key, value) + key === 'class' ? setClass(el, value) : setProp(el, key, value) }) } -describe.todo('directive: v-model', () => { +describe('directive: v-model', () => { test('should work with text input', async () => { const spy = vi.fn() @@ -39,8 +38,11 @@ describe.todo('directive: v-model', () => { const t0 = template('') delegateEvents('input') const n0 = t0() as HTMLInputElement - withDirectives(n0, [[vModelDynamic, () => data.value]]) - delegate(n0, 'update:modelValue', () => val => (data.value = val)) + applyTextModel( + n0, + () => data.value, + val => (data.value = val), + ) delegate(n0, 'input', () => () => spy(data.value)) return n0 }).render() @@ -70,9 +72,12 @@ describe.todo('directive: v-model', () => { const t0 = template( '', ) - const n0 = t0() as HTMLInputElement - withDirectives(n0, [[vModelSelect, () => data.value]]) - delegate(n0, 'update:modelValue', () => val => (data.value = val)) + const n0 = t0() as HTMLSelectElement + applySelectModel( + n0, + () => data.value, + val => (data.value = val), + ) on(n0, 'change', () => () => spy(data.value)) return n0 }).render() @@ -96,10 +101,12 @@ describe.todo('directive: v-model', () => { const { host } = define(() => { const t0 = template('') const n0 = t0() as HTMLInputElement - - setDOMProp(n0, 'type', 'number') - withDirectives(n0, [[vModelDynamic, () => data.value]]) - delegate(n0, 'update:modelValue', () => val => (data.value = val)) + applyTextModel( + n0, + () => data.value, + val => (data.value = val), + ) + n0.type = 'number' return n0 }).render() @@ -115,66 +122,16 @@ describe.todo('directive: v-model', () => { expect(data.value).toEqual(1) }) - test('should work with multiple listeners', async () => { - const spy = vi.fn() - - const data = ref('') - const { host } = define(() => { - const t0 = template('') - const n0 = t0() as HTMLInputElement - withDirectives(n0, [[vModelDynamic, () => data.value]]) - delegate(n0, 'update:modelValue', () => val => (data.value = val)) - delegate(n0, 'update:modelValue', () => spy) - return n0 - }).render() - - const input = host.querySelector('input')! - - input.value = 'foo' - triggerEvent('input', input) - await nextTick() - expect(data.value).toEqual('foo') - expect(spy).toHaveBeenCalledWith('foo') - }) - - test('should work with updated listeners', async () => { - const spy1 = vi.fn() - const spy2 = vi.fn() - const toggle = ref(true) - - const data = ref('') - const { host } = define(() => { - const t0 = template('') - const n0 = t0() as HTMLInputElement - withDirectives(n0, [[vModelDynamic, () => data.value]]) - delegate(n0, 'update:modelValue', () => (toggle.value ? spy1 : spy2)) - return n0 - }).render() - - const input = host.querySelector('input')! - input.value = 'foo' - triggerEvent('input', input) - await nextTick() - expect(spy1).toHaveBeenCalledWith('foo') - - // update listener - toggle.value = false - await nextTick() - - input.value = 'bar' - triggerEvent('input', input) - await nextTick() - expect(spy1).not.toHaveBeenCalledWith('bar') - expect(spy2).toHaveBeenCalledWith('bar') - }) - test('should work with textarea', async () => { const data = ref('') const { host } = define(() => { const t0 = template('