Skip to content

Commit 47cd7b9

Browse files
committed
fix(warn): correctly warn against unused next
1 parent e8fb3fe commit 47cd7b9

File tree

2 files changed

+73
-18
lines changed

2 files changed

+73
-18
lines changed

__tests__/guards/guardToPromiseFn.spec.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,53 @@ describe('guardToPromiseFn', () => {
229229
it('warns if guard resolves without calling next', async () => {
230230
expect.assertions(2)
231231
await expect(
232-
guardToPromiseFn((to, from, next) => false, to, from)()
232+
guardToPromiseFn(
233+
async (to, from, next) => {
234+
// oops not called next
235+
},
236+
to,
237+
from
238+
)()
239+
).rejects.toThrowError()
240+
expect('callback was never called').toHaveBeenWarned()
241+
})
242+
243+
it('does not warn if guard rejects without calling next', async () => {
244+
expect.assertions(2)
245+
await expect(
246+
guardToPromiseFn(
247+
async (to, from, next) => {
248+
// oops not called next
249+
throw new Error('nope')
250+
},
251+
to,
252+
from
253+
)()
233254
).rejects.toThrowError()
255+
expect('callback was never called').not.toHaveBeenWarned()
256+
})
234257

258+
it('warns if guard returns without calling next', async () => {
259+
expect.assertions(2)
260+
await expect(
261+
guardToPromiseFn((to, from, next) => false, to, from)()
262+
).rejects.toThrowError()
235263
expect('callback was never called').toHaveBeenWarned()
236264
})
265+
266+
it('does not warn if guard returns undefined', async () => {
267+
expect.assertions(2)
268+
await expect(
269+
guardToPromiseFn(
270+
(to, from, next) => {
271+
// there could be a callback somewhere
272+
setTimeout(next, 10)
273+
},
274+
to,
275+
from
276+
)()
277+
).resolves.toEqual(undefined)
278+
279+
expect('callback was never called').not.toHaveBeenWarned()
280+
})
237281
})

src/navigationGuards.ts

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -159,27 +159,38 @@ export function guardToPromiseFn(
159159
}
160160

161161
// wrapping with Promise.resolve allows it to work with both async and sync guards
162-
let guardCall = Promise.resolve(
163-
guard.call(
164-
record && record.instances[name!],
165-
to,
166-
from,
167-
__DEV__ ? canOnlyBeCalledOnce(next, to, from) : next
168-
)
162+
const guardReturn = guard.call(
163+
record && record.instances[name!],
164+
to,
165+
from,
166+
__DEV__ ? canOnlyBeCalledOnce(next, to, from) : next
169167
)
168+
let guardCall = Promise.resolve(guardReturn)
170169

171170
if (guard.length < 3) guardCall = guardCall.then(next)
172-
if (__DEV__ && guard.length > 2)
173-
guardCall = guardCall.then(() => {
171+
if (__DEV__ && guard.length > 2) {
172+
const message = `The "next" callback was never called inside of ${
173+
guard.name ? '"' + guard.name + '"' : ''
174+
}:\n${guard.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`
175+
if (typeof guardReturn === 'object' && 'then' in guardReturn) {
176+
guardCall = guardCall.then(resolvedValue => {
177+
// @ts-ignore: _called is added at canOnlyBeCalledOnce
178+
if (!next._called) {
179+
warn(message)
180+
return Promise.reject(new Error('Invalid navigation guard'))
181+
}
182+
return resolvedValue
183+
})
184+
// TODO: test me!
185+
} else if (guardReturn !== undefined) {
174186
// @ts-ignore: _called is added at canOnlyBeCalledOnce
175-
if (!next._called)
176-
warn(
177-
`The "next" callback was never called inside of ${
178-
guard.name ? '"' + guard.name + '"' : ''
179-
}:\n${guard.toString()}\n. If you are returning a value instead of calling "next", make sure to remove the "next" parameter from your function.`
180-
)
181-
return Promise.reject(new Error('Invalid navigation guard'))
182-
})
187+
if (!next._called) {
188+
warn(message)
189+
reject(new Error('Invalid navigation guard'))
190+
return
191+
}
192+
}
193+
}
183194
guardCall.catch(err => reject(err))
184195
})
185196
}

0 commit comments

Comments
 (0)