--- /dev/null
+import { createMemoryHistory, createRouter, RouterHistory } from '../src'
+import { tick } from './utils'
+
+const component = {}
+
+interface RouterHistory_Test extends RouterHistory {
+ changeURL(url: string): void
+}
+
+describe('hash history edge cases', () => {
+ it('correctly sets the url when it is manually changed but aborted with a redirect in guard', async () => {
+ const history = createMemoryHistory() as RouterHistory_Test
+ const router = createRouter({
+ history,
+ routes: [
+ { path: '/', component },
+ { path: '/foo', component },
+ ],
+ })
+
+ await router.push('/foo?step=1')
+ await router.push('/foo?step=2')
+ await router.push('/foo?step=3')
+ router.back()
+ await tick() // wait for router listener on history
+ expect(router.currentRoute.value.fullPath).toBe('/foo?step=2')
+
+ // force a redirect next time
+ const removeListener = router.beforeEach(to => {
+ if (to.path === '/') {
+ removeListener()
+ return '/foo?step=2'
+ }
+ return
+ })
+
+ // const spy = jest.spyOn(history, 'go')
+
+ history.changeURL('/')
+ await tick()
+ expect(router.currentRoute.value.fullPath).toBe('/foo?step=2')
+ expect(history.location).toBe('/foo?step=2')
+ // expect(spy).toHaveBeenCalledTimes(1)
+ // expect(spy).toHaveBeenCalledWith(-1)
+ })
+
+ it('correctly sets the url when it is manually changed but aborted with guard', async () => {
+ const history = createMemoryHistory() as RouterHistory_Test
+ const router = createRouter({
+ history,
+ routes: [
+ { path: '/', component },
+ { path: '/foo', component },
+ ],
+ })
+
+ await router.push('/foo?step=1')
+ await router.push('/foo?step=2')
+ await router.push('/foo?step=3')
+ router.back()
+ await tick() // wait for router listener on history
+ expect(router.currentRoute.value.fullPath).toBe('/foo?step=2')
+
+ // force a redirect next time
+ const removeListener = router.beforeEach(to => {
+ if (to.path === '/') {
+ removeListener()
+ return false
+ }
+
+ return
+ })
+
+ // const spy = jest.spyOn(history, 'go')
+
+ history.changeURL('/')
+ await tick()
+ expect(router.currentRoute.value.fullPath).toBe('/foo?step=2')
+ expect(history.location).toBe('/foo?step=2')
+ // expect(spy).toHaveBeenCalledTimes(1)
+ // expect(spy).toHaveBeenCalledWith(-1)
+ })
+})
RouteLocationOptions,
MatcherLocationRaw,
} from './types'
-import { RouterHistory, HistoryState } from './history/common'
+import { RouterHistory, HistoryState, NavigationType } from './history/common'
import {
ScrollPosition,
getSavedScrollPosition,
) &&
// and we have done it a couple of times
redirectedFrom &&
- // @ts-expect-error
+ // @ts-expect-error: added only in dev
(redirectedFrom._count = redirectedFrom._count
? // @ts-expect-error
redirectedFrom._count + 1
(error as NavigationRedirectError).to,
toLocation
// avoid an uncaught rejection, let push call triggerError
- ).catch(noop)
+ )
+ .then(failure => {
+ // manual change in hash history #916 ending up in the URL not
+ // changing but it was changed by the manual url change, so we
+ // need to manually change it ourselves
+ if (
+ isNavigationFailure(
+ failure,
+ ErrorTypes.NAVIGATION_ABORTED |
+ ErrorTypes.NAVIGATION_DUPLICATED
+ ) &&
+ !info.delta &&
+ info.type === NavigationType.pop
+ ) {
+ routerHistory.go(-1, false)
+ }
+ })
+ .catch(noop)
// avoid the then branch
return Promise.reject()
}
)
// revert the navigation
- if (failure && info.delta) routerHistory.go(-info.delta, false)
+ if (failure) {
+ if (info.delta) {
+ routerHistory.go(-info.delta, false)
+ } else if (
+ info.type === NavigationType.pop &&
+ isNavigationFailure(
+ failure,
+ ErrorTypes.NAVIGATION_ABORTED | ErrorTypes.NAVIGATION_DUPLICATED
+ )
+ ) {
+ // manual change in hash history #916
+ // it's like a push but lacks the information of the direction
+ routerHistory.go(-1, false)
+ }
+ }
triggerAfterEach(
toLocation as RouteLocationNormalizedLoaded,