expect(spy).toHaveBeenCalledTimes(1)
})
- it.skip('does not call beforeRouteEnter if we were already on the page', () => {})
+ it('does not call beforeRouteEnter if we were already on the page', async () => {
+ const router = createRouter({ routes })
+ beforeRouteEnter.mockImplementation((to, from, next) => {
+ next()
+ })
+ await router.push('/guard/one')
+ expect(beforeRouteEnter).toHaveBeenCalledTimes(1)
+ await router[navigationMethod]('/guard/one')
+ expect(beforeRouteEnter).toHaveBeenCalledTimes(1)
+ })
it('waits before navigating', async () => {
const [promise, resolve] = fakePromise()
expect(spy).toHaveBeenCalledTimes(1)
})
- it.skip('does not call beforeEach guard if we were already on the page', () => {})
+ it('does not call beforeEach guard if we were already on the page', async () => {
+ const spy = jest.fn()
+ const router = createRouter({ routes })
+ await router.push('/foo')
+ router.beforeEach(spy)
+ spy.mockImplementationOnce((to, from, next) => {
+ next()
+ })
+ await router[navigationMethod]('/foo')
+ expect(spy).not.toHaveBeenCalled()
+ })
it('waits before navigating', async () => {
const [promise, resolve] = fakePromise()
expect(beforeEnter).toHaveBeenCalledTimes(1)
})
- it.skip('calls beforeEnter guards on replace', () => {})
- it.skip('does not call beforeEnter guard if we were already on the page', () => {})
+ it('does not call beforeEnter guard if we were already on the page', async () => {
+ const router = createRouter({ routes })
+ beforeEnter.mockImplementation((to, from, next) => {
+ next()
+ })
+ await router.push('/guard/one')
+ expect(beforeEnter).toHaveBeenCalledTimes(1)
+ await router[navigationMethod]('/guard/one')
+ expect(beforeEnter).toHaveBeenCalledTimes(1)
+ })
it('waits before navigating', async () => {
const [promise, resolve] = fakePromise()
// @ts-ignore
global.window = dom.window
+ // @ts-ignore
+ global.location = dom.window.location
+ // @ts-ignore
+ global.document = dom.window.document
return dom
}
await guard()
}
- // check global guards first
- guards = []
- for (const guard of this.beforeGuards) {
- guards.push(guardToPromiseFn(guard, to, from))
- }
+ // check global guards beforeEach
+ // avoid if we are not changing route
+ // TODO: trigger on child navigation
+ if (last(to.matched) !== last(from.matched)) {
+ guards = []
+ for (const guard of this.beforeGuards) {
+ guards.push(guardToPromiseFn(guard, to, from))
+ }
- // console.log('Guarding against', guards.length, 'guards')
- for (const guard of guards) {
- await guard()
+ // console.log('Guarding against', guards.length, 'guards')
+ for (const guard of guards) {
+ await guard()
+ }
}
// check the route beforeEnter
// TODO: check children. Should we also check reused routes guards
guards = []
for (const record of to.matched) {
- if (record.beforeEnter)
+ // do not trigger beforeEnter on reused views
+ if (record.beforeEnter && from.matched.indexOf(record) < 0)
guards.push(guardToPromiseFn(record.beforeEnter, to, from))
}
guards = []
// TODO: is it okay to resolve all matched component or should we do it in order
await Promise.all(
- to.matched.map(async ({ component }) => {
+ to.matched.map(async record => {
// TODO: cache async routes per record
+ const { component } = record
const resolvedComponent = await (typeof component === 'function'
? component()
: component)
- if (resolvedComponent.beforeRouteEnter) {
+ if (
+ resolvedComponent.beforeRouteEnter &&
+ from.matched.indexOf(record)
+ ) {
// TODO: handle the next callback
guards.push(
guardToPromiseFn(resolvedComponent.beforeRouteEnter, to, from)
guard(to, from, next)
})
}
+
+function last<T>(array: T[]): T {
+ return array[array.length - 1]
+}