nodeOps,
watch,
ref,
- nextTick
+ nextTick,
+ mockWarn
} from '@vue/runtime-test'
describe('error handling', () => {
+ mockWarn()
+
test('propagtaion', () => {
const err = new Error('foo')
const fn = jest.fn()
expect(fn).toHaveBeenCalledWith(err, 'mounted hook', 'child')
})
+ test('async error handling', 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)
+ }
+ }
+
+ const Child = {
+ setup() {
+ onMounted(async () => {
+ throw err
+ })
+ },
+ render() {}
+ }
+
+ render(h(Comp), nodeOps.createElement('div'))
+ expect(fn).not.toHaveBeenCalled()
+ await new Promise(r => setTimeout(r))
+ expect(fn).toHaveBeenCalledWith(err, 'mounted hook')
+ })
+
test('error thrown in onErrorCaptured', () => {
const err = new Error('foo')
const err2 = new Error('bar')
expect(fn).toHaveBeenCalledWith(err, 'component event handler')
})
+ it('should warn unhandled', () => {
+ const onError = jest.spyOn(console, 'error')
+ onError.mockImplementation(() => {})
+ const err = new Error('foo')
+ const fn = jest.fn()
+
+ const Comp = {
+ setup() {
+ onErrorCaptured((err, instance, info) => {
+ fn(err, info)
+ })
+ return () => h(Child)
+ }
+ }
+
+ const Child = {
+ setup() {
+ throw err
+ },
+ render() {}
+ }
+
+ render(h(Comp), nodeOps.createElement('div'))
+ expect(fn).toHaveBeenCalledWith(err, 'setup function')
+ expect(
+ `Unhandled error during execution of setup function`
+ ).toHaveBeenWarned()
+ expect(onError).toHaveBeenCalledWith(err)
+ onError.mockRestore()
+ })
+
// native event handler handling should be tested in respective renderers
})
// setup returned an inline render function
instance.render = setupResult
} else {
+ if (__DEV__) {
+ if (!Component.render) {
+ warn(
+ `Component is missing render function. Either provide a template or ` +
+ `return a render function from setup().`
+ )
+ }
+ if (
+ setupResult &&
+ typeof setupResult.then === 'function' &&
+ typeof setupResult.catch === 'function'
+ ) {
+ warn(`setup() returned a Promise. setup() cannot be async.`)
+ }
+ }
// setup returned bindings.
// assuming a render function compiled from template is present.
instance.data = reactive(setupResult || {})
- if (__DEV__ && !Component.render) {
- warn(
- `Component is missing render function. Either provide a template or ` +
- `return a render function from setup().`
- )
- }
instance.render = (Component.render || NOOP) as RenderFunction
}
} else {