]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
fix(router): prevent duplicated navigation on aliases
authorEduardo San Martin Morote <posva13@gmail.com>
Sat, 14 Mar 2020 23:31:35 +0000 (00:31 +0100)
committerEduardo San Martin Morote <posva13@gmail.com>
Sat, 14 Mar 2020 23:31:35 +0000 (00:31 +0100)
__tests__/router.spec.ts
src/router.ts

index 12c31b390dc31909ade7c5c53a483c7d47e0527f..2998d1017a0fd2e3f2be376675defac394932885 100644 (file)
@@ -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)
index e80caf5f3cc19f104a57cc35f559b1972750c125..2701b75f4ccd0e7a72c08c04db38a3945bc6e2b2 100644 (file)
@@ -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<RouteLocationNormalized>,
-  b: Immutable<RouteLocationNormalized>
+// function isSameLocation(
+//   a: Immutable<RouteLocationNormalized>,
+//   b: Immutable<RouteLocationNormalized>
+// ): 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)
   )
 }