From ec592e48955f5a77561f963bef4e8e704d82ac38 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 1 Jul 2020 17:49:12 +0200 Subject: [PATCH] feat(guards): allow guards to return a value instead of calling next --- __tests__/guards/guardToPromiseFn.spec.ts | 122 ++++++++++++++++++++++ src/navigationGuards.ts | 7 +- 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/__tests__/guards/guardToPromiseFn.spec.ts b/__tests__/guards/guardToPromiseFn.spec.ts index 7648737b3..c593c4d61 100644 --- a/__tests__/guards/guardToPromiseFn.spec.ts +++ b/__tests__/guards/guardToPromiseFn.spec.ts @@ -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) + } + }) + }) }) diff --git a/src/navigationGuards.ts b/src/navigationGuards.ts index c711d830b..0df6acd2b 100644 --- a/src/navigationGuards.ts +++ b/src/navigationGuards.ts @@ -128,14 +128,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( instance, to, from, __DEV__ ? canOnlyBeCalledOnce(next, to, from) : next ) - ).catch(err => reject(err)) + ) + + if (guard.length < 3) guardCall.then(next) + guardCall.catch(err => reject(err)) }) }