feat(runtime-core): emit now returns array of return values from all triggered handlers
close #635
This commit is contained in:
parent
aca2c2a81e
commit
e81c8a32c7
@ -1,4 +1,11 @@
|
|||||||
import { h, ref, render, nodeOps, nextTick } from '@vue/runtime-test'
|
import {
|
||||||
|
h,
|
||||||
|
ref,
|
||||||
|
render,
|
||||||
|
nodeOps,
|
||||||
|
nextTick,
|
||||||
|
defineComponent
|
||||||
|
} from '@vue/runtime-test'
|
||||||
|
|
||||||
describe('renderer: component', () => {
|
describe('renderer: component', () => {
|
||||||
test.todo('should work')
|
test.todo('should work')
|
||||||
@ -52,4 +59,35 @@ describe('renderer: component', () => {
|
|||||||
expect(spy).toHaveBeenCalledTimes(2)
|
expect(spy).toHaveBeenCalledTimes(2)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('emit', async () => {
|
||||||
|
let noMatchEmitResult: any
|
||||||
|
let singleEmitResult: any
|
||||||
|
let multiEmitResult: any
|
||||||
|
|
||||||
|
const Child = defineComponent({
|
||||||
|
setup(_, { emit }) {
|
||||||
|
noMatchEmitResult = emit('foo')
|
||||||
|
singleEmitResult = emit('bar')
|
||||||
|
multiEmitResult = emit('baz')
|
||||||
|
return () => h('div')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const App = {
|
||||||
|
setup() {
|
||||||
|
return () =>
|
||||||
|
h(Child, {
|
||||||
|
onBar: () => 1,
|
||||||
|
onBaz: [() => Promise.resolve(2), () => Promise.resolve(3)]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(h(App), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
expect(noMatchEmitResult).toMatchObject([])
|
||||||
|
expect(singleEmitResult).toMatchObject([1])
|
||||||
|
expect(await Promise.all(multiEmitResult)).toMatchObject([2, 3])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -362,7 +362,7 @@ describe('error handling', () => {
|
|||||||
expect(fn).toHaveBeenCalledWith(err, 'watcher cleanup function')
|
expect(fn).toHaveBeenCalledWith(err, 'watcher cleanup function')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('in component event handler', () => {
|
test('in component event handler via emit', () => {
|
||||||
const err = new Error('foo')
|
const err = new Error('foo')
|
||||||
const fn = jest.fn()
|
const fn = jest.fn()
|
||||||
|
|
||||||
@ -392,6 +392,78 @@ describe('error handling', () => {
|
|||||||
expect(fn).toHaveBeenCalledWith(err, 'component event handler')
|
expect(fn).toHaveBeenCalledWith(err, 'component event handler')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('in component event handler via emit (async)', async () => {
|
||||||
|
const err = new Error('foo')
|
||||||
|
const fn = jest.fn()
|
||||||
|
|
||||||
|
const Comp = {
|
||||||
|
setup() {
|
||||||
|
onErrorCaptured((err, instance, info) => {
|
||||||
|
fn(err, info)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return () =>
|
||||||
|
h(Child, {
|
||||||
|
async onFoo() {
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res: any
|
||||||
|
const Child = {
|
||||||
|
setup(props: any, { emit }: any) {
|
||||||
|
res = emit('foo')
|
||||||
|
return () => null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(h(Comp), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Promise.all(res)
|
||||||
|
} catch (e) {
|
||||||
|
expect(e).toBe(err)
|
||||||
|
}
|
||||||
|
expect(fn).toHaveBeenCalledWith(err, 'component event handler')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('in component event handler via emit (async + array)', async () => {
|
||||||
|
const err = new Error('foo')
|
||||||
|
const fn = jest.fn()
|
||||||
|
|
||||||
|
const Comp = {
|
||||||
|
setup() {
|
||||||
|
onErrorCaptured((err, instance, info) => {
|
||||||
|
fn(err, info)
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
return () =>
|
||||||
|
h(Child, {
|
||||||
|
onFoo: [() => Promise.reject(err), () => Promise.resolve(1)]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res: any
|
||||||
|
const Child = {
|
||||||
|
setup(props: any, { emit }: any) {
|
||||||
|
res = emit('foo')
|
||||||
|
return () => null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(h(Comp), nodeOps.createElement('div'))
|
||||||
|
|
||||||
|
try {
|
||||||
|
await Promise.all(res)
|
||||||
|
} catch (e) {
|
||||||
|
expect(e).toBe(err)
|
||||||
|
}
|
||||||
|
expect(fn).toHaveBeenCalledWith(err, 'component event handler')
|
||||||
|
})
|
||||||
|
|
||||||
it('should warn unhandled', () => {
|
it('should warn unhandled', () => {
|
||||||
const onError = jest.spyOn(console, 'error')
|
const onError = jest.spyOn(console, 'error')
|
||||||
onError.mockImplementation(() => {})
|
onError.mockImplementation(() => {})
|
||||||
|
@ -24,7 +24,8 @@ import {
|
|||||||
isObject,
|
isObject,
|
||||||
NO,
|
NO,
|
||||||
makeMap,
|
makeMap,
|
||||||
isPromise
|
isPromise,
|
||||||
|
isArray
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
import { SuspenseBoundary } from './components/Suspense'
|
import { SuspenseBoundary } from './components/Suspense'
|
||||||
import { CompilerOptions } from '@vue/compiler-core'
|
import { CompilerOptions } from '@vue/compiler-core'
|
||||||
@ -70,7 +71,7 @@ export const enum LifecycleHooks {
|
|||||||
ERROR_CAPTURED = 'ec'
|
ERROR_CAPTURED = 'ec'
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Emit = (event: string, ...args: unknown[]) => void
|
export type Emit = (event: string, ...args: unknown[]) => any[]
|
||||||
|
|
||||||
export interface SetupContext {
|
export interface SetupContext {
|
||||||
attrs: Data
|
attrs: Data
|
||||||
@ -218,16 +219,19 @@ export function defineComponentInstance(
|
|||||||
rtc: null,
|
rtc: null,
|
||||||
ec: null,
|
ec: null,
|
||||||
|
|
||||||
emit: (event, ...args) => {
|
emit: (event, ...args): any[] => {
|
||||||
const props = instance.vnode.props || EMPTY_OBJ
|
const props = instance.vnode.props || EMPTY_OBJ
|
||||||
const handler = props[`on${event}`] || props[`on${capitalize(event)}`]
|
const handler = props[`on${event}`] || props[`on${capitalize(event)}`]
|
||||||
if (handler) {
|
if (handler) {
|
||||||
callWithAsyncErrorHandling(
|
const res = callWithAsyncErrorHandling(
|
||||||
handler,
|
handler,
|
||||||
instance,
|
instance,
|
||||||
ErrorCodes.COMPONENT_EVENT_HANDLER,
|
ErrorCodes.COMPONENT_EVENT_HANDLER,
|
||||||
args
|
args
|
||||||
)
|
)
|
||||||
|
return isArray(res) ? res : [res]
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ export function callWithAsyncErrorHandling(
|
|||||||
instance: ComponentInternalInstance | null,
|
instance: ComponentInternalInstance | null,
|
||||||
type: ErrorTypes,
|
type: ErrorTypes,
|
||||||
args?: unknown[]
|
args?: unknown[]
|
||||||
) {
|
): any[] {
|
||||||
if (isFunction(fn)) {
|
if (isFunction(fn)) {
|
||||||
const res = callWithErrorHandling(fn, instance, type, args)
|
const res = callWithErrorHandling(fn, instance, type, args)
|
||||||
if (res != null && !res._isVue && isPromise(res)) {
|
if (res != null && !res._isVue && isPromise(res)) {
|
||||||
@ -85,9 +85,11 @@ export function callWithAsyncErrorHandling(
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const values = []
|
||||||
for (let i = 0; i < fn.length; i++) {
|
for (let i = 0; i < fn.length; i++) {
|
||||||
callWithAsyncErrorHandling(fn[i], instance, type, args)
|
values.push(callWithAsyncErrorHandling(fn[i], instance, type, args))
|
||||||
}
|
}
|
||||||
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleError(
|
export function handleError(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user