await expect(router.push({ path: '/foo2' })).resolves.toBe(undefined)
expect(`No match found for location with path "/foo2"`).toHaveBeenWarned()
})
+
+ it('warns if next is called with the same location too many times', async () => {
+ let router = createRouter({
+ history: createMemoryHistory(),
+ routes: [
+ { path: '/', name: 'a', component },
+ { path: '/b', component },
+ ],
+ })
+
+ router.beforeEach(to => {
+ if (to.path === '/b') return '/b'
+ return
+ })
+
+ await router.push('/b').catch(() => {})
+ expect(
+ 'Detected an infinite redirection in a navigation guard when going from "/" to "/b"'
+ ).toHaveBeenWarned()
+ })
})
record && record.instances[name!],
to,
from,
- // TODO: could wrap in dev to check if the guard returns before
- // calling next with 3 or more arguments. This would help people
- // forgetting to remove the `next` argument
__DEV__ ? canOnlyBeCalledOnce(next, to, from) : next
)
)
if (failure) {
if (
isNavigationFailure(failure, ErrorTypes.NAVIGATION_GUARD_REDIRECT)
- )
- // preserve the original redirectedFrom if any
+ ) {
+ if (
+ __DEV__ &&
+ // we are redirecting to the same location we were already at
+ isSameRouteLocation(
+ stringifyQuery,
+ resolve(failure.to),
+ toLocation
+ ) &&
+ // and we have done it a couple of times
+ redirectedFrom &&
+ // @ts-ignore
+ (redirectedFrom._count = redirectedFrom._count
+ ? // @ts-ignore
+ redirectedFrom._count + 1
+ : 1) > 10
+ ) {
+ warn(
+ `Detected an infinite redirection in a navigation guard when going from "${from.fullPath}" to "${toLocation.fullPath}". Aborting to avoid a Stack Overflow. This will break in production if not fixed.`
+ )
+ return Promise.reject(
+ new Error('Infinite redirect in navigation guard')
+ )
+ }
+
return pushWithRedirect(
// keep options
assign(locationAsObject(failure.to), {
force,
replace,
}),
+ // preserve the original redirectedFrom if any
redirectedFrom || toLocation
)
+ }
} else {
// if we fail we don't finalize the navigation
failure = finalizeNavigation(