From 3c442228ff746165fd823687a2661a24edd08820 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 26 Aug 2021 10:40:48 -0400 Subject: [PATCH] fix(vue): router guards are now fired correctly when written in a component (#23821) resolves #23820 --- packages/vue-router/src/viewStacks.ts | 9 ++++ .../vue/src/components/IonRouterOutlet.ts | 2 +- .../vue/test-app/tests/unit/routing.spec.ts | 48 +++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/packages/vue-router/src/viewStacks.ts b/packages/vue-router/src/viewStacks.ts index 1ef105125d..7fd5c331da 100644 --- a/packages/vue-router/src/viewStacks.ts +++ b/packages/vue-router/src/viewStacks.ts @@ -20,6 +20,14 @@ export const createViewStacks = (router: Router) => { const registerIonPage = (viewItem: ViewItem, ionPage: HTMLElement) => { viewItem.ionPageElement = ionPage; viewItem.ionRoute = true; + + /** + * This is needed otherwise Vue Router + * will not consider this component mounted + * and will not run route guards that + * are written in the component. + */ + viewItem.matchedRoute.instances = { default: viewItem.vueComponentRef.value }; } const findViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number, useDeprecatedRouteSetup: boolean = false) => { @@ -202,6 +210,7 @@ export const createViewStacks = (router: Router) => { viewItem.mount = false; viewItem.ionPageElement = undefined; viewItem.ionRoute = false; + viewItem.matchedRoute.instances = {}; } } diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index 4eea4a8915..ffbad4d255 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -63,7 +63,7 @@ export const IonRouterOutlet = defineComponent({ * page/1 to page/2 would not cause this callback * to fire since the matchedRouteRef was the same. */ - watch([route, matchedRouteRef], ([currentRoute, currentMatchedRouteRef], [_, previousMatchedRouteRef]) => { + watch(() => [route, matchedRouteRef.value], ([currentRoute, currentMatchedRouteRef], [_, previousMatchedRouteRef]) => { /** * If the matched route ref has changed, * then we need to set up a new view item. diff --git a/packages/vue/test-app/tests/unit/routing.spec.ts b/packages/vue/test-app/tests/unit/routing.spec.ts index 0a14f980aa..ae510fc22e 100644 --- a/packages/vue/test-app/tests/unit/routing.spec.ts +++ b/packages/vue/test-app/tests/unit/routing.spec.ts @@ -393,4 +393,52 @@ describe('Routing', () => { expect(page.props()).toEqual({ id: '2' }); }); + + it('should fire guard written in a component', async () => { + const beforeRouteEnterSpy = jest.fn(); + const beforeRouteLeaveSpy = jest.fn(); + const Page = { + beforeRouteEnter() { + beforeRouteEnterSpy(); + }, + beforeRouteLeave() { + beforeRouteLeaveSpy(); + }, + components: { IonPage }, + template: `` + } + const Page2 = { + components: { IonPage }, + template: `` + } + + const router = createRouter({ + history: createWebHistory(process.env.BASE_URL), + routes: [ + { path: '/page', component: Page }, + { path: '/page2', component: Page2 }, + { path: '/', redirect: '/page' } + ] + }); + + router.push('/'); + await router.isReady(); + const wrapper = mount(App, { + global: { + plugins: [router, IonicVue] + } + }); + + expect(beforeRouteEnterSpy).toHaveBeenCalledTimes(1); + + router.push('/page2'); + await waitForRouter(); + + expect(beforeRouteLeaveSpy).toHaveBeenCalledTimes(1); + + router.back(); + await waitForRouter(); + + expect(beforeRouteEnterSpy).toHaveBeenCalledTimes(2); + }); });