wip: move compat test cases + filter tests
This commit is contained in:
62
packages/vue-compat/__tests__/componentAsync.spec.ts
Normal file
62
packages/vue-compat/__tests__/componentAsync.spec.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import Vue from '@vue/compat'
|
||||
import {
|
||||
DeprecationTypes,
|
||||
deprecationData,
|
||||
toggleDeprecationWarning
|
||||
} from '../../runtime-core/src/compat/compatConfig'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(true)
|
||||
Vue.configureCompat({
|
||||
MODE: 2,
|
||||
GLOBAL_MOUNT: 'suppress-warning'
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({ MODE: 3 })
|
||||
})
|
||||
|
||||
const timeout = (n: number) => new Promise(r => setTimeout(r, n))
|
||||
|
||||
describe('COMPONENT_ASYNC', () => {
|
||||
test('resolve/reject', async () => {
|
||||
let resolve: any
|
||||
const comp = (r: any) => {
|
||||
resolve = r
|
||||
}
|
||||
const vm = new Vue({
|
||||
template: `<div><comp/></div>`,
|
||||
components: { comp }
|
||||
}).$mount()
|
||||
expect(vm.$el.innerHTML).toBe(`<!---->`)
|
||||
|
||||
resolve({ template: 'foo' })
|
||||
await timeout(0)
|
||||
expect(vm.$el.innerHTML).toBe(`foo`)
|
||||
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.COMPONENT_ASYNC].message as Function)(
|
||||
comp
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('Promise', async () => {
|
||||
const comp = () => Promise.resolve({ template: 'foo' })
|
||||
const vm = new Vue({
|
||||
template: `<div><comp/></div>`,
|
||||
components: { comp }
|
||||
}).$mount()
|
||||
expect(vm.$el.innerHTML).toBe(`<!---->`)
|
||||
await timeout(0)
|
||||
expect(vm.$el.innerHTML).toBe(`foo`)
|
||||
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.COMPONENT_ASYNC].message as Function)(
|
||||
comp
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
61
packages/vue-compat/__tests__/componentFunctional.spec.ts
Normal file
61
packages/vue-compat/__tests__/componentFunctional.spec.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import Vue from '@vue/compat'
|
||||
import {
|
||||
DeprecationTypes,
|
||||
deprecationData,
|
||||
toggleDeprecationWarning
|
||||
} from '../../runtime-core/src/compat/compatConfig'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(true)
|
||||
Vue.configureCompat({
|
||||
MODE: 2,
|
||||
GLOBAL_MOUNT: 'suppress-warning'
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({ MODE: 3 })
|
||||
})
|
||||
|
||||
test('COMPONENT_FUNCTIONAL', async () => {
|
||||
const func = {
|
||||
name: 'Func',
|
||||
functional: true,
|
||||
props: {
|
||||
x: String
|
||||
},
|
||||
inject: ['foo'],
|
||||
render: (h: any, { data, props, injections, slots }: any) => {
|
||||
return h('div', { id: props.x, class: data.class }, [
|
||||
h('div', { class: 'inject' }, injections.foo),
|
||||
h('div', { class: 'slot' }, slots().default)
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
const vm = new Vue({
|
||||
provide() {
|
||||
return {
|
||||
foo: 123
|
||||
}
|
||||
},
|
||||
components: {
|
||||
func
|
||||
},
|
||||
template: `<func class="foo" x="foo">hello</func>`
|
||||
}).$mount()
|
||||
|
||||
expect(vm.$el.id).toBe('foo')
|
||||
expect(vm.$el.className).toBe('foo')
|
||||
expect(vm.$el.querySelector('.inject').textContent).toBe('123')
|
||||
expect(vm.$el.querySelector('.slot').textContent).toBe('hello')
|
||||
expect(vm.$el.outerHTML).toMatchInlineSnapshot(
|
||||
`"<div id=\\"foo\\" class=\\"foo\\"><div class=\\"inject\\">123</div><div class=\\"slot\\">hello</div></div>"`
|
||||
)
|
||||
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL]
|
||||
.message as Function)(func)
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
85
packages/vue-compat/__tests__/componentVModel.spec.ts
Normal file
85
packages/vue-compat/__tests__/componentVModel.spec.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import Vue from '@vue/compat'
|
||||
import { 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: `
|
||||
<div>
|
||||
<span>{{ text }}</span>
|
||||
<custom-input v-model="text"></custom-input>
|
||||
</div>
|
||||
`
|
||||
}).$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: `<input :value="value" @input="$emit('input', $event.target.value)">`
|
||||
})
|
||||
})
|
||||
|
||||
test('with model option', async () => {
|
||||
await runTest({
|
||||
name: 'CustomInput',
|
||||
props: ['input'],
|
||||
model: {
|
||||
prop: 'input',
|
||||
event: 'update'
|
||||
},
|
||||
template: `<input :value="input" @input="$emit('update', $event.target.value)">`
|
||||
})
|
||||
})
|
||||
})
|
||||
237
packages/vue-compat/__tests__/filters.spec.ts
Normal file
237
packages/vue-compat/__tests__/filters.spec.ts
Normal file
@@ -0,0 +1,237 @@
|
||||
import Vue from '@vue/compat'
|
||||
import { CompilerDeprecationTypes } from '../../compiler-core/src'
|
||||
import { toggleDeprecationWarning } from '../../runtime-core/src/compat/compatConfig'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({ MODE: 2 })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
Vue.configureCompat({ MODE: 3 })
|
||||
toggleDeprecationWarning(false)
|
||||
})
|
||||
|
||||
describe('FILTERS', () => {
|
||||
function upper(v: string) {
|
||||
return v.toUpperCase()
|
||||
}
|
||||
|
||||
function lower(v: string) {
|
||||
return v.toLowerCase()
|
||||
}
|
||||
|
||||
function reverse(v: string) {
|
||||
return v
|
||||
.split('')
|
||||
.reverse()
|
||||
.join('')
|
||||
}
|
||||
|
||||
function double(v: number) {
|
||||
return v * 2
|
||||
}
|
||||
|
||||
it('basic usage', () => {
|
||||
const vm = new Vue({
|
||||
template: '<div>{{ msg | upper }}</div>',
|
||||
data: () => ({
|
||||
msg: 'hi'
|
||||
}),
|
||||
filters: {
|
||||
upper
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('HI')
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('chained usage', () => {
|
||||
const vm = new Vue({
|
||||
template: '<div>{{ msg | upper | reverse }}</div>',
|
||||
data: () => ({
|
||||
msg: 'hi'
|
||||
}),
|
||||
filters: {
|
||||
upper,
|
||||
reverse
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('IH')
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('in v-bind', () => {
|
||||
const vm = new Vue({
|
||||
template: `
|
||||
<div
|
||||
v-bind:id="id | upper | reverse"
|
||||
:class="cls | reverse"
|
||||
:ref="ref | lower">
|
||||
</div>
|
||||
`,
|
||||
filters: {
|
||||
upper,
|
||||
reverse,
|
||||
lower
|
||||
},
|
||||
data: () => ({
|
||||
id: 'abc',
|
||||
cls: 'foo',
|
||||
ref: 'BAR'
|
||||
})
|
||||
}).$mount()
|
||||
expect(vm.$el.id).toBe('CBA')
|
||||
expect(vm.$el.className).toBe('oof')
|
||||
expect(vm.$refs.bar).toBe(vm.$el)
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('handle regex with pipe', () => {
|
||||
const vm = new Vue({
|
||||
template: `<test ref="test" :pattern="/a|b\\// | identity"></test>`,
|
||||
filters: { identity: (v: any) => v },
|
||||
components: {
|
||||
test: {
|
||||
props: ['pattern'],
|
||||
template: '<div></div>'
|
||||
}
|
||||
}
|
||||
}).$mount() as any
|
||||
expect(vm.$refs.test.pattern instanceof RegExp).toBe(true)
|
||||
expect(vm.$refs.test.pattern.toString()).toBe('/a|b\\//')
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('handle division', () => {
|
||||
const vm = new Vue({
|
||||
data: () => ({ a: 2 }),
|
||||
template: `<div>{{ 1/a / 4 | double }}</div>`,
|
||||
filters: { double }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe(String(1 / 4))
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('handle division with parenthesis', () => {
|
||||
const vm = new Vue({
|
||||
data: () => ({ a: 20 }),
|
||||
template: `<div>{{ (a*2) / 5 | double }}</div>`,
|
||||
filters: { double }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe(String(16))
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('handle division with dot', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div>{{ 20. / 5 | double }}</div>`,
|
||||
filters: { double }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe(String(8))
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('handle division with array values', () => {
|
||||
const vm = new Vue({
|
||||
data: () => ({ a: [20] }),
|
||||
template: `<div>{{ a[0] / 5 | double }}</div>`,
|
||||
filters: { double }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe(String(8))
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('handle division with hash values', () => {
|
||||
const vm = new Vue({
|
||||
data: () => ({ a: { n: 20 } }),
|
||||
template: `<div>{{ a['n'] / 5 | double }}</div>`,
|
||||
filters: { double }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe(String(8))
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('handle division with variable_', () => {
|
||||
const vm = new Vue({
|
||||
data: () => ({ a_: 8 }),
|
||||
template: `<div>{{ a_ / 2 | double }}</div>`,
|
||||
filters: { double }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe(String(8))
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('arguments', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div>{{ msg | add(a, 3) }}</div>`,
|
||||
data: () => ({
|
||||
msg: 1,
|
||||
a: 2
|
||||
}),
|
||||
filters: {
|
||||
add: (v: number, arg1: number, arg2: number) => v + arg1 + arg2
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('6')
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('quotes', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div>{{ msg + "b | c" + 'd' | upper }}</div>`,
|
||||
data: () => ({
|
||||
msg: 'a'
|
||||
}),
|
||||
filters: {
|
||||
upper
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('AB | CD')
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('double pipe', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div>{{ b || msg | upper }}</div>`,
|
||||
data: () => ({
|
||||
b: false,
|
||||
msg: 'a'
|
||||
}),
|
||||
filters: {
|
||||
upper
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('A')
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('object literal', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div>{{ { a: 123 } | pick('a') }}</div>`,
|
||||
filters: {
|
||||
pick: (v: any, key: string) => v[key]
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('123')
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('array literal', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div>{{ [1, 2, 3] | reverse }}</div>`,
|
||||
filters: {
|
||||
reverse: (arr: any[]) => arr.reverse().join(',')
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('3,2,1')
|
||||
expect(CompilerDeprecationTypes.COMPILER_FILTERS).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('bigint support', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div>{{ BigInt(BigInt(10000000)) + BigInt(2000000000n) * 3000000n }}</div>`
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('6000000010000000')
|
||||
})
|
||||
})
|
||||
336
packages/vue-compat/__tests__/global.spec.ts
Normal file
336
packages/vue-compat/__tests__/global.spec.ts
Normal file
@@ -0,0 +1,336 @@
|
||||
import Vue from '@vue/compat'
|
||||
import { effect, isReactive } from '@vue/reactivity'
|
||||
import {
|
||||
DeprecationTypes,
|
||||
deprecationData,
|
||||
toggleDeprecationWarning
|
||||
} from '../../runtime-core/src/compat/compatConfig'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({ MODE: 2 })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
Vue.configureCompat({ MODE: 3 })
|
||||
toggleDeprecationWarning(false)
|
||||
})
|
||||
|
||||
describe('GLOBAL_MOUNT', () => {
|
||||
test('new Vue() with el', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
|
||||
const el = document.createElement('div')
|
||||
el.innerHTML = `{{ msg }}`
|
||||
new Vue({
|
||||
el,
|
||||
compatConfig: { GLOBAL_MOUNT: true },
|
||||
data() {
|
||||
return {
|
||||
msg: 'hello'
|
||||
}
|
||||
}
|
||||
})
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_MOUNT].message
|
||||
).toHaveBeenWarned()
|
||||
expect(el.innerHTML).toBe('hello')
|
||||
})
|
||||
|
||||
test('new Vue() + $mount', () => {
|
||||
const el = document.createElement('div')
|
||||
el.innerHTML = `{{ msg }}`
|
||||
new Vue({
|
||||
data() {
|
||||
return {
|
||||
msg: 'hello'
|
||||
}
|
||||
}
|
||||
}).$mount(el)
|
||||
expect(el.innerHTML).toBe('hello')
|
||||
})
|
||||
})
|
||||
|
||||
describe('GLOBAL_MOUNT_CONTAINER', () => {
|
||||
test('should warn', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
|
||||
const el = document.createElement('div')
|
||||
el.innerHTML = `test`
|
||||
el.setAttribute('v-bind:id', 'foo')
|
||||
new Vue().$mount(el)
|
||||
// warning only
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_MOUNT].message
|
||||
).toHaveBeenWarned()
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_MOUNT_CONTAINER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
|
||||
describe('GLOBAL_EXTEND', () => {
|
||||
// https://github.com/vuejs/vue/blob/dev/test/unit/features/global-api/extend.spec.js
|
||||
it('should correctly merge options', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
|
||||
const Test = Vue.extend({
|
||||
name: 'test',
|
||||
a: 1,
|
||||
b: 2
|
||||
})
|
||||
expect(Test.options.a).toBe(1)
|
||||
expect(Test.options.b).toBe(2)
|
||||
expect(Test.super).toBe(Vue)
|
||||
const t = new Test({
|
||||
a: 2
|
||||
})
|
||||
expect(t.$options.a).toBe(2)
|
||||
expect(t.$options.b).toBe(2)
|
||||
// inheritance
|
||||
const Test2 = Test.extend({
|
||||
a: 2
|
||||
})
|
||||
expect(Test2.options.a).toBe(2)
|
||||
expect(Test2.options.b).toBe(2)
|
||||
const t2 = new Test2({
|
||||
a: 3
|
||||
})
|
||||
expect(t2.$options.a).toBe(3)
|
||||
expect(t2.$options.b).toBe(2)
|
||||
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_MOUNT].message
|
||||
).toHaveBeenWarned()
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_EXTEND].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('should work when used as components', () => {
|
||||
const foo = Vue.extend({
|
||||
template: '<span>foo</span>'
|
||||
})
|
||||
const bar = Vue.extend({
|
||||
template: '<span>bar</span>'
|
||||
})
|
||||
const vm = new Vue({
|
||||
template: '<div><foo></foo><bar></bar></div>',
|
||||
components: { foo, bar }
|
||||
}).$mount()
|
||||
expect(vm.$el.innerHTML).toBe('<span>foo</span><span>bar</span>')
|
||||
})
|
||||
|
||||
it('should merge lifecycle hooks', () => {
|
||||
const calls: number[] = []
|
||||
const A = Vue.extend({
|
||||
created() {
|
||||
calls.push(1)
|
||||
}
|
||||
})
|
||||
const B = A.extend({
|
||||
created() {
|
||||
calls.push(2)
|
||||
}
|
||||
})
|
||||
new B({
|
||||
created() {
|
||||
calls.push(3)
|
||||
}
|
||||
})
|
||||
expect(calls).toEqual([1, 2, 3])
|
||||
})
|
||||
|
||||
it('should not merge nested mixins created with Vue.extend', () => {
|
||||
const A = Vue.extend({
|
||||
created: () => {}
|
||||
})
|
||||
const B = Vue.extend({
|
||||
mixins: [A],
|
||||
created: () => {}
|
||||
})
|
||||
const C = Vue.extend({
|
||||
extends: B,
|
||||
created: () => {}
|
||||
})
|
||||
const D = Vue.extend({
|
||||
mixins: [C],
|
||||
created: () => {}
|
||||
})
|
||||
expect(D.options.created!.length).toBe(4)
|
||||
})
|
||||
|
||||
it('should merge methods', () => {
|
||||
const A = Vue.extend({
|
||||
methods: {
|
||||
a() {
|
||||
return this.n
|
||||
}
|
||||
}
|
||||
})
|
||||
const B = A.extend({
|
||||
methods: {
|
||||
b() {
|
||||
return this.n + 1
|
||||
}
|
||||
}
|
||||
})
|
||||
const b = new B({
|
||||
data: () => ({ n: 0 }),
|
||||
methods: {
|
||||
c() {
|
||||
return this.n + 2
|
||||
}
|
||||
}
|
||||
}) as any
|
||||
expect(b.a()).toBe(0)
|
||||
expect(b.b()).toBe(1)
|
||||
expect(b.c()).toBe(2)
|
||||
})
|
||||
|
||||
it('should merge assets', () => {
|
||||
const A = Vue.extend({
|
||||
components: {
|
||||
aa: {
|
||||
template: '<div>A</div>'
|
||||
}
|
||||
}
|
||||
})
|
||||
const B = A.extend({
|
||||
components: {
|
||||
bb: {
|
||||
template: '<div>B</div>'
|
||||
}
|
||||
}
|
||||
})
|
||||
const b = new B({
|
||||
template: '<div><aa></aa><bb></bb></div>'
|
||||
}).$mount()
|
||||
expect(b.$el.innerHTML).toBe('<div>A</div><div>B</div>')
|
||||
})
|
||||
|
||||
it('caching', () => {
|
||||
const options = {
|
||||
template: '<div></div>'
|
||||
}
|
||||
const A = Vue.extend(options)
|
||||
const B = Vue.extend(options)
|
||||
expect(A).toBe(B)
|
||||
})
|
||||
|
||||
it('extended options should use different identify from parent', () => {
|
||||
const A = Vue.extend({ computed: {} })
|
||||
const B = A.extend()
|
||||
B.options.computed.b = () => 'foo'
|
||||
expect(B.options.computed).not.toBe(A.options.computed)
|
||||
expect(A.options.computed.b).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('GLOBAL_PROTOTYPE', () => {
|
||||
test('plain properties', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
Vue.prototype.$test = 1
|
||||
const vm = new Vue() as any
|
||||
expect(vm.$test).toBe(1)
|
||||
delete Vue.prototype.$test
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_MOUNT].message
|
||||
).toHaveBeenWarned()
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_PROTOTYPE].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('method this context', () => {
|
||||
Vue.prototype.$test = function() {
|
||||
return this.msg
|
||||
}
|
||||
const vm = new Vue({
|
||||
data() {
|
||||
return { msg: 'method' }
|
||||
}
|
||||
}) as any
|
||||
expect(vm.$test()).toBe('method')
|
||||
delete Vue.prototype.$test
|
||||
})
|
||||
|
||||
test('defined properties', () => {
|
||||
Object.defineProperty(Vue.prototype, '$test', {
|
||||
configurable: true,
|
||||
get() {
|
||||
return this.msg
|
||||
}
|
||||
})
|
||||
const vm = new Vue({
|
||||
data() {
|
||||
return { msg: 'getter' }
|
||||
}
|
||||
}) as any
|
||||
expect(vm.$test).toBe('getter')
|
||||
delete Vue.prototype.$test
|
||||
})
|
||||
|
||||
test('extended prototype', async () => {
|
||||
const Foo = Vue.extend()
|
||||
Foo.prototype.$test = 1
|
||||
const vm = new Foo() as any
|
||||
expect(vm.$test).toBe(1)
|
||||
const plain = new Vue() as any
|
||||
expect(plain.$test).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('GLOBAL_SET/DELETE', () => {
|
||||
test('set', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
const obj: any = {}
|
||||
Vue.set(obj, 'foo', 1)
|
||||
expect(obj.foo).toBe(1)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_SET].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('delete', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
const obj: any = { foo: 1 }
|
||||
Vue.delete(obj, 'foo')
|
||||
expect('foo' in obj).toBe(false)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_DELETE].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
|
||||
describe('GLOBAL_OBSERVABLE', () => {
|
||||
test('should work', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
const obj = Vue.observable({})
|
||||
expect(isReactive(obj)).toBe(true)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_OBSERVABLE].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
|
||||
describe('GLOBAL_PRIVATE_UTIL', () => {
|
||||
test('defineReactive', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
const obj: any = {}
|
||||
// @ts-ignore
|
||||
Vue.util.defineReactive(obj, 'test', 1)
|
||||
|
||||
let n
|
||||
effect(() => {
|
||||
n = obj.test
|
||||
})
|
||||
expect(n).toBe(1)
|
||||
obj.test++
|
||||
expect(n).toBe(2)
|
||||
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.GLOBAL_PRIVATE_UTIL].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
66
packages/vue-compat/__tests__/globalConfig.spec.ts
Normal file
66
packages/vue-compat/__tests__/globalConfig.spec.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import Vue from '@vue/compat'
|
||||
import { toggleDeprecationWarning } from '../../runtime-core/src/compat/compatConfig'
|
||||
import { triggerEvent } from './utils'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({ MODE: 2 })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
Vue.configureCompat({ MODE: 3 })
|
||||
toggleDeprecationWarning(false)
|
||||
})
|
||||
|
||||
// only testing config options that affect runtime behavior.
|
||||
|
||||
test('GLOBAL_KEY_CODES', () => {
|
||||
Vue.config.keyCodes = {
|
||||
foo: 86,
|
||||
bar: [38, 87]
|
||||
}
|
||||
|
||||
const onFoo = jest.fn()
|
||||
const onBar = jest.fn()
|
||||
|
||||
const el = document.createElement('div')
|
||||
new Vue({
|
||||
el,
|
||||
template: `<input type="text" @keyup.foo="onFoo" @keyup.bar="onBar">`,
|
||||
methods: {
|
||||
onFoo,
|
||||
onBar
|
||||
}
|
||||
})
|
||||
|
||||
triggerEvent(el.children[0], 'keyup', e => {
|
||||
e.key = '_'
|
||||
e.keyCode = 86
|
||||
})
|
||||
expect(onFoo).toHaveBeenCalledTimes(1)
|
||||
expect(onBar).toHaveBeenCalledTimes(0)
|
||||
|
||||
triggerEvent(el.children[0], 'keyup', e => {
|
||||
e.key = '_'
|
||||
e.keyCode = 38
|
||||
})
|
||||
expect(onFoo).toHaveBeenCalledTimes(1)
|
||||
expect(onBar).toHaveBeenCalledTimes(1)
|
||||
|
||||
triggerEvent(el.children[0], 'keyup', e => {
|
||||
e.key = '_'
|
||||
e.keyCode = 87
|
||||
})
|
||||
expect(onFoo).toHaveBeenCalledTimes(1)
|
||||
expect(onBar).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
test('GLOBAL_IGNORED_ELEMENTS', () => {
|
||||
Vue.config.ignoredElements = [/^v-/, 'foo']
|
||||
const el = document.createElement('div')
|
||||
new Vue({
|
||||
el,
|
||||
template: `<v-foo/><foo/>`
|
||||
})
|
||||
expect(el.innerHTML).toBe(`<v-foo></v-foo><foo></foo>`)
|
||||
})
|
||||
299
packages/vue-compat/__tests__/instance.spec.ts
Normal file
299
packages/vue-compat/__tests__/instance.spec.ts
Normal file
@@ -0,0 +1,299 @@
|
||||
import Vue from '@vue/compat'
|
||||
import { Slots } from '../../runtime-core/src/componentSlots'
|
||||
import { Text } from '../../runtime-core/src/vnode'
|
||||
import {
|
||||
DeprecationTypes,
|
||||
deprecationData,
|
||||
toggleDeprecationWarning
|
||||
} from '../../runtime-core/src/compat/compatConfig'
|
||||
import { LegacyPublicInstance } from '../../runtime-core/src/compat/instance'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(true)
|
||||
Vue.configureCompat({
|
||||
MODE: 2,
|
||||
GLOBAL_MOUNT: 'suppress-warning'
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({ MODE: 3 })
|
||||
})
|
||||
|
||||
test('INSTANCE_SET', () => {
|
||||
const obj: any = {}
|
||||
new Vue().$set(obj, 'foo', 1)
|
||||
expect(obj.foo).toBe(1)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_SET].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('INSTANCE_DELETE', () => {
|
||||
const obj: any = { foo: 1 }
|
||||
new Vue().$delete(obj, 'foo')
|
||||
expect('foo' in obj).toBe(false)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_DELETE].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('INSTANCE_DESTROY', () => {
|
||||
new Vue({ template: 'foo' }).$mount().$destroy()
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_DESTROY].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
// https://github.com/vuejs/vue/blob/dev/test/unit/features/instance/methods-events.spec.js
|
||||
describe('INSTANCE_EVENT_EMITTER', () => {
|
||||
let vm: LegacyPublicInstance
|
||||
let spy: jest.Mock
|
||||
|
||||
beforeEach(() => {
|
||||
vm = new Vue()
|
||||
spy = jest.fn()
|
||||
})
|
||||
|
||||
it('$on', () => {
|
||||
vm.$on('test', function(this: any) {
|
||||
// expect correct context
|
||||
expect(this).toBe(vm)
|
||||
spy.apply(this, arguments)
|
||||
})
|
||||
vm.$emit('test', 1, 2, 3, 4)
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(spy).toHaveBeenCalledWith(1, 2, 3, 4)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('$on multi event', () => {
|
||||
vm.$on(['test1', 'test2'], function(this: any) {
|
||||
expect(this).toBe(vm)
|
||||
spy.apply(this, arguments)
|
||||
})
|
||||
vm.$emit('test1', 1, 2, 3, 4)
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(spy).toHaveBeenCalledWith(1, 2, 3, 4)
|
||||
vm.$emit('test2', 5, 6, 7, 8)
|
||||
expect(spy).toHaveBeenCalledTimes(2)
|
||||
expect(spy).toHaveBeenCalledWith(5, 6, 7, 8)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('$off multi event', () => {
|
||||
vm.$on(['test1', 'test2', 'test3'], spy)
|
||||
vm.$off(['test1', 'test2'], spy)
|
||||
vm.$emit('test1')
|
||||
vm.$emit('test2')
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
vm.$emit('test3', 1, 2, 3, 4)
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('$off multi event without callback', () => {
|
||||
vm.$on(['test1', 'test2'], spy)
|
||||
vm.$off(['test1', 'test2'])
|
||||
vm.$emit('test1')
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('$once', () => {
|
||||
vm.$once('test', spy)
|
||||
vm.$emit('test', 1, 2, 3)
|
||||
vm.$emit('test', 2, 3, 4)
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(spy).toHaveBeenCalledWith(1, 2, 3)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('$off event added by $once', () => {
|
||||
vm.$once('test', spy)
|
||||
vm.$off('test', spy) // test off event and this event added by once
|
||||
vm.$emit('test', 1, 2, 3)
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('$off', () => {
|
||||
vm.$on('test1', spy)
|
||||
vm.$on('test2', spy)
|
||||
vm.$off()
|
||||
vm.$emit('test1')
|
||||
vm.$emit('test2')
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('$off event', () => {
|
||||
vm.$on('test1', spy)
|
||||
vm.$on('test2', spy)
|
||||
vm.$off('test1')
|
||||
vm.$off('test1') // test off something that's already off
|
||||
vm.$emit('test1', 1)
|
||||
vm.$emit('test2', 2)
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
expect(spy).toHaveBeenCalledWith(2)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('$off event + fn', () => {
|
||||
const spy2 = jasmine.createSpy('emitter')
|
||||
vm.$on('test', spy)
|
||||
vm.$on('test', spy2)
|
||||
vm.$off('test', spy)
|
||||
vm.$emit('test', 1, 2, 3)
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
expect(spy2).toHaveBeenCalledTimes(1)
|
||||
expect(spy2).toHaveBeenCalledWith(1, 2, 3)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_EVENT_EMITTER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
|
||||
describe('INSTANCE_EVENT_HOOKS', () => {
|
||||
test('instance API', () => {
|
||||
const spy = jest.fn()
|
||||
const vm = new Vue({ template: 'foo' })
|
||||
vm.$on('hook:mounted', spy)
|
||||
vm.$mount()
|
||||
expect(spy).toHaveBeenCalled()
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.INSTANCE_EVENT_HOOKS]
|
||||
.message as Function)('hook:mounted')
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('via template', () => {
|
||||
const spy = jest.fn()
|
||||
new Vue({
|
||||
template: `<child @hook:mounted="spy"/>`,
|
||||
methods: { spy },
|
||||
components: {
|
||||
child: {
|
||||
template: 'foo'
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
expect(spy).toHaveBeenCalled()
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.INSTANCE_EVENT_HOOKS]
|
||||
.message as Function)('hook:mounted')
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
|
||||
test('INSTANCE_EVENT_CHILDREN', () => {
|
||||
const vm = new Vue({
|
||||
template: `<child/><div><child v-for="i in 3"/></div>`,
|
||||
components: {
|
||||
child: {
|
||||
template: 'foo',
|
||||
data() {
|
||||
return { n: 1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$children.length).toBe(4)
|
||||
vm.$children.forEach((c: any) => {
|
||||
expect(c.n).toBe(1)
|
||||
})
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_CHILDREN].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('INSTANCE_LISTENERS', () => {
|
||||
const foo = () => 'foo'
|
||||
const bar = () => 'bar'
|
||||
let listeners: Record<string, Function>
|
||||
|
||||
new Vue({
|
||||
template: `<child @click="foo" @custom="bar" />`,
|
||||
methods: { foo, bar },
|
||||
components: {
|
||||
child: {
|
||||
template: `<div/>`,
|
||||
mounted() {
|
||||
listeners = this.$listeners
|
||||
}
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
expect(Object.keys(listeners!)).toMatchObject(['click', 'custom'])
|
||||
expect(listeners!.click()).toBe('foo')
|
||||
expect(listeners!.custom()).toBe('bar')
|
||||
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_LISTENERS].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('INSTANCE_SCOPED_SLOTS', () => {
|
||||
let slots: Slots
|
||||
new Vue({
|
||||
template: `<child v-slot="{ msg }">{{ msg }}</child>`,
|
||||
components: {
|
||||
child: {
|
||||
compatConfig: { RENDER_FUNCTION: false },
|
||||
render() {
|
||||
slots = this.$scopedSlots
|
||||
}
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
expect(slots!.default!({ msg: 'hi' })).toMatchObject([
|
||||
{
|
||||
type: Text,
|
||||
children: 'hi'
|
||||
}
|
||||
])
|
||||
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.INSTANCE_SCOPED_SLOTS].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('INSTANCE_ATTR_CLASS_STYLE', () => {
|
||||
const vm = new Vue({
|
||||
template: `<child class="foo" style="color:red" id="ok" />`,
|
||||
components: {
|
||||
child: {
|
||||
inheritAttrs: false,
|
||||
template: `<div><div v-bind="$attrs" /></div>`
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
expect(vm.$el.outerHTML).toBe(
|
||||
`<div class="foo" style="color: red;"><div id="ok"></div></div>`
|
||||
)
|
||||
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE]
|
||||
.message as Function)('Anonymous')
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
238
packages/vue-compat/__tests__/misc.spec.ts
Normal file
238
packages/vue-compat/__tests__/misc.spec.ts
Normal file
@@ -0,0 +1,238 @@
|
||||
import Vue from '@vue/compat'
|
||||
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 })
|
||||
})
|
||||
|
||||
test('WATCH_ARRAY', async () => {
|
||||
const spy = jest.fn()
|
||||
const vm = new Vue({
|
||||
data() {
|
||||
return {
|
||||
foo: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo: spy
|
||||
}
|
||||
}) as any
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.WATCH_ARRAY].message
|
||||
).toHaveBeenWarned()
|
||||
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
vm.foo.push(1)
|
||||
await nextTick()
|
||||
expect(spy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
test('PROPS_DEFAULT_THIS', () => {
|
||||
let thisCtx: any
|
||||
const Child = {
|
||||
customOption: 1,
|
||||
inject: ['provided'],
|
||||
props: {
|
||||
foo: null,
|
||||
bar: {
|
||||
default(this: any) {
|
||||
// copy values since injection must be sync
|
||||
thisCtx = {
|
||||
foo: this.foo,
|
||||
$options: this.$options,
|
||||
provided: this.provided
|
||||
}
|
||||
return this.foo + 1
|
||||
}
|
||||
}
|
||||
},
|
||||
template: `{{ bar }}`
|
||||
}
|
||||
|
||||
const vm = new Vue({
|
||||
components: { Child },
|
||||
provide: {
|
||||
provided: 2
|
||||
},
|
||||
template: `<child :foo="0" />`
|
||||
}).$mount()
|
||||
|
||||
expect(vm.$el.textContent).toBe('1')
|
||||
// other props
|
||||
expect(thisCtx.foo).toBe(0)
|
||||
// $options
|
||||
expect(thisCtx.$options.customOption).toBe(1)
|
||||
// injections
|
||||
expect(thisCtx.provided).toBe(2)
|
||||
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.PROPS_DEFAULT_THIS].message as Function)(
|
||||
'bar'
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('V_FOR_REF', async () => {
|
||||
const vm = new Vue({
|
||||
data() {
|
||||
return {
|
||||
ok: true,
|
||||
list: [1, 2, 3]
|
||||
}
|
||||
},
|
||||
template: `
|
||||
<template v-if="ok">
|
||||
<li v-for="i in list" ref="list">{{ i }}</li>
|
||||
</template>
|
||||
`
|
||||
}).$mount() as any
|
||||
|
||||
const mapRefs = () => vm.$refs.list.map((el: HTMLElement) => el.textContent)
|
||||
expect(mapRefs()).toMatchObject(['1', '2', '3'])
|
||||
|
||||
expect(deprecationData[DeprecationTypes.V_FOR_REF].message).toHaveBeenWarned()
|
||||
|
||||
vm.list.push(4)
|
||||
await nextTick()
|
||||
expect(mapRefs()).toMatchObject(['1', '2', '3', '4'])
|
||||
|
||||
vm.list.shift()
|
||||
await nextTick()
|
||||
expect(mapRefs()).toMatchObject(['2', '3', '4'])
|
||||
|
||||
vm.ok = !vm.ok
|
||||
await nextTick()
|
||||
expect(mapRefs()).toMatchObject([])
|
||||
|
||||
vm.ok = !vm.ok
|
||||
await nextTick()
|
||||
expect(mapRefs()).toMatchObject(['2', '3', '4'])
|
||||
})
|
||||
|
||||
test('V_ON_KEYCODE_MODIFIER', () => {
|
||||
const spy = jest.fn()
|
||||
const vm = new Vue({
|
||||
template: `<input @keyup.1="spy">`,
|
||||
methods: { spy }
|
||||
}).$mount()
|
||||
triggerEvent(vm.$el, 'keyup', e => {
|
||||
e.key = '_'
|
||||
e.keyCode = 1
|
||||
})
|
||||
expect(spy).toHaveBeenCalled()
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.V_ON_KEYCODE_MODIFIER].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('CUSTOM_DIR', async () => {
|
||||
const myDir = {
|
||||
bind: jest.fn(),
|
||||
inserted: jest.fn(),
|
||||
update: jest.fn(),
|
||||
componentUpdated: jest.fn(),
|
||||
unbind: jest.fn()
|
||||
} as any
|
||||
|
||||
const getCalls = () =>
|
||||
Object.keys(myDir).map(key => myDir[key].mock.calls.length)
|
||||
|
||||
const vm = new Vue({
|
||||
data() {
|
||||
return {
|
||||
ok: true,
|
||||
foo: 1
|
||||
}
|
||||
},
|
||||
template: `<div v-if="ok" v-my-dir="foo"/>`,
|
||||
directives: {
|
||||
myDir
|
||||
}
|
||||
}).$mount() as any
|
||||
|
||||
expect(getCalls()).toMatchObject([1, 1, 0, 0, 0])
|
||||
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.CUSTOM_DIR].message as Function)(
|
||||
'bind',
|
||||
'beforeMount'
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.CUSTOM_DIR].message as Function)(
|
||||
'inserted',
|
||||
'mounted'
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
|
||||
vm.foo++
|
||||
await nextTick()
|
||||
expect(getCalls()).toMatchObject([1, 1, 1, 1, 0])
|
||||
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.CUSTOM_DIR].message as Function)(
|
||||
'update',
|
||||
'updated'
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.CUSTOM_DIR].message as Function)(
|
||||
'componentUpdated',
|
||||
'updated'
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('ATTR_FALSE_VALUE', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div :id="false" :foo="false"/>`
|
||||
}).$mount()
|
||||
expect(vm.$el.hasAttribute('id')).toBe(false)
|
||||
expect(vm.$el.hasAttribute('foo')).toBe(false)
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
|
||||
'id'
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
|
||||
'foo'
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('ATTR_ENUMERATED_COERSION', () => {
|
||||
const vm = new Vue({
|
||||
template: `<div :draggable="null" :spellcheck="0" contenteditable="foo" />`
|
||||
}).$mount()
|
||||
expect(vm.$el.getAttribute('draggable')).toBe('false')
|
||||
expect(vm.$el.getAttribute('spellcheck')).toBe('true')
|
||||
expect(vm.$el.getAttribute('contenteditable')).toBe('true')
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.ATTR_ENUMERATED_COERSION]
|
||||
.message as Function)('draggable', null, 'false')
|
||||
).toHaveBeenWarned()
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.ATTR_ENUMERATED_COERSION]
|
||||
.message as Function)('spellcheck', 0, 'true')
|
||||
).toHaveBeenWarned()
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.ATTR_ENUMERATED_COERSION]
|
||||
.message as Function)('contenteditable', 'foo', 'true')
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
92
packages/vue-compat/__tests__/options.spec.ts
Normal file
92
packages/vue-compat/__tests__/options.spec.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import Vue from '@vue/compat'
|
||||
import { nextTick } from '../../runtime-core/src/scheduler'
|
||||
import {
|
||||
DeprecationTypes,
|
||||
deprecationData,
|
||||
toggleDeprecationWarning
|
||||
} from '../../runtime-core/src/compat/compatConfig'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(true)
|
||||
Vue.configureCompat({
|
||||
MODE: 2,
|
||||
GLOBAL_MOUNT: 'suppress-warning'
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({ MODE: 3 })
|
||||
})
|
||||
|
||||
test('root data plain object', () => {
|
||||
const vm = new Vue({
|
||||
data: { foo: 1 } as any,
|
||||
template: `{{ foo }}`
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('1')
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.OPTIONS_DATA_FN].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('data deep merge', () => {
|
||||
const mixin = {
|
||||
data() {
|
||||
return {
|
||||
foo: {
|
||||
baz: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const vm = new Vue({
|
||||
mixins: [mixin],
|
||||
data: () => ({
|
||||
foo: {
|
||||
bar: 1
|
||||
}
|
||||
}),
|
||||
template: `{{ foo }}`
|
||||
}).$mount()
|
||||
|
||||
expect(vm.$el.textContent).toBe(JSON.stringify({ baz: 2, bar: 1 }, null, 2))
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.OPTIONS_DATA_MERGE].message as Function)(
|
||||
'foo'
|
||||
)
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
test('beforeDestroy/destroyed', async () => {
|
||||
const beforeDestroy = jest.fn()
|
||||
const destroyed = jest.fn()
|
||||
|
||||
const child = {
|
||||
template: `foo`,
|
||||
beforeDestroy,
|
||||
destroyed
|
||||
}
|
||||
|
||||
const vm = new Vue({
|
||||
template: `<child v-if="ok"/>`,
|
||||
data() {
|
||||
return { ok: true }
|
||||
},
|
||||
components: { child }
|
||||
}).$mount() as any
|
||||
|
||||
vm.ok = false
|
||||
await nextTick()
|
||||
expect(beforeDestroy).toHaveBeenCalled()
|
||||
expect(destroyed).toHaveBeenCalled()
|
||||
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.OPTIONS_BEFORE_DESTROY].message
|
||||
).toHaveBeenWarned()
|
||||
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.OPTIONS_DESTROYED].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
219
packages/vue-compat/__tests__/renderFn.spec.ts
Normal file
219
packages/vue-compat/__tests__/renderFn.spec.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
import { ShapeFlags } from '@vue/shared'
|
||||
import Vue from '@vue/compat'
|
||||
import { createComponentInstance } from '../../runtime-core/src/component'
|
||||
import { setCurrentRenderingInstance } from '../../runtime-core/src/componentRenderContext'
|
||||
import { DirectiveBinding } from '../../runtime-core/src/directives'
|
||||
import { createVNode } from '../../runtime-core/src/vnode'
|
||||
import {
|
||||
deprecationData,
|
||||
DeprecationTypes,
|
||||
toggleDeprecationWarning
|
||||
} from '../../runtime-core/src/compat/compatConfig'
|
||||
import { compatH as h } from '../../runtime-core/src/compat/renderFn'
|
||||
|
||||
beforeEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({
|
||||
MODE: 2,
|
||||
GLOBAL_MOUNT: 'suppress-warning'
|
||||
})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
toggleDeprecationWarning(false)
|
||||
Vue.configureCompat({ MODE: 3 })
|
||||
})
|
||||
|
||||
describe('compat: render function', () => {
|
||||
const mockDir = {}
|
||||
const mockChildComp = {}
|
||||
const mockComponent = {
|
||||
directives: {
|
||||
mockDir
|
||||
},
|
||||
components: {
|
||||
foo: mockChildComp
|
||||
}
|
||||
}
|
||||
const mockInstance = createComponentInstance(
|
||||
createVNode(mockComponent),
|
||||
null,
|
||||
null
|
||||
)
|
||||
beforeEach(() => {
|
||||
setCurrentRenderingInstance(mockInstance)
|
||||
})
|
||||
afterEach(() => {
|
||||
setCurrentRenderingInstance(null)
|
||||
})
|
||||
|
||||
test('string component lookup', () => {
|
||||
expect(h('foo')).toMatchObject({
|
||||
type: mockChildComp
|
||||
})
|
||||
})
|
||||
|
||||
test('class / style / attrs / domProps / props', () => {
|
||||
expect(
|
||||
h('div', {
|
||||
class: 'foo',
|
||||
style: { color: 'red' },
|
||||
attrs: {
|
||||
id: 'foo'
|
||||
},
|
||||
domProps: {
|
||||
innerHTML: 'hi'
|
||||
},
|
||||
props: {
|
||||
myProp: 'foo'
|
||||
}
|
||||
})
|
||||
).toMatchObject({
|
||||
props: {
|
||||
class: 'foo',
|
||||
style: { color: 'red' },
|
||||
id: 'foo',
|
||||
innerHTML: 'hi',
|
||||
myProp: 'foo'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('staticClass + class', () => {
|
||||
expect(
|
||||
h('div', {
|
||||
class: { foo: true },
|
||||
staticClass: 'bar'
|
||||
})
|
||||
).toMatchObject({
|
||||
props: {
|
||||
class: 'bar foo'
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('staticStyle + style', () => {
|
||||
expect(
|
||||
h('div', {
|
||||
style: { color: 'red' },
|
||||
staticStyle: { fontSize: '14px' }
|
||||
})
|
||||
).toMatchObject({
|
||||
props: {
|
||||
style: {
|
||||
color: 'red',
|
||||
fontSize: '14px'
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('on / nativeOn', () => {
|
||||
const fn = () => {}
|
||||
expect(
|
||||
h('div', {
|
||||
on: {
|
||||
click: fn,
|
||||
fooBar: fn
|
||||
},
|
||||
nativeOn: {
|
||||
click: fn,
|
||||
'bar-baz': fn
|
||||
}
|
||||
})
|
||||
).toMatchObject({
|
||||
props: {
|
||||
onClick: fn, // should dedupe
|
||||
onFooBar: fn,
|
||||
'onBar-baz': fn
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('directives', () => {
|
||||
expect(
|
||||
h('div', {
|
||||
directives: [
|
||||
{
|
||||
name: 'mock-dir',
|
||||
value: '2',
|
||||
// expression: '1 + 1',
|
||||
arg: 'foo',
|
||||
modifiers: {
|
||||
bar: true
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
).toMatchObject({
|
||||
dirs: [
|
||||
{
|
||||
dir: mockDir,
|
||||
instance: mockInstance.proxy,
|
||||
value: '2',
|
||||
oldValue: void 0,
|
||||
arg: 'foo',
|
||||
modifiers: {
|
||||
bar: true
|
||||
}
|
||||
}
|
||||
] as DirectiveBinding[]
|
||||
})
|
||||
})
|
||||
|
||||
test('scopedSlots', () => {
|
||||
const scopedSlots = {
|
||||
default() {}
|
||||
}
|
||||
const vnode = h(mockComponent, {
|
||||
scopedSlots
|
||||
})
|
||||
expect(vnode).toMatchObject({
|
||||
children: scopedSlots
|
||||
})
|
||||
expect('scopedSlots' in vnode.props!).toBe(false)
|
||||
expect(vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN).toBeTruthy()
|
||||
})
|
||||
|
||||
test('legacy named slot', () => {
|
||||
const vnode = h(mockComponent, [
|
||||
'text',
|
||||
h('div', { slot: 'foo' }, 'one'),
|
||||
h('div', { slot: 'bar' }, 'two'),
|
||||
h('div', { slot: 'foo' }, 'three'),
|
||||
h('div', 'four')
|
||||
])
|
||||
expect(vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN).toBeTruthy()
|
||||
const slots = vnode.children as any
|
||||
|
||||
// default
|
||||
expect(slots.default()).toMatchObject(['text', { children: 'four' }])
|
||||
expect(slots.foo()).toMatchObject([
|
||||
{ children: 'one' },
|
||||
{ children: 'three' }
|
||||
])
|
||||
expect(slots.bar()).toMatchObject([{ children: 'two' }])
|
||||
})
|
||||
|
||||
test('in component usage', () => {
|
||||
toggleDeprecationWarning(true)
|
||||
|
||||
const vm = new Vue({
|
||||
render(h: any) {
|
||||
return h(
|
||||
'div',
|
||||
{
|
||||
class: 'foo',
|
||||
attrs: { id: 'bar' }
|
||||
},
|
||||
'hello'
|
||||
)
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
expect(vm.$el.outerHTML).toBe(`<div class="foo" id="bar">hello</div>`)
|
||||
expect(
|
||||
deprecationData[DeprecationTypes.RENDER_FUNCTION].message
|
||||
).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
11
packages/vue-compat/__tests__/utils.ts
Normal file
11
packages/vue-compat/__tests__/utils.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export function triggerEvent(
|
||||
target: Element,
|
||||
event: string,
|
||||
process?: (e: any) => any
|
||||
) {
|
||||
const e = document.createEvent('HTMLEvents')
|
||||
e.initEvent(event, true, true)
|
||||
if (process) process(e)
|
||||
target.dispatchEvent(e)
|
||||
return e
|
||||
}
|
||||
Reference in New Issue
Block a user