import Vue from '@vue/compat' import type { ComponentOptions } from '../../runtime-core/src/component' import { nextTick } from '../../runtime-core/src/scheduler' import { DeprecationTypes, deprecationData, toggleDeprecationWarning, } from '../../runtime-core/src/compat/compatConfig' import { triggerEvent } from './utils' beforeEach(() => { toggleDeprecationWarning(true) Vue.configureCompat({ MODE: 2, GLOBAL_MOUNT: 'suppress-warning', }) }) afterEach(() => { toggleDeprecationWarning(false) Vue.configureCompat({ MODE: 3 }) }) describe('COMPONENT_V_MODEL', () => { async function runTest(CustomInput: ComponentOptions) { const vm = new Vue({ data() { return { text: 'foo', } }, components: { CustomInput }, template: `
{{ text }}
`, }).$mount() as any const input = vm.$el.querySelector('input') const span = vm.$el.querySelector('span') expect(input.value).toBe('foo') expect(span.textContent).toBe('foo') expect( (deprecationData[DeprecationTypes.COMPONENT_V_MODEL].message as Function)( CustomInput, ), ).toHaveBeenWarned() input.value = 'bar' triggerEvent(input, 'input') await nextTick() expect(input.value).toBe('bar') expect(span.textContent).toBe('bar') vm.text = 'baz' await nextTick() expect(input.value).toBe('baz') expect(span.textContent).toBe('baz') } test('basic usage', async () => { await runTest({ name: 'CustomInput', props: ['value'], template: ``, }) }) test('with model option', async () => { await runTest({ name: 'CustomInput', props: ['input'], model: { prop: 'input', event: 'update', }, template: ``, }) }) async function runTestWithModifier(CustomInput: ComponentOptions) { const vm = new Vue({ data() { return { text: ' foo ', } }, components: { CustomInput, }, template: `
{{ text }}
`, }).$mount() as any const input = vm.$el.querySelector('input') const span = vm.$el.querySelector('span') expect(input.value).toBe(' foo ') expect(span.textContent).toBe(' foo ') expect( (deprecationData[DeprecationTypes.COMPONENT_V_MODEL].message as Function)( CustomInput, ), ).toHaveBeenWarned() input.value = ' bar ' triggerEvent(input, 'input') await nextTick() expect(input.value).toBe('bar') expect(span.textContent).toBe('bar') } test('with model modifiers', async () => { await runTestWithModifier({ name: 'CustomInput', props: ['value'], template: ``, }) }) test('with model modifiers and model option', async () => { await runTestWithModifier({ name: 'CustomInput', props: ['foo'], model: { prop: 'foo', event: 'bar', }, template: ``, }) }) // #14202 test('should handle v-model deprecation warning with missing appContext', async () => { const ChildComponent = { template: `
{{ value }}
`, props: ['value'], } const vm = new Vue({ components: { ChildComponent }, data() { return { myVal: 'initial', } }, template: `
`, }).$mount() as any expect(vm.$el.textContent).toContain('initial') expect( (deprecationData[DeprecationTypes.COMPONENT_V_MODEL].message as Function)( ChildComponent, ), ).toHaveBeenWarned() // Should work correctly const child = vm.$el.querySelector('div') child.click() await nextTick() expect(vm.myVal).toBe('new val') expect(vm.$el.textContent).toContain('new val') }) })