]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat(warn): warn if next was called multiple times
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 6 May 2020 09:29:38 +0000 (11:29 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 6 May 2020 09:29:38 +0000 (11:29 +0200)
__tests__/warnings.spec.ts
src/navigationGuards.ts

index 7b54705b5d39b627cb6db94c697cbce2dfe85664..12f5b455af7bb25a4288302556255a705718c760 100644 (file)
@@ -90,4 +90,27 @@ describe('warnings', () => {
       'Alias "/:p/:c" and the original record: "/:p/c" should have the exact same param named "c"'
     ).toHaveBeenWarned()
   })
+
+  it('warns if next is called multiple times in one navigation guard', done => {
+    expect.assertions(3)
+    let router = createRouter({
+      history: createMemoryHistory(),
+      routes: [
+        { path: '/', name: 'a', component },
+        { path: '/b', name: 'a', component },
+      ],
+    })
+
+    router.beforeEach((to, from, next) => {
+      next()
+      expect('').not.toHaveBeenWarned()
+      next()
+      expect('called more than once').toHaveBeenWarnedTimes(1)
+      next()
+      expect('called more than once').toHaveBeenWarnedTimes(1)
+      done()
+    })
+
+    router.push('/b')
+  })
 })
index fba11dbe6079c741954a530adfcaba5ff9194495..d906e36504e0846b495d05138807cff6b4951667 100644 (file)
@@ -127,12 +127,32 @@ export function guardToPromiseFn(
       }
 
       // wrapping with Promise.resolve allows it to work with both async and sync guards
-      Promise.resolve(guard.call(instance, to, from, next)).catch(err =>
-        reject(err)
-      )
+      Promise.resolve(
+        guard.call(
+          instance,
+          to,
+          from,
+          __DEV__ ? canOnlyBeCalledOnce(next, to, from) : next
+        )
+      ).catch(err => reject(err))
     })
 }
 
+function canOnlyBeCalledOnce(
+  next: NavigationGuardCallback,
+  to: RouteLocationNormalized,
+  from: RouteLocationNormalized
+): NavigationGuardCallback {
+  let called = 0
+  return function () {
+    if (called++ === 1)
+      warn(
+        `The "next" callback was called more than once in one navigation guard when going from "${from.fullPath}" to "${to.fullPath}". It should be called exactly one time in each navigation guard. This will fail in production.`
+      )
+    if (called === 1) next.apply(null, arguments as any)
+  }
+}
+
 type GuardType = 'beforeRouteEnter' | 'beforeRouteUpdate' | 'beforeRouteLeave'
 
 export function extractComponentsGuards(