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
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()
})
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,
})
})
+ 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 })
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 => {
}
}
+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,
}
}
+ 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
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
)
toLocation as RouteLocationNormalizedLoaded,
from,
true,
- // RouteLocationNormalized will give undefined
- (to as RouteLocationRaw).replace === true,
+ replace,
data
)
| 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>[]