From 54af49b5676086807a0ec7df9ce60160d92250fe Mon Sep 17 00:00:00 2001 From: Austin Story Date: Sun, 5 Nov 2017 13:55:34 -0600 Subject: [PATCH 1/3] Propogate thrown errors by configuring error handler and attaching in mount function resolves #147 --- src/lib/error-handler.js | 28 +++++++++++++++++ src/mount.js | 2 ++ test/unit/specs/lib/error-handler.spec.js | 38 +++++++++++++++++++++++ test/unit/specs/mount.spec.js | 10 ++++++ 4 files changed, 78 insertions(+) create mode 100644 src/lib/error-handler.js create mode 100644 test/unit/specs/lib/error-handler.spec.js diff --git a/src/lib/error-handler.js b/src/lib/error-handler.js new file mode 100644 index 000000000..19b44172a --- /dev/null +++ b/src/lib/error-handler.js @@ -0,0 +1,28 @@ +function errorMessage(msg, info) { + if (info) { + return `${msg} : additional info ${info}` + } + + return msg; +} + +function setVueErrorHandler(vue) { + vue.config.errorHandler = errorHandler +} + +function errorHandler(err, _vm, info) { + if ((typeof err === 'object') && err.message) { + if (info) { + err.message = errorMessage(err.message, info); + } + + throw err; + } + + throw new Error(errorMessage(err, info)); +} + +export { + errorHandler, + setVueErrorHandler +} diff --git a/src/mount.js b/src/mount.js index c33163b80..432ec9dac 100644 --- a/src/mount.js +++ b/src/mount.js @@ -7,8 +7,10 @@ import createInstance from './lib/create-instance' import cloneDeep from 'lodash/cloneDeep' import createElement from './lib/create-element' import './lib/matches-polyfill' +import { setVueErrorHandler } from './lib/error-handler' Vue.config.productionTip = false +setVueErrorHandler(Vue) export default function mount (component: Component, options: Options = {}): VueWrapper { const componentToMount = options.clone === false ? component : cloneDeep(component.extend ? component.options : component) diff --git a/test/unit/specs/lib/error-handler.spec.js b/test/unit/specs/lib/error-handler.spec.js new file mode 100644 index 000000000..76b5b221e --- /dev/null +++ b/test/unit/specs/lib/error-handler.spec.js @@ -0,0 +1,38 @@ +import { errorHandler } from '../../../../src/lib/error-handler' + +describe('errorHandler', () => { + const errorString = 'errorString' + const info = 'additional info provided by vue' + + describe('with Error thrown', () => { + const error = new Error(errorString) + + it('rethrows error', () => { + expect(() => errorHandler(error)).to.throw().with.property('message', errorString) + }) + + it('rethrown error contains vue info when provided', () => { + expect(() => errorHandler(error, {}, info)).to.throw().that.satisfies(function(err) { + const errorMessage = err.message + + return errorMessage.includes(errorString) && errorMessage.includes(info) + }); + }) + }) + + describe('with not Error object thrown', () => { + const error = errorString + + it('throws error with string', () => { + expect(() => errorHandler(error)).to.throw().with.property('message', errorString) + }) + + it('throws error with string and appends info when provided', () => { + expect(() => errorHandler(error, {}, info)).to.throw().that.satisfies(function(err) { + const errorMessage = err.message; + + return errorMessage.includes(errorString) && errorMessage.includes(info) + }); + }) + }) +}) diff --git a/test/unit/specs/mount.spec.js b/test/unit/specs/mount.spec.js index 0082d2d7b..357155d3c 100644 --- a/test/unit/specs/mount.spec.js +++ b/test/unit/specs/mount.spec.js @@ -85,4 +85,14 @@ describe('mount', () => { expect(wrapper.vm).to.be.an('object') expect(wrapper.html()).to.equal(`
foo
`) }) + + it('throws an error when it fails to mount', () => { + expect(() => mount({ + template: '
', + mounted: function() { + throw(new Error('Error')) + } + })).to.throw(); + + }) }) From e43f9fc5d4ee79cc0a89ac70f1f0c1a64c6b63f9 Mon Sep 17 00:00:00 2001 From: Austin Story Date: Sun, 5 Nov 2017 21:08:11 -0600 Subject: [PATCH 2/3] set errorHandler to be a default export and set Vue.config.errorHandler = errorHandler in mount --- src/lib/error-handler.js | 21 ++++-------- src/mount.js | 4 +-- test/unit/specs/create-local-vue.spec.js | 9 ++++++ test/unit/specs/lib/error-handler.spec.js | 39 ++++++++++------------- test/unit/specs/mount.spec.js | 15 ++++----- test/unit/specs/shallow.spec.js | 9 ++++++ 6 files changed, 49 insertions(+), 48 deletions(-) diff --git a/src/lib/error-handler.js b/src/lib/error-handler.js index 19b44172a..3f721826b 100644 --- a/src/lib/error-handler.js +++ b/src/lib/error-handler.js @@ -1,28 +1,19 @@ -function errorMessage(msg, info) { +function errorMessage (msg, info) { if (info) { return `${msg} : additional info ${info}` } - return msg; + return msg } -function setVueErrorHandler(vue) { - vue.config.errorHandler = errorHandler -} - -function errorHandler(err, _vm, info) { +export default function errorHandler (err, _vm, info) { if ((typeof err === 'object') && err.message) { if (info) { - err.message = errorMessage(err.message, info); + err.message = errorMessage(err.message, info) } - throw err; + throw err } - throw new Error(errorMessage(err, info)); -} - -export { - errorHandler, - setVueErrorHandler + throw new Error(errorMessage(err, info)) } diff --git a/src/mount.js b/src/mount.js index 432ec9dac..9a461d2b9 100644 --- a/src/mount.js +++ b/src/mount.js @@ -7,10 +7,10 @@ import createInstance from './lib/create-instance' import cloneDeep from 'lodash/cloneDeep' import createElement from './lib/create-element' import './lib/matches-polyfill' -import { setVueErrorHandler } from './lib/error-handler' +import errorHandler from './lib/error-handler' Vue.config.productionTip = false -setVueErrorHandler(Vue) +Vue.config.errorHandler = errorHandler export default function mount (component: Component, options: Options = {}): VueWrapper { const componentToMount = options.clone === false ? component : cloneDeep(component.extend ? component.options : component) diff --git a/test/unit/specs/create-local-vue.spec.js b/test/unit/specs/create-local-vue.spec.js index ff14bb22f..70b49cc59 100644 --- a/test/unit/specs/create-local-vue.spec.js +++ b/test/unit/specs/create-local-vue.spec.js @@ -112,4 +112,13 @@ describe('createLocalVue', () => { const localVue = createLocalVue() localVue.use(Vuetify) }) + + it('throws an error when the component fails to mount', () => { + expect(() => mount({ + template: '
', + mounted: function () { + throw (new Error('Error')) + } + })).to.throw() + }) }) diff --git a/test/unit/specs/lib/error-handler.spec.js b/test/unit/specs/lib/error-handler.spec.js index 76b5b221e..9e6dbdbb0 100644 --- a/test/unit/specs/lib/error-handler.spec.js +++ b/test/unit/specs/lib/error-handler.spec.js @@ -1,38 +1,31 @@ -import { errorHandler } from '../../../../src/lib/error-handler' +import errorHandler from '../../../../src/lib/error-handler' describe('errorHandler', () => { const errorString = 'errorString' const info = 'additional info provided by vue' + const errorObject = new Error(errorString) - describe('with Error thrown', () => { - const error = new Error(errorString) - - it('rethrows error', () => { - expect(() => errorHandler(error)).to.throw().with.property('message', errorString) - }) + it('when error object: rethrows error', () => { + expect(() => errorHandler(errorObject)).to.throw().with.property('message', errorString) + }) - it('rethrown error contains vue info when provided', () => { - expect(() => errorHandler(error, {}, info)).to.throw().that.satisfies(function(err) { - const errorMessage = err.message + it('when error object: rethrown error contains vue info when provided', () => { + expect(() => errorHandler(errorObject, {}, info)).to.throw().that.satisfies(function (err) { + const errorMessage = err.message - return errorMessage.includes(errorString) && errorMessage.includes(info) - }); + return errorMessage.includes(errorString) && errorMessage.includes(info) }) }) - describe('with not Error object thrown', () => { - const error = errorString - - it('throws error with string', () => { - expect(() => errorHandler(error)).to.throw().with.property('message', errorString) - }) + it('when error string: throws error with string', () => { + expect(() => errorHandler(errorString)).to.throw().with.property('message', errorString) + }) - it('throws error with string and appends info when provided', () => { - expect(() => errorHandler(error, {}, info)).to.throw().that.satisfies(function(err) { - const errorMessage = err.message; + it('throws error with string and appends info when provided', () => { + expect(() => errorHandler(errorString, {}, info)).to.throw().that.satisfies(function (err) { + const errorMessage = err.message - return errorMessage.includes(errorString) && errorMessage.includes(info) - }); + return errorMessage.includes(errorString) && errorMessage.includes(info) }) }) }) diff --git a/test/unit/specs/mount.spec.js b/test/unit/specs/mount.spec.js index 357155d3c..29c086729 100644 --- a/test/unit/specs/mount.spec.js +++ b/test/unit/specs/mount.spec.js @@ -86,13 +86,12 @@ describe('mount', () => { expect(wrapper.html()).to.equal(`
foo
`) }) - it('throws an error when it fails to mount', () => { + it('throws an error when the component fails to mount', () => { expect(() => mount({ - template: '
', - mounted: function() { - throw(new Error('Error')) - } - })).to.throw(); - - }) + template: '
', + mounted: function () { + throw (new Error('Error')) + } + })).to.throw() + }) }) diff --git a/test/unit/specs/shallow.spec.js b/test/unit/specs/shallow.spec.js index 2204b8dd5..066a44868 100644 --- a/test/unit/specs/shallow.spec.js +++ b/test/unit/specs/shallow.spec.js @@ -74,4 +74,13 @@ describe('shallow', () => { shallow(ComponentWithNestedChildren) expect(info.called).to.equal(false) }) + + it('throws an error when the component fails to mount', () => { + expect(() => shallow({ + template: '
', + mounted: function () { + throw (new Error('Error')) + } + })).to.throw() + }) }) From 0084d2bb4151d1b1dde958cf939b8666676afb5a Mon Sep 17 00:00:00 2001 From: Austin Story Date: Sun, 5 Nov 2017 21:28:27 -0600 Subject: [PATCH 3/3] Add test for create-local-vue error handler being defined and configure that in create local vue --- src/create-local-vue.js | 3 +++ test/unit/specs/create-local-vue.spec.js | 11 ++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/create-local-vue.js b/src/create-local-vue.js index cc33d6e3a..2eb2ba730 100644 --- a/src/create-local-vue.js +++ b/src/create-local-vue.js @@ -2,6 +2,7 @@ import Vue from 'vue' import cloneDeep from 'lodash/cloneDeep' +import errorHandler from './lib/error-handler' function createLocalVue (): Component { const instance = Vue.extend() @@ -19,6 +20,8 @@ function createLocalVue (): Component { // config is not enumerable instance.config = cloneDeep(Vue.config) + instance.config.errorHandler = errorHandler + // option merge strategies need to be exposed by reference // so that merge strats registered by plguins can work properly instance.config.optionMergeStrategies = Vue.config.optionMergeStrategies diff --git a/test/unit/specs/create-local-vue.spec.js b/test/unit/specs/create-local-vue.spec.js index 70b49cc59..fdac20c9b 100644 --- a/test/unit/specs/create-local-vue.spec.js +++ b/test/unit/specs/create-local-vue.spec.js @@ -113,12 +113,9 @@ describe('createLocalVue', () => { localVue.use(Vuetify) }) - it('throws an error when the component fails to mount', () => { - expect(() => mount({ - template: '
', - mounted: function () { - throw (new Error('Error')) - } - })).to.throw() + it('has an errorHandler', () => { + const localVue = createLocalVue() + + expect(localVue.config.errorHandler).to.be.an('function') }) })