From: Evan You Date: Fri, 30 Aug 2019 20:20:32 +0000 (-0400) Subject: test: more coverage for error handling X-Git-Tag: v3.0.0-alpha.0~858 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6801885f5798b365dd268b34e05c10faf12a97c2;p=thirdparty%2Fvuejs%2Fcore.git test: more coverage for error handling --- diff --git a/packages/runtime-core/__tests__/errorHandling.spec.ts b/packages/runtime-core/__tests__/errorHandling.spec.ts index fb752a6bf7..9756692fcb 100644 --- a/packages/runtime-core/__tests__/errorHandling.spec.ts +++ b/packages/runtime-core/__tests__/errorHandling.spec.ts @@ -6,10 +6,13 @@ import { 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() @@ -86,6 +89,35 @@ describe('error handling', () => { 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') @@ -327,5 +359,36 @@ describe('error handling', () => { 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 }) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 67803d5ba2..396313490a 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -296,15 +296,24 @@ export function setupStatefulComponent(instance: ComponentInstance) { // 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 {