Skip to content

Commit

Permalink
fix(vue): lifecycles now fire on tabs pages (#25786)
Browse files Browse the repository at this point in the history
resolves #25784
  • Loading branch information
liamdebeasi authored Aug 23, 2022
1 parent 71fad38 commit 3020005
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 23 deletions.
29 changes: 15 additions & 14 deletions packages/vue/src/components/IonRouterOutlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,20 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
* all of the keys in the params object, we check the url path to
* see if they are different after ensuring we are in a parameterized route.
*/
if (currentMatchedRouteRef === undefined) { return; }

const matchedDifferentRoutes = currentMatchedRouteRef !== previousMatchedRouteRef;
const matchedDifferentParameterRoutes = (
currentRoute.matched[currentRoute.matched.length - 1] === currentMatchedRouteRef &&
currentRoute.path !== previousMatchedPath
);

if (matchedDifferentRoutes || matchedDifferentParameterRoutes) {
setupViewItem(matchedRouteRef);
previousMatchedRouteRef = currentMatchedRouteRef;
previousMatchedPath = currentRoute.path;
if (currentMatchedRouteRef !== undefined) {
const matchedDifferentRoutes = currentMatchedRouteRef !== previousMatchedRouteRef;
const matchedDifferentParameterRoutes = (
currentRoute.matched[currentRoute.matched.length - 1] === currentMatchedRouteRef &&
currentRoute.path !== previousMatchedPath
);

if (matchedDifferentRoutes || matchedDifferentParameterRoutes) {
setupViewItem(matchedRouteRef);
}
}

previousMatchedRouteRef = currentMatchedRouteRef;
previousMatchedPath = currentRoute.path;
});

const canStart = () => {
Expand Down Expand Up @@ -274,13 +275,13 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
* return early for swipe to go back when
* going from a non-tabs page to a tabs page.
*/
if (isViewVisible(enteringEl) && leavingViewItem !== undefined && !isViewVisible(leavingViewItem.ionPageElement)) {
if (isViewVisible(enteringEl) && leavingViewItem?.ionPageElement !== undefined && !isViewVisible(leavingViewItem.ionPageElement)) {
return;
}

fireLifecycle(enteringViewItem.vueComponent, enteringViewItem.vueComponentRef, LIFECYCLE_WILL_ENTER);

if (leavingViewItem && enteringViewItem !== leavingViewItem) {
if (leavingViewItem?.ionPageElement && enteringViewItem !== leavingViewItem) {
let animationBuilder = routerAnimation;
const leavingEl = leavingViewItem.ionPageElement;

Expand Down
131 changes: 122 additions & 9 deletions packages/vue/test-app/tests/unit/lifecycle.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils';
import { createRouter, createWebHistory } from '@ionic/vue-router';
import { IonicVue, IonApp, IonRouterOutlet, IonPage } from '@ionic/vue';
import { IonicVue, IonApp, IonRouterOutlet, IonTabs, IonPage } from '@ionic/vue';
import { defineComponent } from 'vue';
import { waitForRouter } from './utils';

Expand Down Expand Up @@ -40,19 +40,19 @@ const Page2 = defineComponent({
ionViewDidLeave: jest.fn(),
});

const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes: [
{ path: '/', component: Page1 },
{ path: '/2', component: Page2 }
]
});

describe('Lifecycle Events', () => {
beforeAll(() => {
(HTMLElement.prototype as HTMLIonRouterOutletElement).commit = jest.fn();
});
it('Triggers lifecycle events', async () => {
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes: [
{ path: '/', component: Page1 },
{ path: '/2', component: Page2 }
]
});

// Initial render
router.push('/');
await router.isReady();
Expand Down Expand Up @@ -105,4 +105,117 @@ describe('Lifecycle Events', () => {
expect(Page2.ionViewDidLeave).not.toHaveBeenCalled();
expect(wrapper.html()).toContain('page2');
});
it('should fire lifecycle events on inner tab page', async () => {
const TabsPage = {
template: `
<ion-page>
<ion-tabs>
<ion-router-outlet></ion-router-outlet>
</ion-tabs>
</ion-page>
`,
components: { IonPage, IonTabs, IonRouterOutlet },
ionViewWillEnter: jest.fn(),
ionViewDidEnter: jest.fn(),
ionViewWillLeave: jest.fn(),
ionViewDidLeave: jest.fn(),
}
const Tab1Page = {
...BasePage,
ionViewWillEnter: jest.fn(),
ionViewDidEnter: jest.fn(),
ionViewWillLeave: jest.fn(),
ionViewDidLeave: jest.fn(),
}

const NonTabPage = {
...BasePage,
ionViewWillEnter: jest.fn(),
ionViewDidEnter: jest.fn(),
ionViewWillLeave: jest.fn(),
ionViewDidLeave: jest.fn(),
}


const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes: [
{ path: '/', component: TabsPage, children: [
{ path: 'tab1', component: Tab1Page }
]},
{ path: '/non-tab', component: NonTabPage }
]
});

// Initial render
router.push('/tab1');
await router.isReady();
const wrapper = mount(App, {
global: {
plugins: [router, IonicVue]
}
});

// Initial load
expect(TabsPage.ionViewWillEnter).toHaveBeenCalled();
expect(TabsPage.ionViewDidEnter).toHaveBeenCalled();

expect(Tab1Page.ionViewWillEnter).toHaveBeenCalled();
expect(Tab1Page.ionViewDidEnter).toHaveBeenCalled();

expect(NonTabPage.ionViewWillEnter).not.toHaveBeenCalled();
expect(NonTabPage.ionViewDidEnter).not.toHaveBeenCalled();

// Navigate out of tabs
router.push('/non-tab');
jest.resetAllMocks();
await waitForRouter();

expect(TabsPage.ionViewWillLeave).toHaveBeenCalled();
expect(TabsPage.ionViewDidLeave).toHaveBeenCalled();

// Tab1Page currently does not call leaving hooks
// when navigating out of tabs
//expect(Tab1Page.ionViewWillLeave).toHaveBeenCalled();
//expect(Tab1Page.ionViewDidLeave).toHaveBeenCalled();

expect(NonTabPage.ionViewWillEnter).toHaveBeenCalled();
expect(NonTabPage.ionViewDidEnter).toHaveBeenCalled();

// Go back
router.back();
jest.resetAllMocks();
await waitForRouter();

expect(TabsPage.ionViewWillEnter).toHaveBeenCalled();
expect(TabsPage.ionViewDidEnter).toHaveBeenCalled();

expect(Tab1Page.ionViewWillEnter).toHaveBeenCalled();
expect(Tab1Page.ionViewDidEnter).toHaveBeenCalled();

expect(NonTabPage.ionViewWillLeave).toHaveBeenCalled();
expect(NonTabPage.ionViewDidLeave).toHaveBeenCalled();

// Navigate out of tabs again
router.push('/non-tab');
jest.resetAllMocks();
await waitForRouter();

expect(TabsPage.ionViewWillLeave).toHaveBeenCalled();
expect(TabsPage.ionViewDidLeave).toHaveBeenCalled();

expect(NonTabPage.ionViewWillEnter).toHaveBeenCalled();
expect(NonTabPage.ionViewDidEnter).toHaveBeenCalled();

// Go back again
router.back();
jest.resetAllMocks();
await waitForRouter();

expect(TabsPage.ionViewWillEnter).toHaveBeenCalled();
expect(TabsPage.ionViewDidEnter).toHaveBeenCalled();

expect(NonTabPage.ionViewWillLeave).toHaveBeenCalled();
expect(NonTabPage.ionViewDidLeave).toHaveBeenCalled();
})
});

0 comments on commit 3020005

Please sign in to comment.