From 1688d6eac157a51ee31d61480a6025d3ccb99472 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 12:53:33 -0500 Subject: [PATCH 01/11] test(vue): update to latest vue deps --- packages/vue/test/apps/vue3/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vue/test/apps/vue3/package.json b/packages/vue/test/apps/vue3/package.json index 669d1600d8b..09674766549 100644 --- a/packages/vue/test/apps/vue3/package.json +++ b/packages/vue/test/apps/vue3/package.json @@ -19,8 +19,8 @@ "@ionic/vue": "^6.0.12", "@ionic/vue-router": "^6.0.12", "ionicons": "^6.0.4", - "vue": "^3.2.31", - "vue-router": "^4.0.14" + "vue": "^3.4.14", + "vue-router": "^4.2.5" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "^5.4.0", From b668eec1c872dd12ee7f1a027e2d34cb6b1e97a5 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 13:58:53 -0500 Subject: [PATCH 02/11] fix(vue): account for vue 3.2 fix --- packages/vue/src/components/IonTabs.ts | 34 ++++++++++++++++++++------ 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/vue/src/components/IonTabs.ts b/packages/vue/src/components/IonTabs.ts index a2333695a30..03449f83aba 100644 --- a/packages/vue/src/components/IonTabs.ts +++ b/packages/vue/src/components/IonTabs.ts @@ -6,6 +6,27 @@ const DID_CHANGE = "ionTabsDidChange"; // TODO(FW-2969): types +/** + * Vue 3.2.38 fixed an issue where Web Component + * names are respected using kebab case instead of pascal case. + * As a result, we need to account for both here since we support + * versions of Vue < 3.2.38. + */ +const isRouterOutlet = (node: VNode) => { + return ( + node.type && + ((node.type as any).name === "IonRouterOutlet" || + node.type === "ion-router-outlet") + ); +}; + +const isTabBar = (node: VNode) => { + return ( + node.type && + ((node.type as any).name === "IonTabBar" || node.type === "ion-tab-bar") + ); +}; + export const IonTabs = /*@__PURE__*/ defineComponent({ name: "IonTabs", emits: [WILL_CHANGE, DID_CHANGE], @@ -19,9 +40,8 @@ export const IonTabs = /*@__PURE__*/ defineComponent({ * inside of ion-tabs. */ if (slottedContent && slottedContent.length > 0) { - routerOutlet = slottedContent.find( - (child: VNode) => - child.type && (child.type as any).name === "IonRouterOutlet" + routerOutlet = slottedContent.find((child: VNode) => + isRouterOutlet(child) ); } @@ -57,13 +77,11 @@ export const IonTabs = /*@__PURE__*/ defineComponent({ * since that needs to be inside of `.tabs-inner`. */ const filteredContent = slottedContent.filter( - (child: VNode) => - !child.type || - (child.type && (child.type as any).name !== "IonRouterOutlet") + (child: VNode) => !child.type || !isRouterOutlet(child) ); - const slottedTabBar = filteredContent.find( - (child: VNode) => child.type && (child.type as any).name === "IonTabBar" + const slottedTabBar = filteredContent.find((child: VNode) => + isTabBar(child) ); const hasTopSlotTabBar = slottedTabBar && slottedTabBar.props?.slot === "top"; From ffff74917907e58ea26c40354495c58fb07e09eb Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 14:29:04 -0500 Subject: [PATCH 03/11] chore: update vitest to avoid event bug --- packages/vue/test/apps/vue3/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vue/test/apps/vue3/package.json b/packages/vue/test/apps/vue3/package.json index 09674766549..09e9b8fcdf6 100644 --- a/packages/vue/test/apps/vue3/package.json +++ b/packages/vue/test/apps/vue3/package.json @@ -35,7 +35,7 @@ "jsdom": "^20.0.0", "typescript": "~4.5.5", "vite": "^3.1.4", - "vitest": "^0.23.4", + "vitest": "^1.2.1", "wait-on": "^5.3.0" }, "engines": { From 7b0a09c42dec0f21ede9622941cf2c0725169c44 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 15:31:55 -0500 Subject: [PATCH 04/11] test(vue): simplify tabs tests --- .../vue/test/base/tests/unit/tab-bar.spec.ts | 22 +++++++------------ .../vue/test/base/tests/unit/tabs.spec.ts | 15 +++++-------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/packages/vue/test/base/tests/unit/tab-bar.spec.ts b/packages/vue/test/base/tests/unit/tab-bar.spec.ts index d1c1037a924..00ded7020b4 100644 --- a/packages/vue/test/base/tests/unit/tab-bar.spec.ts +++ b/packages/vue/test/base/tests/unit/tab-bar.spec.ts @@ -1,12 +1,7 @@ import { mount } from '@vue/test-utils'; import { describe, expect, it } from 'vitest'; import { createRouter, createWebHistory } from '@ionic/vue-router'; -import { IonicVue, IonApp, IonRouterOutlet, IonPage, IonTabs, IonTabBar } from '@ionic/vue'; - -const App = { - components: { IonApp, IonRouterOutlet }, - template: '', -} +import { IonicVue, IonRouterOutlet, IonPage, IonTabs, IonTabBar } from '@ionic/vue'; describe('ion-tab-bar', () => { it('should render in the top slot', async () => { @@ -31,7 +26,7 @@ describe('ion-tab-bar', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(Tabs, { global: { plugins: [router, IonicVue] } @@ -67,7 +62,7 @@ describe('ion-tab-bar', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(Tabs, { global: { plugins: [router, IonicVue] } @@ -102,7 +97,7 @@ describe('ion-tab-bar', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(Tabs, { global: { plugins: [router, IonicVue] } @@ -141,16 +136,15 @@ describe('ion-tab-bar', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(Tabs, { global: { plugins: [router, IonicVue] } }); - const innerHTML = wrapper.find('ion-tabs').html(); - - const tabs = wrapper.findComponent(IonTabBar); - const children = tabs.vm.$el.childNodes; + const tabs = wrapper.findComponent(IonTabs); + const tabbar = tabs.vm.$el.children[1]; + const children = tabbar.childNodes; // 8 is a comment node: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType expect(children[0].nodeType).toEqual(8); diff --git a/packages/vue/test/base/tests/unit/tabs.spec.ts b/packages/vue/test/base/tests/unit/tabs.spec.ts index 528386b8963..73a82bd8748 100644 --- a/packages/vue/test/base/tests/unit/tabs.spec.ts +++ b/packages/vue/test/base/tests/unit/tabs.spec.ts @@ -1,14 +1,9 @@ import { mount } from '@vue/test-utils'; import { describe, expect, it } from 'vitest'; import { createRouter, createWebHistory } from '@ionic/vue-router'; -import { IonicVue, IonApp, IonRouterOutlet, IonPage, IonTabs, IonTabBar, IonTabButton, IonLabel } from '@ionic/vue'; +import { IonicVue, IonRouterOutlet, IonPage, IonTabs, IonTabBar, IonTabButton, IonLabel } from '@ionic/vue'; import { waitForRouter } from './utils'; -const App = { - components: { IonApp, IonRouterOutlet }, - template: '', -} - const Tabs = { components: { IonPage, IonTabs, IonTabBar, IonTabButton, IonLabel, IonRouterOutlet }, template: ` @@ -64,7 +59,7 @@ describe('ion-tabs', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -112,7 +107,7 @@ describe('ion-tabs', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -166,7 +161,7 @@ describe('ion-tabs', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -222,7 +217,7 @@ describe('ion-tabs', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } From 6252a053740f16abdddc3772de4ca27a3edf2e8a Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 15:43:16 -0500 Subject: [PATCH 05/11] test(vue): simplify hooks, page, and router-outlet tests --- packages/vue/test/base/tests/unit/hooks.spec.ts | 17 ++++++----------- packages/vue/test/base/tests/unit/page.spec.ts | 11 +++-------- .../test/base/tests/unit/router-outlet.spec.ts | 12 ++---------- 3 files changed, 11 insertions(+), 29 deletions(-) diff --git a/packages/vue/test/base/tests/unit/hooks.spec.ts b/packages/vue/test/base/tests/unit/hooks.spec.ts index b0ef23bed7a..d6657faa6bc 100644 --- a/packages/vue/test/base/tests/unit/hooks.spec.ts +++ b/packages/vue/test/base/tests/unit/hooks.spec.ts @@ -1,14 +1,9 @@ import { mount } from '@vue/test-utils'; import { describe, expect, it } from 'vitest'; import { createRouter, createWebHistory } from '@ionic/vue-router'; -import { IonicVue, IonApp, IonRouterOutlet, IonPage, useIonRouter, createAnimation } from '@ionic/vue'; +import { IonicVue, IonRouterOutlet, IonPage, useIonRouter } from '@ionic/vue'; import { mockAnimation, waitForRouter } from './utils'; -const App = { - components: { IonApp, IonRouterOutlet }, - template: '', -} - const BasePage = { template: '', components: { IonPage }, @@ -40,7 +35,7 @@ describe('useIonRouter', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -85,7 +80,7 @@ describe('useIonRouter', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -137,7 +132,7 @@ describe('useIonRouter', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -181,7 +176,7 @@ describe('useIonRouter', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -229,7 +224,7 @@ describe('useIonRouter', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } diff --git a/packages/vue/test/base/tests/unit/page.spec.ts b/packages/vue/test/base/tests/unit/page.spec.ts index cd8917c30bd..4fb0e985f25 100644 --- a/packages/vue/test/base/tests/unit/page.spec.ts +++ b/packages/vue/test/base/tests/unit/page.spec.ts @@ -1,12 +1,7 @@ import { mount } from '@vue/test-utils'; import { describe, expect, it } from 'vitest'; import { createRouter, createWebHistory } from '@ionic/vue-router'; -import { IonicVue, IonApp, IonRouterOutlet, IonPage } from '@ionic/vue'; - -const App = { - components: { IonApp, IonRouterOutlet }, - template: '', -} +import { IonicVue, IonRouterOutlet, IonPage } from '@ionic/vue'; describe('IonPage', () => { it('should add ion-page class', async () => { @@ -25,7 +20,7 @@ describe('IonPage', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -50,7 +45,7 @@ describe('IonPage', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } diff --git a/packages/vue/test/base/tests/unit/router-outlet.spec.ts b/packages/vue/test/base/tests/unit/router-outlet.spec.ts index 89ee04bc559..f25490c2a21 100644 --- a/packages/vue/test/base/tests/unit/router-outlet.spec.ts +++ b/packages/vue/test/base/tests/unit/router-outlet.spec.ts @@ -3,22 +3,14 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { createRouter, createWebHistory } from '@ionic/vue-router'; import { IonicVue, - IonApp, IonRouterOutlet, IonPage, useIonRouter, - createAnimation } from '@ionic/vue'; -import { onBeforeRouteLeave } from 'vue-router'; import { mockAnimation, waitForRouter } from './utils'; enableAutoUnmount(afterEach); -const App = { - components: { IonApp, IonRouterOutlet }, - template: '', -} - const BasePage = { template: '', components: { IonPage }, @@ -60,7 +52,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -122,7 +114,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } From 2b44684b3bd56c9c5c745b16c00d971591b8d0d7 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 15:47:05 -0500 Subject: [PATCH 06/11] fix(vue): account for vue 3.4 watcher change --- packages/vue/src/components/IonRouterOutlet.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index 4b4c634e946..0e2a7697258 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -115,7 +115,8 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({ previousMatchedRouteRef = currentMatchedRouteRef; previousMatchedPath = currentRoute.path; - } + }, + { deep: true } ); const canStart = () => { From 6a74477ad9d36dea2417d19ae91c18b962c80b78 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 16:02:59 -0500 Subject: [PATCH 07/11] test(vue): clean up routing tests --- .../vue/test/base/tests/unit/routing.spec.ts | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/vue/test/base/tests/unit/routing.spec.ts b/packages/vue/test/base/tests/unit/routing.spec.ts index a4a8f55521a..15c4c184d7b 100644 --- a/packages/vue/test/base/tests/unit/routing.spec.ts +++ b/packages/vue/test/base/tests/unit/routing.spec.ts @@ -17,11 +17,6 @@ import { waitForRouter } from './utils'; enableAutoUnmount(afterEach); -const App = { - components: { IonApp, IonRouterOutlet }, - template: '', -} - const BasePage = { template: '', components: { IonPage }, @@ -46,7 +41,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -74,7 +69,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -107,7 +102,7 @@ describe('Routing', () => { router.push('/myPath/123'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -147,7 +142,7 @@ describe('Routing', () => { router.push('/myPath'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -182,7 +177,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -249,7 +244,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(Tabs, { global: { plugins: [router, IonicVue] } @@ -302,7 +297,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -355,7 +350,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -402,7 +397,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -450,7 +445,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -618,7 +613,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -672,7 +667,7 @@ describe('Routing', () => { router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } From 3b483064da2946e9b8a49fe6a349e5943025c834 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 16:13:36 -0500 Subject: [PATCH 08/11] test(vue): clean up routing test more --- packages/vue/test/base/tests/unit/routing.spec.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/vue/test/base/tests/unit/routing.spec.ts b/packages/vue/test/base/tests/unit/routing.spec.ts index 15c4c184d7b..3d1f50a428f 100644 --- a/packages/vue/test/base/tests/unit/routing.spec.ts +++ b/packages/vue/test/base/tests/unit/routing.spec.ts @@ -198,7 +198,7 @@ describe('Routing', () => { template: ` - + Tab 1 @@ -242,9 +242,9 @@ describe('Routing', () => { ] }); - router.push('/'); + router.push('/tabs/tab1'); await router.isReady(); - const wrapper = mount(Tabs, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } From bc0acb5e4a879fffc4abedaa37d5f1333bbdad86 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Wed, 17 Jan 2024 16:14:50 -0500 Subject: [PATCH 09/11] test(vue): clean up lifecycle test --- packages/vue/test/base/tests/unit/lifecycle.spec.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/vue/test/base/tests/unit/lifecycle.spec.ts b/packages/vue/test/base/tests/unit/lifecycle.spec.ts index f82106ccbe8..3c1996d5e74 100644 --- a/packages/vue/test/base/tests/unit/lifecycle.spec.ts +++ b/packages/vue/test/base/tests/unit/lifecycle.spec.ts @@ -1,15 +1,10 @@ import { mount } from '@vue/test-utils'; import { describe, expect, it, vi } from 'vitest'; import { createRouter, createWebHistory } from '@ionic/vue-router'; -import { IonicVue, IonApp, IonRouterOutlet, IonTabs, IonPage } from '@ionic/vue'; +import { IonicVue, IonRouterOutlet, IonTabs, IonPage } from '@ionic/vue'; import { defineComponent } from 'vue'; import { waitForRouter } from './utils'; -const App = { - components: { IonApp, IonRouterOutlet }, - template: '', -} - const BasePage = { template: '', components: { IonPage }, @@ -54,7 +49,7 @@ describe('Lifecycle Events', () => { // Initial render router.push('/'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } @@ -108,7 +103,7 @@ describe('Lifecycle Events', () => { template: ` - + `, @@ -148,7 +143,7 @@ describe('Lifecycle Events', () => { // Initial render router.push('/tab1'); await router.isReady(); - const wrapper = mount(App, { + const wrapper = mount(IonRouterOutlet, { global: { plugins: [router, IonicVue] } From 0a2878231e41a901ea35420515e1ba9796ca8afb Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 18 Jan 2024 13:53:40 -0500 Subject: [PATCH 10/11] Update IonRouterOutlet.ts --- packages/vue/src/components/IonRouterOutlet.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/vue/src/components/IonRouterOutlet.ts b/packages/vue/src/components/IonRouterOutlet.ts index 0e2a7697258..1c32de13c01 100644 --- a/packages/vue/src/components/IonRouterOutlet.ts +++ b/packages/vue/src/components/IonRouterOutlet.ts @@ -116,6 +116,13 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({ previousMatchedRouteRef = currentMatchedRouteRef; previousMatchedPath = currentRoute.path; }, + /** + * Future versions of Vue may default watching nested + * reactive objects to "deep: false". + * We explicitly set this watcher to "deep: true" to + * account for that. + * https://github.com/vuejs/core/issues/9965#issuecomment-1875067499 + */ { deep: true } ); From 658a3ca7068ea1b5c2ade95a028d9e17ae586921 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 18 Jan 2024 13:56:16 -0500 Subject: [PATCH 11/11] Update IonTabs.ts --- packages/vue/src/components/IonTabs.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/vue/src/components/IonTabs.ts b/packages/vue/src/components/IonTabs.ts index 03449f83aba..432c2479b59 100644 --- a/packages/vue/src/components/IonTabs.ts +++ b/packages/vue/src/components/IonTabs.ts @@ -12,6 +12,7 @@ const DID_CHANGE = "ionTabsDidChange"; * As a result, we need to account for both here since we support * versions of Vue < 3.2.38. */ +// TODO FW-5904 const isRouterOutlet = (node: VNode) => { return ( node.type &&