Skip to content

Commit

Permalink
fix(router): preserve navigation options with redirects
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Apr 20, 2020
1 parent 0586394 commit 9732758
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 29 deletions.
19 changes: 2 additions & 17 deletions __tests__/initialNavigation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { JSDOM } from 'jsdom'
import { createRouter, createWebHistory, Router } from '../src'
import { createDom, components } from './utils'
import { createRouter, createWebHistory } from '../src'
import { createDom, components, nextNavigation } from './utils'
import { RouteRecordRaw } from '../src/types'

// override the value of isBrowser because the variable is created before JSDOM
Expand Down Expand Up @@ -40,21 +40,6 @@ describe('Initial Navigation', () => {
return { history, router }
}

function nextNavigation(router: Router) {
return new Promise((resolve, reject) => {
let removeAfter = router.afterEach((_to, _from, failure) => {
removeAfter()
removeError()
resolve(failure)
})
let removeError = router.onError(err => {
removeAfter()
removeError()
reject(err)
})
})
}

beforeAll(() => {
dom = createDom()
})
Expand Down
20 changes: 19 additions & 1 deletion __tests__/router.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fakePromise from 'faked-promise'
import { createRouter, createMemoryHistory, createWebHistory } from '../src'
import { NavigationFailureType } from '../src/errors'
import { createDom, components, tick } from './utils'
import { createDom, components, tick, nextNavigation } from './utils'
import {
RouteRecordRaw,
RouteLocationRaw,
Expand Down Expand Up @@ -504,6 +504,24 @@ describe('Router', () => {
})
})

it('keeps original replace if redirect', async () => {
const history = createMemoryHistory()
const router = createRouter({ history, routes })
await router.push('/search')

await expect(router.replace('/to-foo')).resolves.toEqual(undefined)
expect(router.currentRoute.value).toMatchObject({
path: '/foo',
redirectedFrom: expect.objectContaining({ path: '/to-foo' }),
})

history.go(-1)
await nextNavigation(router)
expect(router.currentRoute.value).not.toMatchObject({
path: '/search',
})
})

it('can pass on query and hash when redirecting', async () => {
const history = createMemoryHistory()
const router = createRouter({ history, routes })
Expand Down
17 changes: 16 additions & 1 deletion __tests__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
RouteRecordName,
} from '../src/types'
import { h, resolveComponent, ComponentOptions } from 'vue'
import { RouterOptions, createWebHistory, createRouter } from '../src'
import { RouterOptions, createWebHistory, createRouter, Router } from '../src'

export const tick = (time?: number) =>
new Promise(resolve => {
Expand All @@ -24,6 +24,21 @@ export async function ticks(n: number) {
}
}

export function nextNavigation(router: Router) {
return new Promise((resolve, reject) => {
let removeAfter = router.afterEach((_to, _from, failure) => {
removeAfter()
removeError()
resolve(failure)
})
let removeError = router.onError(err => {
removeAfter()
removeError()
reject(err)
})
})
}

export interface RouteRecordViewLoose
extends Pick<
RouteRecordMultipleViews,
Expand Down
26 changes: 17 additions & 9 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,33 +229,42 @@ export function createRouter({
}
}

function locationAsObject(
to: RouteLocationRaw | RouteLocationNormalized
): Exclude<RouteLocationRaw, string> | RouteLocationNormalized {
return typeof to === 'string' ? { path: to } : to
}

function push(to: RouteLocationRaw | RouteLocation) {
return pushWithRedirect(to, undefined)
return pushWithRedirect(to)
}

function replace(to: RouteLocationRaw | RouteLocationNormalized) {
const location = typeof to === 'string' ? { path: to } : to
return push({ ...location, replace: true })
return push({ ...locationAsObject(to), replace: true })
}

async function pushWithRedirect(
to: RouteLocationRaw | RouteLocation,
redirectedFrom: RouteLocation | undefined
redirectedFrom?: RouteLocation
): Promise<NavigationFailure | void> {
const targetLocation: RouteLocation = (pendingLocation = resolve(to))
const from = currentRoute.value
const data: HistoryState | undefined = (to as any).state
// @ts-ignore: no need to check the string as force do not exist on a string
const force: boolean | undefined = to.force
const force: boolean | undefined = (to as any).force
const replace: boolean | undefined = (to as any).replace === true

if (!force && isSameRouteLocation(from, targetLocation)) return

const lastMatched =
targetLocation.matched[targetLocation.matched.length - 1]
if (lastMatched && 'redirect' in lastMatched) {
const { redirect } = lastMatched
// transform it into an object to pass the original RouteLocaleOptions
let newTargetLocation = locationAsObject(
typeof redirect === 'function' ? redirect(targetLocation) : redirect
)
return pushWithRedirect(
typeof redirect === 'function' ? redirect(targetLocation) : redirect,
{ ...newTargetLocation, state: data, force, replace },
// keep original redirectedFrom if it exists
redirectedFrom || targetLocation
)
Expand Down Expand Up @@ -301,8 +310,7 @@ export function createRouter({
toLocation as RouteLocationNormalizedLoaded,
from,
true,
// RouteLocationNormalized will give undefined
(to as RouteLocationRaw).replace === true,
replace,
data
)

Expand Down
5 changes: 4 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ export interface _RouteRecordBase {
| boolean
| Record<string, any>
| ((to: RouteLocationNormalized) => Record<string, any>)
// TODO: beforeEnter has no effect with redirect, move and test
/**
* Before Enter guard specific to this record. Note `beforeEnter` has no
* effect if the record has a `redirect` property.
*/
beforeEnter?:
| NavigationGuardWithThis<undefined>
| NavigationGuardWithThis<undefined>[]
Expand Down

0 comments on commit 9732758

Please sign in to comment.