From 506966fd88786e1021b5b9508d6dc92bda944d6c Mon Sep 17 00:00:00 2001 From: ShaneK Date: Tue, 12 May 2026 05:48:39 -0700 Subject: [PATCH] fix(vue-router): set pushedByRoute on same-tab push with direction none --- packages/vue-router/src/router.ts | 19 +++++++++ packages/vue/test/base/src/router/index.ts | 12 ++++++ .../base/src/views/DirectionNoneBackA.vue | 40 +++++++++++++++++++ .../base/src/views/DirectionNoneBackB.vue | 40 +++++++++++++++++++ .../src/views/DirectionNoneBackFallback.vue | 33 +++++++++++++++ .../playwright/direction-none-back.spec.ts | 37 +++++++++++++++++ 6 files changed, 181 insertions(+) create mode 100644 packages/vue/test/base/src/views/DirectionNoneBackA.vue create mode 100644 packages/vue/test/base/src/views/DirectionNoneBackB.vue create mode 100644 packages/vue/test/base/src/views/DirectionNoneBackFallback.vue create mode 100644 packages/vue/test/base/tests/e2e/playwright/direction-none-back.spec.ts diff --git a/packages/vue-router/src/router.ts b/packages/vue-router/src/router.ts index 35ce3d55a94..8f673aa4e6f 100644 --- a/packages/vue-router/src/router.ts +++ b/packages/vue-router/src/router.ts @@ -383,6 +383,25 @@ export const createIonRouter = ( routeInfo.tab ); routeInfo.pushedByRoute = lastRoute?.pushedByRoute; + } else if ( + routeInfo.routerAction === "push" && + routeInfo.routerDirection === "none" && + routeInfo.tab === leavingLocationInfo.tab + ) { + /** + * Same-tab push with direction "none" still needs pushedByRoute so + * ion-back-button uses history instead of falling back to defaultHref. + * Cross-tab pushes hit the branch above. + * + * Skip when the candidate equals the current pathname (e.g. /a?x=1 -> + * /a?x=2) to avoid a self-loop on back. Same guard as the replace + * branch below. + */ + const candidate = leavingLocationInfo.pathname; + routeInfo.pushedByRoute = + candidate !== "" && candidate !== routeInfo.pathname + ? candidate + : undefined; } else if (routeInfo.routerAction === "replace") { /** * When replacing a route, we want to make sure we select the current route diff --git a/packages/vue/test/base/src/router/index.ts b/packages/vue/test/base/src/router/index.ts index 37511871b81..c052e16f14f 100644 --- a/packages/vue/test/base/src/router/index.ts +++ b/packages/vue/test/base/src/router/index.ts @@ -49,6 +49,18 @@ const routes: Array = [ path: '/default-href', component: () => import('@/views/DefaultHref.vue') }, + { + path: '/direction-none-back/a', + component: () => import('@/views/DirectionNoneBackA.vue') + }, + { + path: '/direction-none-back/b', + component: () => import('@/views/DirectionNoneBackB.vue') + }, + { + path: '/direction-none-back/fallback', + component: () => import('@/views/DirectionNoneBackFallback.vue') + }, { path: '/routing', component: () => import('@/views/Routing.vue') diff --git a/packages/vue/test/base/src/views/DirectionNoneBackA.vue b/packages/vue/test/base/src/views/DirectionNoneBackA.vue new file mode 100644 index 00000000000..4b1d41afa5b --- /dev/null +++ b/packages/vue/test/base/src/views/DirectionNoneBackA.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/vue/test/base/src/views/DirectionNoneBackB.vue b/packages/vue/test/base/src/views/DirectionNoneBackB.vue new file mode 100644 index 00000000000..d87dad1f3d3 --- /dev/null +++ b/packages/vue/test/base/src/views/DirectionNoneBackB.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/vue/test/base/src/views/DirectionNoneBackFallback.vue b/packages/vue/test/base/src/views/DirectionNoneBackFallback.vue new file mode 100644 index 00000000000..86d1fe7c58a --- /dev/null +++ b/packages/vue/test/base/src/views/DirectionNoneBackFallback.vue @@ -0,0 +1,33 @@ + + + diff --git a/packages/vue/test/base/tests/e2e/playwright/direction-none-back.spec.ts b/packages/vue/test/base/tests/e2e/playwright/direction-none-back.spec.ts new file mode 100644 index 00000000000..714d3cfbb65 --- /dev/null +++ b/packages/vue/test/base/tests/e2e/playwright/direction-none-back.spec.ts @@ -0,0 +1,37 @@ +import { test, expect } from './utils/test-base'; +import { ionPageVisible, ionPageDoesNotExist, ionBackClick } from './utils/test-utils'; + +/** + * Tests that ion-back-button works correctly after navigating with + * router-direction="none". The back button should use history to determine + * the previous page, not fall back to defaultHref. + * + * @see https://github.com/ionic-team/ionic-framework/issues/24074 + */ +test.describe('router-direction="none" Back Button', () => { + test('back button should return to Page A after navigating with direction "forward"', async ({ page }) => { + await page.goto('/direction-none-back/a'); + await ionPageVisible(page, 'direction-none-page-a'); + + await page.locator('ion-button#go-forward').click(); + await ionPageVisible(page, 'direction-none-page-b'); + + await ionBackClick(page, 'direction-none-page-b'); + await ionPageDoesNotExist(page, 'direction-none-page-fallback'); + await ionPageVisible(page, 'direction-none-page-a'); + expect(new URL(page.url()).pathname).toBe('/direction-none-back/a'); + }); + + test('back button should return to Page A after navigating with direction "none"', async ({ page }) => { + await page.goto('/direction-none-back/a'); + await ionPageVisible(page, 'direction-none-page-a'); + + await page.locator('ion-button#go-none').click(); + await ionPageVisible(page, 'direction-none-page-b'); + + await ionBackClick(page, 'direction-none-page-b'); + await ionPageDoesNotExist(page, 'direction-none-page-fallback'); + await ionPageVisible(page, 'direction-none-page-a'); + expect(new URL(page.url()).pathname).toBe('/direction-none-back/a'); + }); +});