Skip to content

Commit 37533fd

Browse files
committed
refactor: improve errorCaptured propagation behavior
1 parent 96b9744 commit 37533fd

File tree

3 files changed

+108
-13
lines changed

3 files changed

+108
-13
lines changed

Diff for: src/core/util/error.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ export function handleError (err: Error, vm: any, info: string) {
88
if (vm) {
99
let cur = vm
1010
while ((cur = cur.$parent)) {
11-
if (cur.$options.errorCaptured) {
12-
try {
13-
const propagate = cur.$options.errorCaptured.call(cur, err, vm, info)
14-
if (!propagate) return
15-
} catch (e) {
16-
globalHandleError(e, cur, 'errorCaptured hook')
11+
const hooks = cur.$options.errorCaptured
12+
if (hooks) {
13+
for (let i = 0; i < hooks.length; i++) {
14+
try {
15+
const capture = hooks[i].call(cur, err, vm, info) === false
16+
if (capture) return
17+
} catch (e) {
18+
globalHandleError(e, cur, 'errorCaptured hook')
19+
}
1720
}
1821
}
1922
}

Diff for: src/shared/constants.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,6 @@ export const LIFECYCLE_HOOKS = [
1616
'beforeDestroy',
1717
'destroyed',
1818
'activated',
19-
'deactivated'
19+
'deactivated',
20+
'errorCaptured'
2021
]

Diff for: test/unit/features/options/errorCaptured.spec.js

+97-6
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ describe('Options errorCaptured', () => {
3131
}).$mount()
3232

3333
expect(spy).toHaveBeenCalledWith(err, child, 'created hook')
34-
// should not propagate by default
35-
expect(globalSpy).not.toHaveBeenCalled()
34+
// should propagate by default
35+
expect(globalSpy).toHaveBeenCalledWith(err, child, 'created hook')
3636
})
3737

3838
it('should be able to render the error in itself', done => {
@@ -67,7 +67,7 @@ describe('Options errorCaptured', () => {
6767
}).then(done)
6868
})
6969

70-
it('should propagate to global handler when returning true', () => {
70+
it('should not propagate to global handler when returning true', () => {
7171
const spy = jasmine.createSpy()
7272

7373
let child
@@ -84,14 +84,14 @@ describe('Options errorCaptured', () => {
8484
new Vue({
8585
errorCaptured (err, vm, info) {
8686
spy(err, vm, info)
87-
return true
87+
return false
8888
},
8989
render: h => h(Child, {})
9090
}).$mount()
9191

9292
expect(spy).toHaveBeenCalledWith(err, child, 'created hook')
93-
// should propagate
94-
expect(globalSpy).toHaveBeenCalledWith(err, child, 'created hook')
93+
// should not propagate
94+
expect(globalSpy).not.toHaveBeenCalled()
9595
})
9696

9797
it('should propagate to global handler if itself throws error', () => {
@@ -118,4 +118,95 @@ describe('Options errorCaptured', () => {
118118
expect(globalSpy).toHaveBeenCalledWith(err, child, 'created hook')
119119
expect(globalSpy).toHaveBeenCalledWith(err2, vm, 'errorCaptured hook')
120120
})
121+
122+
it('should work across multiple parents, mixins and extends', () => {
123+
const calls = []
124+
125+
const Child = {
126+
created () {
127+
throw new Error('child')
128+
},
129+
render () {}
130+
}
131+
132+
const ErrorBoundaryBase = {
133+
errorCaptured () {
134+
calls.push(1)
135+
}
136+
}
137+
138+
const mixin = {
139+
errorCaptured () {
140+
calls.push(2)
141+
}
142+
}
143+
144+
const ErrorBoundaryExtended = {
145+
extends: ErrorBoundaryBase,
146+
mixins: [mixin],
147+
errorCaptured () {
148+
calls.push(3)
149+
},
150+
render: h => h(Child)
151+
}
152+
153+
Vue.config.errorHandler = () => {
154+
calls.push(5)
155+
}
156+
157+
new Vue({
158+
errorCaptured () {
159+
calls.push(4)
160+
},
161+
render: h => h(ErrorBoundaryExtended)
162+
}).$mount()
163+
164+
expect(calls).toEqual([1, 2, 3, 4, 5])
165+
})
166+
167+
it('should work across multiple parents, mixins and extends with return false', () => {
168+
const calls = []
169+
170+
const Child = {
171+
created () {
172+
throw new Error('child')
173+
},
174+
render () {}
175+
}
176+
177+
const ErrorBoundaryBase = {
178+
errorCaptured () {
179+
calls.push(1)
180+
}
181+
}
182+
183+
const mixin = {
184+
errorCaptured () {
185+
calls.push(2)
186+
}
187+
}
188+
189+
const ErrorBoundaryExtended = {
190+
extends: ErrorBoundaryBase,
191+
mixins: [mixin],
192+
errorCaptured () {
193+
calls.push(3)
194+
return false
195+
},
196+
render: h => h(Child)
197+
}
198+
199+
Vue.config.errorHandler = () => {
200+
calls.push(5)
201+
}
202+
203+
new Vue({
204+
errorCaptured () {
205+
calls.push(4)
206+
},
207+
render: h => h(ErrorBoundaryExtended)
208+
}).$mount()
209+
210+
expect(calls).toEqual([1, 2, 3])
211+
})
121212
})

0 commit comments

Comments
 (0)