From: Eduardo San Martin Morote Date: Sat, 14 Mar 2020 23:31:35 +0000 (+0100) Subject: fix(router): prevent duplicated navigation on aliases X-Git-Tag: v4.0.0-alpha.4~64 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e82558684c0b6b688065032df65604b2c245d395;p=thirdparty%2Fvuejs%2Frouter.git fix(router): prevent duplicated navigation on aliases --- diff --git a/__tests__/router.spec.ts b/__tests__/router.spec.ts index 12c31b39..2998d101 100644 --- a/__tests__/router.spec.ts +++ b/__tests__/router.spec.ts @@ -34,6 +34,26 @@ const routes: RouteRecord[] = [ hash: to.hash + '-2', }), }, + { + path: '/basic', + alias: '/basic-alias', + component: components.Foo, + }, + { + path: '/aliases', + alias: ['/aliases1', '/aliases2'], + component: components.Nested, + children: [ + { + path: 'one', + alias: ['o', 'o2'], + component: components.Foo, + children: [ + { path: 'two', alias: ['t', 't2'], component: components.Bar }, + ], + }, + ], + }, ] async function newRouter({ history }: { history?: RouterHistory } = {}) { @@ -111,6 +131,55 @@ describe('Router', () => { ) }) + // FIXME: + it.skip('navigates if the location does not exist', async () => { + const { router } = await newRouter() + const spy = jest.fn((to, from, next) => next()) + router.beforeEach(spy) + await router.push('/idontexist') + spy.mockReset() + await router.push('/me-neither') + expect(spy).not.toHaveBeenCalled() + }) + + describe('alias', () => { + it('does not navigate to alias if already on original record', async () => { + const { router } = await newRouter() + const spy = jest.fn((to, from, next) => next()) + router.beforeEach(spy) + await router.push('/basic') + spy.mockReset() + await router.push('/basic-alias') + expect(spy).not.toHaveBeenCalled() + }) + + it('does not navigate to alias with children if already on original record', async () => { + const { router } = await newRouter() + const spy = jest.fn((to, from, next) => next()) + router.beforeEach(spy) + await router.push('/aliases') + spy.mockReset() + await router.push('/aliases1') + expect(spy).not.toHaveBeenCalled() + await router.push('/aliases2') + expect(spy).not.toHaveBeenCalled() + }) + + it('does not navigate to child alias if already on original record', async () => { + const { router } = await newRouter() + const spy = jest.fn((to, from, next) => next()) + router.beforeEach(spy) + await router.push('/aliases/one') + spy.mockReset() + await router.push('/aliases1/one') + expect(spy).not.toHaveBeenCalled() + await router.push('/aliases2/one') + expect(spy).not.toHaveBeenCalled() + await router.push('/aliases2/o') + expect(spy).not.toHaveBeenCalled() + }) + }) + describe('navigation', () => { async function checkNavigationCancelledOnPush( target?: RouteLocation | false | ((vm: any) => void) diff --git a/src/router.ts b/src/router.ts index e80caf5f..2701b75f 100644 --- a/src/router.ts +++ b/src/router.ts @@ -26,9 +26,9 @@ import { import { extractComponentsGuards, guardToPromiseFn, - isSameLocationObject, applyToParams, isSameRouteRecord, + isSameLocationObject, } from './utils' import { useCallbacks } from './utils/callbacks' import { encodeParam, decode } from './utils/encoding' @@ -199,7 +199,7 @@ export function createRouter({ const force: boolean | undefined = to.force // TODO: should we throw an error as the navigation was aborted - if (!force && isSameLocation(from, toLocation)) return from + if (!force && isSameRouteLocation(from, toLocation)) return from toLocation.redirectedFrom = redirectedFrom @@ -543,16 +543,31 @@ function extractChangingRecords( return [leavingRecords, updatingRecords, enteringRecords] } -function isSameLocation( - a: Immutable, - b: Immutable +// function isSameLocation( +// a: Immutable, +// b: Immutable +// ): boolean { +// return ( +// a.name === b.name && +// a.path === b.path && +// a.hash === b.hash && +// isSameLocationObject(a.query, b.query) && +// a.matched.length === b.matched.length && +// a.matched.every((record, i) => isSameRouteRecord(record, b.matched[i])) +// ) +// } + +function isSameRouteLocation( + a: RouteLocationNormalized, + b: RouteLocationNormalized ): boolean { + let aLastIndex = a.matched.length - 1 + let bLastIndex = b.matched.length - 1 + return ( - a.name === b.name && - a.path === b.path && - a.hash === b.hash && - isSameLocationObject(a.query, b.query) && - a.matched.length === b.matched.length && - a.matched.every((record, i) => isSameRouteRecord(record, b.matched[i])) + aLastIndex > -1 && + aLastIndex === bLastIndex && + isSameRouteRecord(a.matched[aLastIndex], b.matched[bLastIndex]) && + isSameLocationObject(a.params, b.params) ) }