test(compiler-vapor): v-model (#132)

Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
This commit is contained in:
FireBushtree 2024-02-21 17:08:20 +08:00 committed by GitHub
parent ebc157c84c
commit ba29b4c89a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 410 additions and 3 deletions

View File

@ -0,0 +1,236 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`compiler: vModel transform > modifiers > .lazy 1`] = `
"import { children as _children, vModelText as _vModelText, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelText, () => _ctx.model, void 0, { lazy: true }]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > modifiers > .number 1`] = `
"import { children as _children, vModelText as _vModelText, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelText, () => _ctx.model, void 0, { number: true }]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > modifiers > .trim 1`] = `
"import { children as _children, vModelText as _vModelText, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelText, () => _ctx.model, void 0, { trim: true }]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should support input (checkbox) 1`] = `
"import { children as _children, vModelCheckbox as _vModelCheckbox, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"checkbox\\">")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelCheckbox, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should support input (dynamic type) 1`] = `
"import { children as _children, vModelDynamic as _vModelDynamic, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelDynamic, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should support input (radio) 1`] = `
"import { children as _children, vModelRadio as _vModelRadio, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"radio\\">")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelRadio, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should support input (text) 1`] = `
"import { children as _children, vModelText as _vModelText, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"text\\">")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelText, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should support select 1`] = `
"import { children as _children, vModelSelect as _vModelSelect, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<select></select>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelSelect, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should support simple expression 1`] = `
"import { children as _children, vModelText as _vModelText, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelText, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should support textarea 1`] = `
"import { children as _children, vModelText as _vModelText, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<textarea></textarea>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelText, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should support w/ dynamic v-bind 1`] = `
"import { children as _children, vModelDynamic as _vModelDynamic, withDirectives as _withDirectives, on as _on, renderEffect as _renderEffect, setDynamicProps as _setDynamicProps, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelDynamic, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
_renderEffect(() => _setDynamicProps(n1, _ctx.obj))
return n0
}"
`;
exports[`compiler: vModel transform > should support w/ dynamic v-bind 2`] = `
"import { children as _children, vModelDynamic as _vModelDynamic, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelDynamic, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should work with input (checkbox) 1`] = `
"import { children as _children, vModelCheckbox as _vModelCheckbox, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"checkbox\\">")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelCheckbox, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should work with input (dynamic type) 1`] = `
"import { children as _children, vModelDynamic as _vModelDynamic, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelDynamic, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should work with input (radio) 1`] = `
"import { children as _children, vModelRadio as _vModelRadio, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"radio\\">")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelRadio, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should work with input (text) 1`] = `
"import { children as _children, vModelText as _vModelText, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input type=\\"text\\">")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelText, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should work with select 1`] = `
"import { children as _children, vModelSelect as _vModelSelect, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<select></select>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelSelect, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;
exports[`compiler: vModel transform > should work with simple expression 1`] = `
"import { children as _children, vModelText as _vModelText, withDirectives as _withDirectives, on as _on, template as _template } from 'vue/vapor';
const t0 = _template("<input>")
export function render(_ctx) {
const n0 = t0()
const n1 = _children(n0, 0)
_withDirectives(n1, [[_vModelText, () => _ctx.model]])
_on(n1, "update:modelValue", $event => (_ctx.model = $event))
return n0
}"
`;

View File

@ -1,4 +1,174 @@
// TODO: add tests for this transform
describe('compiler: vModel transform', () => {
test.todo('basic')
import { makeCompile } from './_utils'
import { transformElement, transformVModel } from '../../src'
import { DOMErrorCodes } from '@vue/compiler-dom'
const compileWithVModel = makeCompile({
nodeTransforms: [transformElement],
directiveTransforms: {
model: transformVModel,
},
})
describe('compiler: vModel transform', () => {
test('should support simple expression', () => {
const { code, vaporHelpers } = compileWithVModel(
'<input v-model="model" />',
)
expect(vaporHelpers).toContain('vModelText')
expect(code).toMatchSnapshot()
})
test('should support input (text)', () => {
const { code, vaporHelpers } = compileWithVModel(
'<input type="text" v-model="model" />',
)
expect(vaporHelpers).toContain('vModelText')
expect(code).toMatchSnapshot()
})
test('should support input (radio)', () => {
const { code, vaporHelpers } = compileWithVModel(
'<input type="radio" v-model="model" />',
)
expect(vaporHelpers).toContain('vModelRadio')
expect(code).toMatchSnapshot()
})
test('should support input (checkbox)', () => {
const { code, vaporHelpers } = compileWithVModel(
'<input type="checkbox" v-model="model" />',
)
expect(vaporHelpers).toContain('vModelCheckbox')
expect(code).toMatchSnapshot()
})
test('should support select', () => {
const { code, vaporHelpers } = compileWithVModel(
'<select v-model="model" />',
)
expect(vaporHelpers).toContain('vModelSelect')
expect(code).toMatchSnapshot()
})
test('should support textarea', () => {
const { code, vaporHelpers } = compileWithVModel(
'<textarea v-model="model" />',
)
expect(vaporHelpers).toContain('vModelText')
expect(code).toMatchSnapshot()
})
test('should support input (dynamic type)', () => {
const { code, vaporHelpers } = compileWithVModel(
'<input :type="foo" v-model="model" />',
)
expect(vaporHelpers).toContain('vModelDynamic')
expect(code).toMatchSnapshot()
})
test('should support w/ dynamic v-bind', () => {
const root1 = compileWithVModel('<input v-bind="obj" v-model="model" />')
expect(root1.vaporHelpers).toContain('vModelDynamic')
expect(root1.code).toMatchSnapshot()
const root2 = compileWithVModel(
'<input v-bind:[key]="val" v-model="model" />',
)
expect(root2.vaporHelpers).toContain('vModelDynamic')
expect(root2.code).toMatchSnapshot()
})
describe('errors', () => {
test('invalid element', () => {
const onError = vi.fn()
compileWithVModel('<span v-model="model" />', { onError })
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_MODEL_ON_INVALID_ELEMENT,
}),
)
})
// TODO: component
test.fails('plain elements with argument', () => {
const onError = vi.fn()
compileWithVModel('<input v-model:value="model" />', { onError })
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_MODEL_ARG_ON_ELEMENT,
}),
)
})
// TODO: component
test.fails('should allow usage on custom element', () => {
const onError = vi.fn()
const root = compileWithVModel('<my-input v-model="model" />', {
onError,
isCustomElement: tag => tag.startsWith('my-'),
})
expect(root.helpers).toContain('vModelText')
expect(onError).not.toHaveBeenCalled()
})
test('should raise error if used file input element', () => {
const onError = vi.fn()
compileWithVModel(`<input type="file" v-model="test"/>`, {
onError,
})
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_MODEL_ON_FILE_INPUT_ELEMENT,
}),
)
})
test('should error on dynamic value binding alongside v-model', () => {
const onError = vi.fn()
compileWithVModel(`<input v-model="test" :value="test" />`, {
onError,
})
expect(onError).toHaveBeenCalledWith(
expect.objectContaining({
code: DOMErrorCodes.X_V_MODEL_UNNECESSARY_VALUE,
}),
)
})
// #3596
test('should NOT error on static value binding alongside v-model', () => {
const onError = vi.fn()
compileWithVModel(`<input v-model="test" value="test" />`, {
onError,
})
expect(onError).not.toHaveBeenCalled()
})
})
describe('modifiers', () => {
test('.number', () => {
const { code } = compileWithVModel('<input v-model.number="model" />')
expect(code).toMatchSnapshot()
})
test('.trim', () => {
const { code } = compileWithVModel('<input v-model.trim="model" />')
expect(code).toMatchSnapshot()
})
test('.lazy', () => {
const { code } = compileWithVModel('<input v-model.lazy="model" />')
expect(code).toMatchSnapshot()
})
})
})

View File

@ -19,3 +19,4 @@ export { transformVShow } from './transforms/vShow'
export { transformVText } from './transforms/vText'
export { transformVIf } from './transforms/vIf'
export { transformVFor } from './transforms/vFor'
export { transformVModel } from './transforms/vModel'