diff --git a/packages/runtime-core/src/compat/renderFn.ts b/packages/runtime-core/src/compat/renderFn.ts
index ffbd34e7..ba67cd36 100644
--- a/packages/runtime-core/src/compat/renderFn.ts
+++ b/packages/runtime-core/src/compat/renderFn.ts
@@ -113,7 +113,7 @@ export function compatH(
): VNode
export function compatH(
type: string | Component,
- props?: LegacyVNodeProps,
+ props?: Data & LegacyVNodeProps,
children?: LegacyVNodeChildren
): VNode
@@ -190,16 +190,12 @@ function convertLegacyProps(
} else if (key === 'on' || key === 'nativeOn') {
const listeners = legacyProps[key]
for (const event in listeners) {
- const handlerKey = convertLegacyEventKey(event)
+ let handlerKey = convertLegacyEventKey(event)
+ if (key === 'nativeOn') handlerKey += `Native`
const existing = converted[handlerKey]
const incoming = listeners[event]
if (existing !== incoming) {
if (existing) {
- // for the rare case where the same handler is attached
- // twice with/without .native modifier...
- if (key === 'nativeOn' && String(existing) === String(incoming)) {
- continue
- }
converted[handlerKey] = [].concat(existing as any, incoming as any)
} else {
converted[handlerKey] = incoming
@@ -307,6 +303,7 @@ function convertLegacySlots(vnode: VNode): VNode {
}
export function defineLegacyVNodeProperties(vnode: VNode) {
+ /* istanbul ignore if */
if (
isCompatEnabled(
DeprecationTypes.RENDER_FUNCTION,
diff --git a/packages/vue-compat/__tests__/componentAsync.spec.ts b/packages/vue-compat/__tests__/componentAsync.spec.ts
index c7d2a789..9e7316a6 100644
--- a/packages/vue-compat/__tests__/componentAsync.spec.ts
+++ b/packages/vue-compat/__tests__/componentAsync.spec.ts
@@ -59,4 +59,24 @@ describe('COMPONENT_ASYNC', () => {
)
).toHaveBeenWarned()
})
+
+ test('object syntax', async () => {
+ const comp = () => ({
+ component: Promise.resolve({ template: 'foo' })
+ })
+
+ const vm = new Vue({
+ template: `
`,
+ 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()
+ })
})
diff --git a/packages/vue-compat/__tests__/global.spec.ts b/packages/vue-compat/__tests__/global.spec.ts
index 8b8b066e..ad3619dd 100644
--- a/packages/vue-compat/__tests__/global.spec.ts
+++ b/packages/vue-compat/__tests__/global.spec.ts
@@ -1,5 +1,6 @@
import Vue from '@vue/compat'
import { effect, isReactive } from '@vue/reactivity'
+import { nextTick } from '@vue/runtime-core'
import {
DeprecationTypes,
deprecationData,
@@ -333,4 +334,50 @@ describe('GLOBAL_PRIVATE_UTIL', () => {
deprecationData[DeprecationTypes.GLOBAL_PRIVATE_UTIL].message
).toHaveBeenWarned()
})
+
+ test('defineReactive on instance', async () => {
+ const vm = new Vue({
+ beforeCreate() {
+ // @ts-ignore
+ Vue.util.defineReactive(this, 'foo', 1)
+ },
+ template: `{{ foo }}
`
+ }).$mount() as any
+ expect(vm.$el.textContent).toBe('1')
+ vm.foo = 2
+ await nextTick()
+ expect(vm.$el.textContent).toBe('2')
+ })
+
+ test('defineReactive with object value', () => {
+ const obj: any = {}
+ const val = { a: 1 }
+ // @ts-ignore
+ Vue.util.defineReactive(obj, 'foo', val)
+
+ let n
+ effect(() => {
+ n = obj.foo.a
+ })
+ expect(n).toBe(1)
+ // mutating original
+ val.a++
+ expect(n).toBe(2)
+ })
+
+ test('defineReactive with array value', () => {
+ const obj: any = {}
+ const val = [1]
+ // @ts-ignore
+ Vue.util.defineReactive(obj, 'foo', val)
+
+ let n
+ effect(() => {
+ n = obj.foo.length
+ })
+ expect(n).toBe(1)
+ // mutating original
+ val.push(2)
+ expect(n).toBe(2)
+ })
})
diff --git a/packages/vue-compat/__tests__/renderFn.spec.ts b/packages/vue-compat/__tests__/renderFn.spec.ts
index 00ad4c23..27b320e7 100644
--- a/packages/vue-compat/__tests__/renderFn.spec.ts
+++ b/packages/vue-compat/__tests__/renderFn.spec.ts
@@ -123,9 +123,29 @@ describe('compat: render function', () => {
})
).toMatchObject({
props: {
- onClick: fn, // should dedupe
+ onClick: fn,
+ onClickNative: fn,
onFooBar: fn,
- 'onBar-baz': fn
+ 'onBar-bazNative': fn
+ }
+ })
+ })
+
+ test('v2 legacy event prefixes', () => {
+ const fn = () => {}
+ expect(
+ h('div', {
+ on: {
+ '&click': fn,
+ '~keyup': fn,
+ '!touchend': fn
+ }
+ })
+ ).toMatchObject({
+ props: {
+ onClickPassive: fn,
+ onKeyupOnce: fn,
+ onTouchendCapture: fn
}
})
})