Skip to content

Commit

Permalink
feat: return a promise with push and replace (#2862)
Browse files Browse the repository at this point in the history
Closes #1769 

* fix: push/replace return promise close(#1769)

* feat: organize tests and add overloading

* fix:  text names

* feat: Add promise rejection
  • Loading branch information
Mighty683 authored and posva committed Aug 1, 2019
1 parent f00f1fc commit d907a13
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 40 deletions.
18 changes: 16 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,25 @@ export default class VueRouter {
}

push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.history.push(location, onComplete, onAbort)
// $flow-disable-line
if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
this.history.push(location, resolve, reject)
})
} else {
this.history.push(location, onComplete, onAbort)
}
}

replace (location: RawLocation, onComplete?: Function, onAbort?: Function) {
this.history.replace(location, onComplete, onAbort)
// $flow-disable-line
if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
return new Promise((resolve, reject) => {
this.history.replace(location, resolve, reject)
})
} else {
this.history.replace(location, onComplete, onAbort)
}
}

go (n: number) {
Expand Down
101 changes: 76 additions & 25 deletions test/unit/specs/api.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('router.addRoutes', () => {
})
})

describe('router.push/replace callbacks', () => {
describe('router.push/replace', () => {
let calls = []
let router, spy1, spy2

Expand Down Expand Up @@ -151,38 +151,89 @@ describe('router.push/replace callbacks', () => {
}, 1)
})
})
describe('callbacks', () => {
it('push does not return a Promise when a callback is passed', done => {
expect(router.push('/foo', done)).toEqual(undefined)
})

it('push complete', done => {
router.push('/foo', () => {
expect(calls).toEqual([1, 2, 3, 4])
done()
it('push complete', done => {
router.push('/foo', () => {
expect(calls).toEqual([1, 2, 3, 4])
done()
})
})
})

it('push abort', done => {
router.push('/foo', spy1, spy2)
router.push('/bar', () => {
expect(calls).toEqual([1, 1, 2, 2])
expect(spy1).not.toHaveBeenCalled()
expect(spy2).toHaveBeenCalled()
done()
it('push abort', done => {
router.push('/foo', spy1, spy2)
router.push('/bar', () => {
expect(calls).toEqual([1, 1, 2, 2])
expect(spy1).not.toHaveBeenCalled()
expect(spy2).toHaveBeenCalled()
done()
})
})
})

it('replace complete', done => {
router.replace('/foo', () => {
expect(calls).toEqual([1, 2, 3, 4])
done()
it('replace does not return a Promise when a callback is passed', done => {
expect(router.replace('/foo', done)).toEqual(undefined)
})

it('replace complete', done => {
router.replace('/foo', () => {
expect(calls).toEqual([1, 2, 3, 4])
done()
})
})

it('replace abort', done => {
router.replace('/foo', spy1, spy2)
router.replace('/bar', () => {
expect(calls).toEqual([1, 1, 2, 2])
expect(spy1).not.toHaveBeenCalled()
expect(spy2).toHaveBeenCalled()
done()
})
})
})

it('replace abort', done => {
router.replace('/foo', spy1, spy2)
router.replace('/bar', () => {
expect(calls).toEqual([1, 1, 2, 2])
expect(spy1).not.toHaveBeenCalled()
expect(spy2).toHaveBeenCalled()
done()
describe('promises', () => {
it('push complete', done => {
router.push('/foo')
.then(spy1)
.finally(() => {
expect(calls).toEqual([1, 2, 3, 4])
expect(spy1).toHaveBeenCalledWith(router.currentRoute)
done()
})
})

it('push abort', done => {
router.push('/foo').catch(spy2)
router.push('/bar').finally(() => {
expect(calls).toEqual([1, 1, 2, 2])
expect(spy1).not.toHaveBeenCalled()
expect(spy2).toHaveBeenCalled()
done()
})
})

it('replace complete', done => {
router.replace('/foo')
.then(spy1)
.finally(() => {
expect(calls).toEqual([1, 2, 3, 4])
expect(spy1).toHaveBeenCalledWith(router.currentRoute)
done()
})
})

it('replace abort', done => {
router.replace('/foo').catch(spy2)
router.replace('/bar').finally(() => {
expect(calls).toEqual([1, 1, 2, 2])
expect(spy1).not.toHaveBeenCalled()
expect(spy2).toHaveBeenCalled()
done()
})
})
})
})
Expand Down
36 changes: 23 additions & 13 deletions test/unit/specs/error-handling.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,47 @@ import VueRouter from '../../../src/index'
Vue.use(VueRouter)

describe('error handling', () => {
it('onReady errors', () => {
it('onReady errors', done => {
const router = new VueRouter()
const err = new Error('foo')
router.beforeEach(() => { throw err })
router.onError(() => {})

const onReady = jasmine.createSpy('ready')
const onError = jasmine.createSpy('error')
const onPromiseReject = jasmine.createSpy('promise reject')
router.onReady(onReady, onError)

router.push('/')

expect(onReady).not.toHaveBeenCalled()
expect(onError).toHaveBeenCalledWith(err)
router.push('/').catch(onPromiseReject).finally(() => {
expect(onReady).not.toHaveBeenCalled()
expect(onError).toHaveBeenCalledWith(err)
expect(onPromiseReject).toHaveBeenCalled()
done()
})
})

it('navigation errors', () => {
it('navigation errors', done => {
const router = new VueRouter()
const err = new Error('foo')
const spy = jasmine.createSpy('error')
const spy1 = jasmine.createSpy('promise reject')
router.onError(spy)

router.push('/')
router.beforeEach(() => { throw err })

router.push('/foo')
expect(spy).toHaveBeenCalledWith(err)
router.push('/foo').catch(spy1).finally(() => {
expect(spy).toHaveBeenCalledWith(err)
expect(spy1).toHaveBeenCalled()
done()
})
})

it('async component errors', () => {
it('async component errors', done => {
const err = new Error('foo')
const spy1 = jasmine.createSpy('error')
const spy2 = jasmine.createSpy('errpr')
const spy3 = jasmine.createSpy('promise reject')
const Comp = () => { throw err }
const router = new VueRouter({
routes: [
Expand All @@ -47,9 +55,11 @@ describe('error handling', () => {
router.onError(spy1)
router.onReady(() => {}, spy2)

router.push('/')

expect(spy1).toHaveBeenCalledWith(err)
expect(spy2).toHaveBeenCalledWith(err)
router.push('/').catch(spy3).finally(() => {
expect(spy1).toHaveBeenCalledWith(err)
expect(spy2).toHaveBeenCalledWith(err)
expect(spy3).toHaveBeenCalled()
done()
})
})
})
2 changes: 2 additions & 0 deletions types/router.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export declare class VueRouter {
afterEach (hook: (to: Route, from: Route) => any): Function;
push (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void;
replace (location: RawLocation, onComplete?: Function, onAbort?: ErrorHandler): void;
push (location: RawLocation): Promise<Route>;
replace (location: RawLocation): Promise<Route>;
go (n: number): void;
back (): void;
forward (): void;
Expand Down

0 comments on commit d907a13

Please sign in to comment.