Skip to content

Commit 3f3c64a

Browse files
Austioeddyerburgh
authored andcommitted
feat(errors): propogate thrown errors by configuring error handler (#154)
* Propogate thrown errors by configuring error handler and attaching in mount function resolves #147 * set errorHandler to be a default export and set Vue.config.errorHandler = errorHandler in mount * Add test for create-local-vue error handler being defined and configure that in create local vue
1 parent e484c7e commit 3f3c64a

File tree

7 files changed

+79
-0
lines changed

7 files changed

+79
-0
lines changed

src/create-local-vue.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import Vue from 'vue'
44
import cloneDeep from 'lodash/cloneDeep'
5+
import errorHandler from './lib/error-handler'
56

67
function createLocalVue (): Component {
78
const instance = Vue.extend()
@@ -19,6 +20,8 @@ function createLocalVue (): Component {
1920
// config is not enumerable
2021
instance.config = cloneDeep(Vue.config)
2122

23+
instance.config.errorHandler = errorHandler
24+
2225
// option merge strategies need to be exposed by reference
2326
// so that merge strats registered by plguins can work properly
2427
instance.config.optionMergeStrategies = Vue.config.optionMergeStrategies

src/lib/error-handler.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function errorMessage (msg, info) {
2+
if (info) {
3+
return `${msg} : additional info ${info}`
4+
}
5+
6+
return msg
7+
}
8+
9+
export default function errorHandler (err, _vm, info) {
10+
if ((typeof err === 'object') && err.message) {
11+
if (info) {
12+
err.message = errorMessage(err.message, info)
13+
}
14+
15+
throw err
16+
}
17+
18+
throw new Error(errorMessage(err, info))
19+
}

src/mount.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ import createInstance from './lib/create-instance'
77
import cloneDeep from 'lodash/cloneDeep'
88
import createElement from './lib/create-element'
99
import './lib/matches-polyfill'
10+
import errorHandler from './lib/error-handler'
1011

1112
Vue.config.productionTip = false
13+
Vue.config.errorHandler = errorHandler
1214

1315
export default function mount (component: Component, options: Options = {}): VueWrapper {
1416
const componentToMount = options.clone === false ? component : cloneDeep(component.extend ? component.options : component)

test/unit/specs/create-local-vue.spec.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,10 @@ describe('createLocalVue', () => {
112112
const localVue = createLocalVue()
113113
localVue.use(Vuetify)
114114
})
115+
116+
it('has an errorHandler', () => {
117+
const localVue = createLocalVue()
118+
119+
expect(localVue.config.errorHandler).to.be.an('function')
120+
})
115121
})
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import errorHandler from '../../../../src/lib/error-handler'
2+
3+
describe('errorHandler', () => {
4+
const errorString = 'errorString'
5+
const info = 'additional info provided by vue'
6+
const errorObject = new Error(errorString)
7+
8+
it('when error object: rethrows error', () => {
9+
expect(() => errorHandler(errorObject)).to.throw().with.property('message', errorString)
10+
})
11+
12+
it('when error object: rethrown error contains vue info when provided', () => {
13+
expect(() => errorHandler(errorObject, {}, info)).to.throw().that.satisfies(function (err) {
14+
const errorMessage = err.message
15+
16+
return errorMessage.includes(errorString) && errorMessage.includes(info)
17+
})
18+
})
19+
20+
it('when error string: throws error with string', () => {
21+
expect(() => errorHandler(errorString)).to.throw().with.property('message', errorString)
22+
})
23+
24+
it('throws error with string and appends info when provided', () => {
25+
expect(() => errorHandler(errorString, {}, info)).to.throw().that.satisfies(function (err) {
26+
const errorMessage = err.message
27+
28+
return errorMessage.includes(errorString) && errorMessage.includes(info)
29+
})
30+
})
31+
})

test/unit/specs/mount.spec.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,13 @@ describe('mount', () => {
8585
expect(wrapper.vm).to.be.an('object')
8686
expect(wrapper.html()).to.equal(`<div>foo</div>`)
8787
})
88+
89+
it('throws an error when the component fails to mount', () => {
90+
expect(() => mount({
91+
template: '<div></div>',
92+
mounted: function () {
93+
throw (new Error('Error'))
94+
}
95+
})).to.throw()
96+
})
8897
})

test/unit/specs/shallow.spec.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,13 @@ describe('shallow', () => {
7474
shallow(ComponentWithNestedChildren)
7575
expect(info.called).to.equal(false)
7676
})
77+
78+
it('throws an error when the component fails to mount', () => {
79+
expect(() => shallow({
80+
template: '<div></div>',
81+
mounted: function () {
82+
throw (new Error('Error'))
83+
}
84+
})).to.throw()
85+
})
7786
})

0 commit comments

Comments
 (0)