]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat(guards): allow guards to return a value instead of calling next (#343)
authorEduardo San Martin Morote <posva@users.noreply.github.com>
Tue, 21 Jul 2020 12:39:29 +0000 (14:39 +0200)
committerGitHub <noreply@github.com>
Tue, 21 Jul 2020 12:39:29 +0000 (14:39 +0200)
__tests__/guards/guardToPromiseFn.spec.ts
src/navigationGuards.ts

index 7648737b34e3d5f0e66a1462fca47abc40d00f87..c593c4d61642c95ffcd5de5e8808efa273ff45cb 100644 (file)
@@ -110,4 +110,126 @@ describe('guardToPromiseFn', () => {
       expect(err).toBe(error)
     }
   })
+
+  describe('no next argument', () => {
+    it('rejects if returns false', async () => {
+      expect.assertions(1)
+      try {
+        await guardToPromiseFn((to, from) => false, to, from)()
+      } catch (err) {
+        expect(err).toMatchObject({
+          from,
+          to,
+          type: ErrorTypes.NAVIGATION_ABORTED,
+        })
+      }
+    })
+
+    it('resolves no value is returned', async () => {
+      await expect(
+        guardToPromiseFn((to, from) => {}, to, from)()
+      ).resolves.toEqual(undefined)
+    })
+
+    it('resolves if true is returned', async () => {
+      await expect(
+        guardToPromiseFn((to, from) => true, to, from)()
+      ).resolves.toEqual(undefined)
+    })
+
+    it('rejects if false is returned', async () => {
+      expect.assertions(1)
+      try {
+        await guardToPromiseFn((to, from) => false, to, from)()
+      } catch (err) {
+        expect(err).toMatchObject({
+          from,
+          to,
+          type: ErrorTypes.NAVIGATION_ABORTED,
+        })
+      }
+    })
+
+    it('rejects if async false is returned', async () => {
+      expect.assertions(1)
+      try {
+        await guardToPromiseFn(async (to, from) => false, to, from)()
+      } catch (err) {
+        expect(err).toMatchObject({
+          from,
+          to,
+          type: ErrorTypes.NAVIGATION_ABORTED,
+        })
+      }
+    })
+
+    it('rejects if a string location is returned', async () => {
+      expect.assertions(1)
+      try {
+        await guardToPromiseFn((to, from) => '/new', to, from)()
+      } catch (err) {
+        expect(err).toMatchObject({
+          from: to,
+          to: '/new',
+          type: ErrorTypes.NAVIGATION_GUARD_REDIRECT,
+        })
+      }
+    })
+
+    it('rejects if an object location is returned', async () => {
+      expect.assertions(1)
+      let redirectTo = { path: '/new' }
+      try {
+        await guardToPromiseFn((to, from) => redirectTo, to, from)()
+      } catch (err) {
+        expect(err).toMatchObject({
+          from: to,
+          to: redirectTo,
+          type: ErrorTypes.NAVIGATION_GUARD_REDIRECT,
+        })
+      }
+    })
+
+    it('rejects if an error is returned', async () => {
+      expect.assertions(1)
+      let error = new Error('nope')
+      try {
+        await guardToPromiseFn((to, from) => error, to, from)()
+      } catch (err) {
+        expect(err).toBe(error)
+      }
+    })
+
+    it('rejects if guard rejects a Promise', async () => {
+      expect.assertions(1)
+      let error = new Error('nope')
+      try {
+        await guardToPromiseFn(
+          async (to, from) => {
+            throw error
+          },
+          to,
+          from
+        )()
+      } catch (err) {
+        expect(err).toBe(error)
+      }
+    })
+
+    it('rejects if guard throws an error', async () => {
+      expect.assertions(1)
+      let error = new Error('nope')
+      try {
+        await guardToPromiseFn(
+          (to, from) => {
+            throw error
+          },
+          to,
+          from
+        )()
+      } catch (err) {
+        expect(err).toBe(error)
+      }
+    })
+  })
 })
index 74a734f7b3720eafe161b3197de4aea505eca982..2f09b2cfafa14d911c168d14e5f98d5eaf28d5ab 100644 (file)
@@ -152,14 +152,17 @@ export function guardToPromiseFn(
       }
 
       // wrapping with Promise.resolve allows it to work with both async and sync guards
-      Promise.resolve(
+      let guardCall = Promise.resolve(
         guard.call(
           record && record.instances[name!],
           to,
           from,
           __DEV__ ? canOnlyBeCalledOnce(next, to, from) : next
         )
-      ).catch(err => reject(err))
+      )
+
+      if (guard.length < 3) guardCall.then(next)
+      guardCall.catch(err => reject(err))
     })
 }