From 325e15ef41367aa5d382ad53740643a92041b9db Mon Sep 17 00:00:00 2001 From: Dmitry Sharshakov Date: Mon, 28 Oct 2019 19:03:30 +0300 Subject: [PATCH] feat(createRenderer): handle errors in function refs (#403) --- .../__tests__/errorHandling.spec.ts | 26 ++++++++++++++++++- packages/runtime-core/src/createRenderer.ts | 4 +-- packages/runtime-core/src/errorHandling.ts | 2 ++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/packages/runtime-core/__tests__/errorHandling.spec.ts b/packages/runtime-core/__tests__/errorHandling.spec.ts index 6f3f9c6a..feb2b30c 100644 --- a/packages/runtime-core/__tests__/errorHandling.spec.ts +++ b/packages/runtime-core/__tests__/errorHandling.spec.ts @@ -7,7 +7,8 @@ import { watch, ref, nextTick, - mockWarn + mockWarn, + createComponent } from '@vue/runtime-test' describe('error handling', () => { @@ -208,6 +209,29 @@ describe('error handling', () => { expect(fn).toHaveBeenCalledWith(err, 'render function') }) + test('in function ref', () => { + const err = new Error('foo') + const ref = () => { + throw err + } + const fn = jest.fn() + + const Comp = { + setup() { + onErrorCaptured((err, instance, info) => { + fn(err, info) + return true + }) + return () => h(Child) + } + } + + const Child = createComponent(() => () => h('div', { ref })) + + render(h(Comp), nodeOps.createElement('div')) + expect(fn).toHaveBeenCalledWith(err, 'ref function') + }) + test('in watch (simple usage)', () => { const err = new Error('foo') const fn = jest.fn() diff --git a/packages/runtime-core/src/createRenderer.ts b/packages/runtime-core/src/createRenderer.ts index 3473f53b..009329dc 100644 --- a/packages/runtime-core/src/createRenderer.ts +++ b/packages/runtime-core/src/createRenderer.ts @@ -52,7 +52,7 @@ import { createSuspenseBoundary, normalizeSuspenseChildren } from './suspense' -import { handleError, ErrorCodes } from './errorHandling' +import { handleError, ErrorCodes, callWithErrorHandling } from './errorHandling' const prodEffectOptions = { scheduler: queueJob @@ -1852,7 +1852,7 @@ export function createRenderer< } else if (isRef(ref)) { ref.value = value } else if (isFunction(ref)) { - ref(value, refs) + callWithErrorHandling(ref, parent, ErrorCodes.FUNCTION_REF, [value, refs]) } else if (__DEV__) { warn('Invalid template ref type:', value, `(${typeof value})`) } diff --git a/packages/runtime-core/src/errorHandling.ts b/packages/runtime-core/src/errorHandling.ts index d576ff4a..cc5e42c4 100644 --- a/packages/runtime-core/src/errorHandling.ts +++ b/packages/runtime-core/src/errorHandling.ts @@ -16,6 +16,7 @@ export const enum ErrorCodes { DIRECTIVE_HOOK, APP_ERROR_HANDLER, APP_WARN_HANDLER, + FUNCTION_REF, SCHEDULER } @@ -43,6 +44,7 @@ export const ErrorTypeStrings: Record = { [ErrorCodes.DIRECTIVE_HOOK]: 'directive hook', [ErrorCodes.APP_ERROR_HANDLER]: 'app errorHandler', [ErrorCodes.APP_WARN_HANDLER]: 'app warnHandler', + [ErrorCodes.FUNCTION_REF]: 'ref function', [ErrorCodes.SCHEDULER]: 'scheduler flush. This is likely a Vue internals bug. ' + 'Please open an issue at https://new-issue.vuejs.org/?repo=vuejs/vue'