-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')
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])
+ })
})
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()
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(() => {})
isObject,
NO,
makeMap,
- isPromise
+ isPromise,
+ isArray
} from '@vue/shared'
import { SuspenseBoundary } from './components/Suspense'
import { CompilerOptions } from '@vue/compiler-core'
ERROR_CAPTURED = 'ec'
}
-export type Emit = (event: string, ...args: unknown[]) => void
+export type Emit = (event: string, ...args: unknown[]) => any[]
export interface SetupContext {
attrs: Data
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 []
}
}
}
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)) {
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(