refactor(runtime-core): adjust error handling behavior

- Crash in dev to make the errors more noticeable
- Recover in prod to reduce impact on end users
This commit is contained in:
Evan You 2020-07-28 00:17:59 -04:00
parent 678364802d
commit 3cc768f9f2
2 changed files with 12 additions and 24 deletions

View File

@ -10,17 +10,8 @@ import {
defineComponent, defineComponent,
watchEffect watchEffect
} from '@vue/runtime-test' } from '@vue/runtime-test'
import { setErrorRecovery } from '../src/errorHandling'
describe('error handling', () => { describe('error handling', () => {
beforeEach(() => {
setErrorRecovery(true)
})
afterEach(() => {
setErrorRecovery(false)
})
test('propagation', () => { test('propagation', () => {
const err = new Error('foo') const err = new Error('foo')
const fn = jest.fn() const fn = jest.fn()
@ -470,8 +461,6 @@ describe('error handling', () => {
}) })
it('should warn unhandled', () => { it('should warn unhandled', () => {
const onError = jest.spyOn(console, 'error')
onError.mockImplementation(() => {})
const groupCollapsed = jest.spyOn(console, 'groupCollapsed') const groupCollapsed = jest.spyOn(console, 'groupCollapsed')
groupCollapsed.mockImplementation(() => {}) groupCollapsed.mockImplementation(() => {})
const log = jest.spyOn(console, 'log') const log = jest.spyOn(console, 'log')
@ -496,14 +485,18 @@ describe('error handling', () => {
render() {} render() {}
} }
render(h(Comp), nodeOps.createElement('div')) let caughtError
try {
render(h(Comp), nodeOps.createElement('div'))
} catch (caught) {
caughtError = caught
}
expect(fn).toHaveBeenCalledWith(err, 'setup function') expect(fn).toHaveBeenCalledWith(err, 'setup function')
expect( expect(
`Unhandled error during execution of setup function` `Unhandled error during execution of setup function`
).toHaveBeenWarned() ).toHaveBeenWarned()
expect(onError).toHaveBeenCalledWith(err) expect(caughtError).toBe(err)
onError.mockRestore()
groupCollapsed.mockRestore() groupCollapsed.mockRestore()
log.mockRestore() log.mockRestore()
}) })

View File

@ -134,25 +134,20 @@ export function handleError(
logError(err, type, contextVNode) logError(err, type, contextVNode)
} }
// Test-only toggle for testing the unhandled warning behavior
let forceRecover = false
export function setErrorRecovery(value: boolean) {
forceRecover = value
}
function logError(err: unknown, type: ErrorTypes, contextVNode: VNode | null) { function logError(err: unknown, type: ErrorTypes, contextVNode: VNode | null) {
// default behavior is crash in prod & test, recover in dev. if (__DEV__) {
if (__DEV__ && (forceRecover || !__TEST__)) {
const info = ErrorTypeStrings[type] const info = ErrorTypeStrings[type]
if (contextVNode) { if (contextVNode) {
pushWarningContext(contextVNode) pushWarningContext(contextVNode)
} }
warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`) warn(`Unhandled error${info ? ` during execution of ${info}` : ``}`)
console.error(err)
if (contextVNode) { if (contextVNode) {
popWarningContext() popWarningContext()
} }
} else { // crash in dev so it's more noticeable
throw err throw err
} else {
// recover in prod to reduce the impact on end-user
console.error(err)
} }
} }