import { BindingTypes } from '@vue/compiler-core' import { assertCode, compileSFCScript as compile } from '../utils' describe('defineModel()', () => { test('basic usage', () => { const { content, bindings } = compile( ` `, ) assertCode(content) expect(content).toMatch('props: {') expect(content).toMatch('"modelValue": { required: true },') expect(content).toMatch('"count": {},') expect(content).toMatch('"toString": { type: Function },') expect(content).toMatch( 'emits: ["update:modelValue", "update:count", "update:toString"],', ) expect(content).toMatch( `const modelValue = _useModel(__props, "modelValue")`, ) expect(content).toMatch(`const c = _useModel(__props, 'count')`) expect(content).toMatch(`const toString = _useModel(__props, 'toString')`) expect(content).toMatch(`return { modelValue, c, toString }`) expect(content).not.toMatch('defineModel') expect(bindings).toStrictEqual({ modelValue: BindingTypes.SETUP_REF, count: BindingTypes.PROPS, c: BindingTypes.SETUP_REF, toString: BindingTypes.SETUP_REF, }) }) test('w/ template literal name', () => { const { content, bindings } = compile( ` `, ) assertCode(content) expect(content).toMatch('"x": { default: 100 },') expect(content).toMatch('"y": { default: 200 },') expect(content).toMatch('emits: ["update:x", "update:y"],') expect(content).toMatch('const x = _useModel(__props, `x`)') expect(content).toMatch('const y = _useModel(__props, `y`)') expect(content).not.toMatch('defineModel') expect(bindings).toStrictEqual({ x: BindingTypes.SETUP_REF, y: BindingTypes.SETUP_REF, }) }) test('w/ template literal name with expressions falls back to modelValue', () => { const { content } = compile( ` `, ) assertCode(content) expect(content).toMatch('"modelValue":') expect(content).toMatch('_useModel(__props, "modelValue",') }) test('w/ defineProps and defineEmits', () => { const { content, bindings } = compile( ` `, ) assertCode(content) expect(content).toMatch(`props: /*@__PURE__*/_mergeModels({ foo: String }`) expect(content).toMatch(`"modelValue": { default: 0 }`) expect(content).toMatch(`const count = _useModel(__props, "modelValue")`) expect(content).not.toMatch('defineModel') expect(bindings).toStrictEqual({ count: BindingTypes.SETUP_REF, foo: BindingTypes.PROPS, modelValue: BindingTypes.PROPS, }) }) test('w/ array props', () => { const { content, bindings } = compile( ` `, ) assertCode(content) expect(content).toMatch(`props: /*@__PURE__*/_mergeModels(['foo', 'bar'], { "count": {}, "countModifiers": {}, })`) expect(content).toMatch(`const count = _useModel(__props, 'count')`) expect(content).not.toMatch('defineModel') expect(bindings).toStrictEqual({ foo: BindingTypes.PROPS, bar: BindingTypes.PROPS, count: BindingTypes.SETUP_REF, }) }) test('w/ types, basic usage', () => { const { content, bindings } = compile( ` `, ) assertCode(content) expect(content).toMatch('"modelValue": { type: [Boolean, String] }') expect(content).toMatch('"modelModifiers": {}') expect(content).toMatch('"count": { type: Number }') expect(content).toMatch( '"disabled": { type: Number, ...{ required: false } }', ) expect(content).toMatch('"any": { type: Boolean, skipCheck: true }') expect(content).toMatch( 'emits: ["update:modelValue", "update:count", "update:disabled", "update:any"]', ) expect(content).toMatch( `const modelValue = _useModel(__props, "modelValue")`, ) expect(content).toMatch(`const count = _useModel(__props, 'count')`) expect(content).toMatch( `const disabled = _useModel(__props, 'disabled')`, ) expect(content).toMatch( `const any = _useModel(__props, 'any')`, ) expect(bindings).toStrictEqual({ modelValue: BindingTypes.SETUP_REF, count: BindingTypes.SETUP_REF, disabled: BindingTypes.SETUP_REF, any: BindingTypes.SETUP_REF, }) }) test('w/ types, production mode', () => { const { content, bindings } = compile( ` `, { isProd: true }, ) assertCode(content) expect(content).toMatch('"modelValue": { type: Boolean }') expect(content).toMatch('"fn": {}') expect(content).toMatch( '"fnWithDefault": { type: Function, ...{ default: () => null } },', ) expect(content).toMatch('"str": {}') expect(content).toMatch('"optional": { required: false }') expect(content).toMatch( 'emits: ["update:modelValue", "update:fn", "update:fnWithDefault", "update:str", "update:optional"]', ) expect(content).toMatch( `const modelValue = _useModel(__props, "modelValue")`, ) expect(content).toMatch(`const fn = _useModel<() => void>(__props, 'fn')`) expect(content).toMatch(`const str = _useModel(__props, 'str')`) expect(bindings).toStrictEqual({ modelValue: BindingTypes.SETUP_REF, fn: BindingTypes.SETUP_REF, fnWithDefault: BindingTypes.SETUP_REF, str: BindingTypes.SETUP_REF, optional: BindingTypes.SETUP_REF, }) }) test('w/ types, production mode, boolean + multiple types', () => { const { content } = compile( ` `, { isProd: true }, ) assertCode(content) expect(content).toMatch('"modelValue": { type: [Boolean, String, Object] }') }) test('w/ types, production mode, function + runtime opts + multiple types', () => { const { content } = compile( ` `, { isProd: true }, ) assertCode(content) expect(content).toMatch( '"modelValue": { type: [Number, Function], ...{ default: () => 1 } }', ) }) test('get / set transformers', () => { const { content } = compile( ` `, ) assertCode(content) expect(content).toMatch(/"modelValue": {\s+required: true,?\s+}/m) expect(content).toMatch( `_useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })`, ) const { content: content2 } = compile( ` `, ) assertCode(content2) expect(content2).toMatch( /"modelValue": {\s+default: 0,\s+required: true,?\s+}/m, ) expect(content2).toMatch( `_useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })`, ) }) test('usage w/ props destructure', () => { const { content } = compile( ` `, { propsDestructure: true }, ) assertCode(content) expect(content).toMatch(`set: (v) => { return v + __props.x }`) }) test('w/ Boolean And Function types, production mode', () => { const { content, bindings } = compile( ` `, { isProd: true }, ) assertCode(content) expect(content).toMatch('"modelValue": { type: [Boolean, String] }') expect(content).toMatch('emits: ["update:modelValue"]') expect(content).toMatch( `const modelValue = _useModel(__props, "modelValue")`, ) expect(bindings).toStrictEqual({ modelValue: BindingTypes.SETUP_REF, }) }) })