Skip to content

Commit

Permalink
feat(runtime-core): emit now returns array of return values from all …
Browse files Browse the repository at this point in the history
…triggered handlers

close #635
  • Loading branch information
yyx990803 committed Jan 20, 2020
1 parent aca2c2a commit e81c8a3
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 8 deletions.
40 changes: 39 additions & 1 deletion packages/runtime-core/__tests__/component.spec.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
test.todo('should work')
Expand Down Expand Up @@ -52,4 +59,35 @@ describe('renderer: component', () => {
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])
})
})
74 changes: 73 additions & 1 deletion packages/runtime-core/__tests__/errorHandling.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ describe('error handling', () => {
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 fn = jest.fn()

Expand Down Expand Up @@ -392,6 +392,78 @@ describe('error handling', () => {
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', () => {
const onError = jest.spyOn(console, 'error')
onError.mockImplementation(() => {})
Expand Down
12 changes: 8 additions & 4 deletions packages/runtime-core/src/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ import {
isObject,
NO,
makeMap,
isPromise
isPromise,
isArray
} from '@vue/shared'
import { SuspenseBoundary } from './components/Suspense'
import { CompilerOptions } from '@vue/compiler-core'
Expand Down Expand Up @@ -70,7 +71,7 @@ export const enum LifecycleHooks {
ERROR_CAPTURED = 'ec'
}

export type Emit = (event: string, ...args: unknown[]) => void
export type Emit = (event: string, ...args: unknown[]) => any[]

export interface SetupContext {
attrs: Data
Expand Down Expand Up @@ -218,16 +219,19 @@ export function defineComponentInstance(
rtc: null,
ec: null,

emit: (event, ...args) => {
emit: (event, ...args): any[] => {
const props = instance.vnode.props || EMPTY_OBJ
const handler = props[`on${event}`] || props[`on${capitalize(event)}`]
if (handler) {
callWithAsyncErrorHandling(
const res = callWithAsyncErrorHandling(
handler,
instance,
ErrorCodes.COMPONENT_EVENT_HANDLER,
args
)
return isArray(res) ? res : [res]
} else {
return []
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions packages/runtime-core/src/errorHandling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function callWithAsyncErrorHandling(
instance: ComponentInternalInstance | null,
type: ErrorTypes,
args?: unknown[]
) {
): any[] {
if (isFunction(fn)) {
const res = callWithErrorHandling(fn, instance, type, args)
if (res != null && !res._isVue && isPromise(res)) {
Expand All @@ -85,9 +85,11 @@ export function callWithAsyncErrorHandling(
return res
}

const values = []
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(
Expand Down

0 comments on commit e81c8a3

Please sign in to comment.