Skip to content

Commit 3e84d0a

Browse files
committed
improve error handling
1 parent 4ed8744 commit 3e84d0a

File tree

5 files changed

+85
-8
lines changed

5 files changed

+85
-8
lines changed

src/router/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ var historyBackends = {
1414
* - {Boolean} abstract (default: false)
1515
* - {Boolean} saveScrollPosition (default: false)
1616
* - {Boolean} transitionOnLoad (default: false)
17+
* - {Boolean} suppressTransitionError (default: false)
1718
* - {String} root (default: null)
1819
* - {String} linkActiveClass (default: 'v-link-active')
1920
*/
@@ -60,6 +61,7 @@ function Router (options) {
6061
// other options
6162
this._saveScrollPosition = !!options.saveScrollPosition
6263
this._linkActiveClass = options.linkActiveClass || 'v-link-active'
64+
this._suppress = !!options.suppressTransitionError
6365

6466
// create history object
6567
this.mode = this._abstract

src/transition.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ p.runQueue = function (queue, fn, cb) {
184184
p.callHook = function (hook, context, cb, expectBoolean, cleanup) {
185185
var transition = this
186186
var nextCalled = false
187+
187188
var next = function (data) {
188189
if (nextCalled) {
189190
util.warn('transition.next() should be called only once.')
@@ -195,10 +196,23 @@ p.callHook = function (hook, context, cb, expectBoolean, cleanup) {
195196
}
196197
cb(data)
197198
}
199+
198200
var abort = function () {
199201
cleanup && cleanup()
200202
transition.abort()
201203
}
204+
205+
var onError = function (err) {
206+
// cleanup indicates an after-activation hook,
207+
// so instead of aborting we just let the transition
208+
// finish.
209+
cleanup ? next() : abort()
210+
if (err && !transition.router._suppress) {
211+
util.warn('Uncaught error during transition: ')
212+
throw err instanceof Error ? err : new Error(err)
213+
}
214+
}
215+
202216
// the copied transition object passed to the user.
203217
var exposed = {
204218
to: transition.to,
@@ -209,18 +223,23 @@ p.callHook = function (hook, context, cb, expectBoolean, cleanup) {
209223
transition.redirect.apply(transition, arguments)
210224
}
211225
}
212-
var res = hook.call(context, exposed)
226+
var res
227+
try {
228+
res = hook.call(context, exposed)
229+
} catch (err) {
230+
return onError(err)
231+
}
213232
var promise = util.isPromise(res)
214233
if (expectBoolean) {
215234
if (typeof res === 'boolean') {
216235
res ? next() : abort()
217236
} else if (promise) {
218237
res.then(function (ok) {
219238
ok ? next() : abort()
220-
}, abort)
239+
}, onError)
221240
}
222241
} else if (promise) {
223-
res.then(next, abort)
242+
res.then(next, onError)
224243
}
225244
}
226245

test/unit/specs/pipeline/activate.js

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
var testUtils = require('../util')
22
var test = testUtils.test
33
var assertCalls = testUtils.assertCalls
4+
var routerUtil = require('../../../../src/util')
45

56
describe('activate', function () {
67

8+
beforeEach(function () {
9+
spyOn(routerUtil, 'warn')
10+
})
11+
712
it('sync', function (done) {
813
test({
914
a: {
@@ -117,11 +122,35 @@ describe('activate', function () {
117122
// path changes during validation phase
118123
expect(router.history.currentPath).toBe('/a')
119124
setTimeout(function () {
120-
// but gets reset when validation fails
121-
expect(router.app.$el.textContent).toBe('')
122-
expect(router.history.currentPath).toBe('/')
125+
// activation error should continue transition
126+
expect(router.app.$el.textContent).toBe('A ')
127+
expect(router.history.currentPath).toBe('/a')
123128
done()
124129
}, wait * 2)
125130
})
126131
})
132+
133+
it('error', function (done) {
134+
test({
135+
a: {
136+
activate: function (transition) {
137+
throw new Error('oh no')
138+
}
139+
}
140+
}, function (router, calls, emitter) {
141+
var errorThrown = jasmine.createSpy()
142+
try {
143+
router.go('/a')
144+
} catch (e) {
145+
errorThrown()
146+
}
147+
expect(routerUtil.warn).toHaveBeenCalled()
148+
expect(errorThrown).toHaveBeenCalled()
149+
// should complete the transition despite error
150+
assertCalls(calls, ['a.activate'])
151+
expect(router.app.$el.textContent).toBe('A ')
152+
expect(router.history.currentPath).toBe('/a')
153+
done()
154+
})
155+
})
127156
})

test/unit/specs/pipeline/data.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
var testUtils = require('../util')
22
var test = testUtils.test
33
var assertCalls = testUtils.assertCalls
4+
var routerUtil = require('../../../../src/util')
45

56
describe('data', function () {
67

8+
beforeEach(function () {
9+
spyOn(routerUtil, 'warn')
10+
})
11+
712
it('initial load', function (done) {
813
test({
914
data: {
@@ -87,4 +92,26 @@ describe('data', function () {
8792
})
8893
})
8994

95+
it('promise error', function (done) {
96+
test({
97+
data: {
98+
data: function () {
99+
return new Promise(function (resolve, reject) {
100+
setTimeout(function () {
101+
reject()
102+
}, wait)
103+
})
104+
}
105+
}
106+
}, function (router, calls, emitter) {
107+
router.go('/data/hello')
108+
assertCalls(calls, ['data.data'])
109+
expect(router.app.$el.textContent).toBe('loading...')
110+
setTimeout(function () {
111+
// should complete the transition despite error
112+
expect(router.app.$el.textContent).toBe('')
113+
done()
114+
}, wait * 2)
115+
})
116+
})
90117
})

test/unit/specs/util.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ exports.test = function (configs, cb) {
2525
Object.keys(config).forEach(function (hook) {
2626
var fn = config[hook]
2727
config[hook] = function (transition) {
28+
var event = route + '.' + hook
29+
calls.push(event)
2830
var res = typeof fn === 'function'
2931
? fn(transition)
3032
: fn
31-
var event = route + '.' + hook
32-
calls.push(event)
3333
emitter.emit(event)
3434
return res
3535
}

0 commit comments

Comments
 (0)