From 5c66ea0e157e71dc1481305ca07562f681c20832 Mon Sep 17 00:00:00 2001 From: ShaneK Date: Mon, 8 Dec 2025 10:39:35 -0800 Subject: [PATCH 1/4] fix(react-router): support React Router 6 style relative paths in IonRouterOutlet --- .../src/ReactRouter/ReactRouterViewStack.tsx | 10 ++ .../src/ReactRouter/StackManager.tsx | 20 ++- .../src/ReactRouter/utils/pathMatching.ts | 29 ++-- packages/react-router/test/base/src/App.tsx | 2 + .../react-router/test/base/src/pages/Main.tsx | 3 + .../pages/relative-paths/RelativePaths.tsx | 132 ++++++++++++++++++ .../base/tests/e2e/specs/relative-paths.cy.js | 70 ++++++++++ 7 files changed, 251 insertions(+), 15 deletions(-) create mode 100644 packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx create mode 100644 packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js diff --git a/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx b/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx index 32598cb22ba..02bfa725bf4 100644 --- a/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx +++ b/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx @@ -713,7 +713,17 @@ export class ReactRouterViewStack extends ViewStacks { return false; } + // For empty path routes, only match if we're at the same level as when the view was created. + // This prevents an empty path view item from being reused for different routes. if (isDefaultRoute) { + const previousPathnameBase = v.routeData?.match?.pathnameBase || ''; + const normalizedBase = normalizePathnameForComparison(previousPathnameBase); + const normalizedPathname = normalizePathnameForComparison(pathname); + + if (normalizedPathname !== normalizedBase) { + return false; + } + match = { params: {}, pathname, diff --git a/packages/react-router/src/ReactRouter/StackManager.tsx b/packages/react-router/src/ReactRouter/StackManager.tsx index 4ce73c561b0..ad68d406675 100644 --- a/packages/react-router/src/ReactRouter/StackManager.tsx +++ b/packages/react-router/src/ReactRouter/StackManager.tsx @@ -933,7 +933,8 @@ function findRouteByRouteInfo(node: React.ReactNode, routeInfo: RouteInfo, paren // For nested routes in React Router 6, we need to extract the relative path // that this outlet should be responsible for matching - let pathnameToMatch = routeInfo.pathname; + const originalPathname = routeInfo.pathname; + let relativePathnameToMatch = routeInfo.pathname; // Check if we have relative routes (routes that don't start with '/') const hasRelativeRoutes = sortedRoutes.some((r) => r.props.path && !r.props.path.startsWith('/')); @@ -950,14 +951,27 @@ function findRouteByRouteInfo(node: React.ReactNode, routeInfo: RouteInfo, paren const pathSegments = routeInfo.pathname.split('/').filter(Boolean); const parentSegments = normalizedParent.split('/').filter(Boolean); const relativeSegments = pathSegments.slice(parentSegments.length); - pathnameToMatch = relativeSegments.join('/'); // Empty string is valid for index routes + relativePathnameToMatch = relativeSegments.join('/'); // Empty string is valid for index routes } } // Find the first matching route for (const child of sortedRoutes) { + const childPath = child.props.path as string | undefined; + const isAbsoluteRoute = childPath && childPath.startsWith('/'); + const pathnameToMatch = isAbsoluteRoute ? originalPathname : relativePathnameToMatch; + + // Only use derivePathnameToMatch for absolute routes or wildcard patterns; + // non-wildcard relative routes match directly against the computed relative pathname. + let pathForMatch: string; + if (isAbsoluteRoute || (childPath && childPath.includes('*'))) { + pathForMatch = derivePathnameToMatch(pathnameToMatch, childPath); + } else { + pathForMatch = pathnameToMatch; + } + const match = matchPath({ - pathname: pathnameToMatch, + pathname: pathForMatch, componentProps: child.props, }); diff --git a/packages/react-router/src/ReactRouter/utils/pathMatching.ts b/packages/react-router/src/ReactRouter/utils/pathMatching.ts index a0ab74164f7..054a2333740 100644 --- a/packages/react-router/src/ReactRouter/utils/pathMatching.ts +++ b/packages/react-router/src/ReactRouter/utils/pathMatching.ts @@ -27,13 +27,8 @@ interface MatchPathOptions { export const matchPath = ({ pathname, componentProps }: MatchPathOptions): PathMatch | null => { const { path, index, ...restProps } = componentProps; - // Handle index routes + // Handle index routes - they match when pathname is empty or just "/" if (index && !path) { - // Index routes match when there's no additional path after the parent route - // For example, in a nested outlet at /routing/*, the index route matches - // when the relative path is empty (i.e., we're exactly at /routing) - - // If pathname is empty or just "/", it should match the index route if (pathname === '' || pathname === '/') { return { params: {}, @@ -46,17 +41,27 @@ export const matchPath = ({ pathname, componentProps }: MatchPathOptions): PathM }, }; } - - // Otherwise, index routes don't match when there's additional path return null; } - if (!path) { + // Handle empty path routes - they match when pathname is also empty or just "/" + if (path === '' || path === undefined) { + if (pathname === '' || pathname === '/') { + return { + params: {}, + pathname: pathname, + pathnameBase: pathname || '/', + pattern: { + path: '', + caseSensitive: restProps.caseSensitive ?? false, + end: restProps.end ?? true, + }, + }; + } return null; } - // For relative paths in nested routes (those that don't start with '/'), - // use React Router's matcher against a normalized path. + // For relative paths (don't start with '/'), normalize both path and pathname for matching if (!path.startsWith('/')) { const matchOptions: Parameters[0] = { path: `/${path}`, @@ -83,7 +88,6 @@ export const matchPath = ({ pathname, componentProps }: MatchPathOptions): PathM }; } - // No match found return null; } @@ -109,6 +113,7 @@ export const matchPath = ({ pathname, componentProps }: MatchPathOptions): PathM * strip off the already-matched parent segments so React Router receives the remainder. */ export const derivePathnameToMatch = (fullPathname: string, routePath?: string): string => { + // For absolute or empty routes, use the full pathname as-is if (!routePath || routePath === '' || routePath.startsWith('/')) { return fullPathname; } diff --git a/packages/react-router/test/base/src/App.tsx b/packages/react-router/test/base/src/App.tsx index 9cc461a4176..ccfb3264fad 100644 --- a/packages/react-router/test/base/src/App.tsx +++ b/packages/react-router/test/base/src/App.tsx @@ -31,6 +31,7 @@ import MultipleTabs from './pages/muiltiple-tabs/MultipleTabs'; import NestedOutlet from './pages/nested-outlet/NestedOutlet'; import NestedOutlet2 from './pages/nested-outlet/NestedOutlet2'; import NestedParams from './pages/nested-params/NestedParams'; +import RelativePaths from './pages/relative-paths/RelativePaths'; import { OutletRef } from './pages/outlet-ref/OutletRef'; import Params from './pages/params/Params'; import Refs from './pages/refs/Refs'; @@ -70,6 +71,7 @@ const App: React.FC = () => { } /> } /> } /> + } /> diff --git a/packages/react-router/test/base/src/pages/Main.tsx b/packages/react-router/test/base/src/pages/Main.tsx index da6f3dd0667..18bffa7c813 100644 --- a/packages/react-router/test/base/src/pages/Main.tsx +++ b/packages/react-router/test/base/src/pages/Main.tsx @@ -74,6 +74,9 @@ const Main: React.FC = () => { Nested Params + + Relative Paths + diff --git a/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx b/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx new file mode 100644 index 00000000000..1c22520da24 --- /dev/null +++ b/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx @@ -0,0 +1,132 @@ +import { + IonContent, + IonHeader, + IonPage, + IonTitle, + IonToolbar, + IonRouterOutlet, + IonList, + IonItem, + IonLabel, + IonBackButton, + IonButtons, +} from '@ionic/react'; +import React from 'react'; +import { Route } from 'react-router-dom'; + +/** + * This test page verifies that IonRouterOutlet correctly handles + * relative paths (paths without a leading slash) the same way + * React Router 6's Routes component does. + * + * Issue: https://github.com/ionic-team/ionic-framework/issues/24177#issuecomment-3624311206 + * - Routes with path="help" should work the same as path="/help" + * - IonRouterOutlet should match relative paths correctly + */ + +const RelativePathsHome: React.FC = () => { + return ( + + + + + + + Relative Paths Test + + + + + + Go to Page A (absolute path route) + + + Go to Page B (relative path route) + + + Go to Page C (relative path route) + + + + + ); +}; + +const PageA: React.FC = () => { + return ( + + + + + + + Page A + + + +
+ This is Page A - route defined with absolute path +
+
+
+ ); +}; + +const PageB: React.FC = () => { + return ( + + + + + + + Page B + + + +
+ This is Page B - route defined with relative path (no leading slash) +
+
+
+ ); +}; + +const PageC: React.FC = () => { + return ( + + + + + + + Page C + + + +
+ This is Page C - another route defined with relative path +
+
+
+ ); +}; + +const RelativePaths: React.FC = () => { + return ( + + {/* Route with absolute path (has leading slash) - this should work */} + } /> + + {/* Routes with relative paths (no leading slash) - these should also work + but currently don't match in IonRouterOutlet */} + } /> + } /> + + {/* Home route - using relative path */} + } /> + + ); +}; + +export default RelativePaths; diff --git a/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js b/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js new file mode 100644 index 00000000000..9f8599c0c46 --- /dev/null +++ b/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js @@ -0,0 +1,70 @@ +const port = 3000; + +/** + * Tests for relative path handling in IonRouterOutlet + * + * Issue: IonRouterOutlet doesn't handle relative paths (without leading slash) + * the same way React Router 6's Routes component does. + * + * In React Router 6, both of these should work identically: + * - } /> + * - } /> + * + * However, IonRouterOutlet only matches the first one (with leading slash). + */ +describe('Relative Paths Tests', () => { + it('should navigate to the relative paths home page', () => { + cy.visit(`http://localhost:${port}/relative-paths`); + cy.ionPageVisible('relative-paths-home'); + }); + + it('should navigate to Page A (defined with absolute path)', () => { + cy.visit(`http://localhost:${port}/relative-paths`); + cy.ionPageVisible('relative-paths-home'); + cy.ionNav('ion-item', 'Go to Page A'); + cy.ionPageVisible('relative-paths-page-a'); + cy.get('[data-testid="page-a-content"]').should('contain', 'Page A'); + }); + + it('should navigate to Page B (defined with relative path - no leading slash)', () => { + // This test verifies the bug - Page B route is defined as path="page-b" (no leading slash) + // It should work the same as path="/relative-paths/page-b" but currently doesn't + cy.visit(`http://localhost:${port}/relative-paths`); + cy.ionPageVisible('relative-paths-home'); + cy.ionNav('ion-item', 'Go to Page B'); + cy.ionPageVisible('relative-paths-page-b'); + cy.get('[data-testid="page-b-content"]').should('contain', 'Page B'); + }); + + it('should navigate to Page C (defined with relative path - no leading slash)', () => { + // Another test for relative path handling + cy.visit(`http://localhost:${port}/relative-paths`); + cy.ionPageVisible('relative-paths-home'); + cy.ionNav('ion-item', 'Go to Page C'); + cy.ionPageVisible('relative-paths-page-c'); + cy.get('[data-testid="page-c-content"]').should('contain', 'Page C'); + }); + + it('should navigate directly to Page B via URL', () => { + // Direct navigation to a page with a relative path route + cy.visit(`http://localhost:${port}/relative-paths/page-b`); + cy.ionPageVisible('relative-paths-page-b'); + cy.get('[data-testid="page-b-content"]').should('contain', 'Page B'); + }); + + it('should navigate directly to Page C via URL', () => { + // Direct navigation to a page with a relative path route + cy.visit(`http://localhost:${port}/relative-paths/page-c`); + cy.ionPageVisible('relative-paths-page-c'); + cy.get('[data-testid="page-c-content"]').should('contain', 'Page C'); + }); + + it('should navigate to Page B and back', () => { + cy.visit(`http://localhost:${port}/relative-paths`); + cy.ionPageVisible('relative-paths-home'); + cy.ionNav('ion-item', 'Go to Page B'); + cy.ionPageVisible('relative-paths-page-b'); + cy.ionBackClick('relative-paths-page-b'); + cy.ionPageVisible('relative-paths-home'); + }); +}); From f491e929bc716481d7015c44caaf9331fdac31e7 Mon Sep 17 00:00:00 2001 From: ShaneK Date: Tue, 9 Dec 2025 11:17:58 -0800 Subject: [PATCH 2/4] fix(react-router): improve relative path matching edge cases --- .../src/ReactRouter/ReactRouterViewStack.tsx | 4 +- .../src/ReactRouter/StackManager.tsx | 74 +++++++++++++------ .../src/ReactRouter/utils/pathMatching.ts | 5 +- packages/react-router/test/base/src/App.tsx | 3 +- .../pages/relative-paths/RelativePaths.tsx | 3 +- .../base/tests/e2e/specs/relative-paths.cy.js | 18 +---- 6 files changed, 65 insertions(+), 42 deletions(-) diff --git a/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx b/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx index 02bfa725bf4..76fa4bfd0c9 100644 --- a/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx +++ b/packages/react-router/src/ReactRouter/ReactRouterViewStack.tsx @@ -469,7 +469,9 @@ export class ReactRouterViewStack extends ViewStacks { let parentPath: string | undefined = undefined; try { // Only attempt parent path computation for non-root outlets - if (outletId !== 'routerOutlet') { + // Root outlets have IDs like 'routerOutlet' or 'routerOutlet-2' + const isRootOutlet = outletId.startsWith('routerOutlet'); + if (!isRootOutlet) { const routeChildren = extractRouteChildren(ionRouterOutlet.props.children); const { hasRelativeRoutes, hasIndexRoute, hasWildcardRoute } = analyzeRouteChildren(routeChildren); diff --git a/packages/react-router/src/ReactRouter/StackManager.tsx b/packages/react-router/src/ReactRouter/StackManager.tsx index ad68d406675..3a58b74be8d 100644 --- a/packages/react-router/src/ReactRouter/StackManager.tsx +++ b/packages/react-router/src/ReactRouter/StackManager.tsx @@ -109,28 +109,36 @@ export class StackManager extends React.PureComponent { return undefined; } - // If this is a nested outlet (has an explicit ID like "main"), - // we need to figure out what part of the path was already matched - if (this.id !== 'routerOutlet' && this.ionRouterOutlet) { + // Check if this outlet has route children to analyze + if (this.ionRouterOutlet) { const routeChildren = extractRouteChildren(this.ionRouterOutlet.props.children); const { hasRelativeRoutes, hasIndexRoute, hasWildcardRoute } = analyzeRouteChildren(routeChildren); - const result = computeParentPath({ - currentPathname, - outletMountPath: this.outletMountPath, - routeChildren, - hasRelativeRoutes, - hasIndexRoute, - hasWildcardRoute, - }); + // Root outlets have IDs like 'routerOutlet' or 'routerOutlet-2' + // But even outlets with auto-generated IDs may need parent path computation + // if they have relative routes (indicating they're nested outlets) + const isRootOutlet = this.id.startsWith('routerOutlet'); + const needsParentPath = !isRootOutlet || hasRelativeRoutes || hasIndexRoute; + + if (needsParentPath) { + const result = computeParentPath({ + currentPathname, + outletMountPath: this.outletMountPath, + routeChildren, + hasRelativeRoutes, + hasIndexRoute, + hasWildcardRoute, + }); + + // Update the outlet mount path if it was set + if (result.outletMountPath && !this.outletMountPath) { + this.outletMountPath = result.outletMountPath; + } - // Update the outlet mount path if it was set - if (result.outletMountPath && !this.outletMountPath) { - this.outletMountPath = result.outletMountPath; + return result.parentPath; } - - return result.parentPath; } + return this.outletMountPath; } @@ -246,7 +254,9 @@ export class StackManager extends React.PureComponent { parentPath: string | undefined, leavingViewItem: ViewItem | undefined ): boolean { - if (this.id === 'routerOutlet' || parentPath !== undefined || !this.ionRouterOutlet) { + // Root outlets have IDs like 'routerOutlet' or 'routerOutlet-2' + const isRootOutlet = this.id.startsWith('routerOutlet'); + if (isRootOutlet || parentPath !== undefined || !this.ionRouterOutlet) { return false; } @@ -283,7 +293,9 @@ export class StackManager extends React.PureComponent { enteringViewItem: ViewItem | undefined, leavingViewItem: ViewItem | undefined ): boolean { - if (this.id === 'routerOutlet' || enteringRoute || enteringViewItem) { + // Root outlets have IDs like 'routerOutlet' or 'routerOutlet-2' + const isRootOutlet = this.id.startsWith('routerOutlet'); + if (isRootOutlet || enteringRoute || enteringViewItem) { return false; } @@ -943,7 +955,8 @@ function findRouteByRouteInfo(node: React.ReactNode, routeInfo: RouteInfo, paren // SIMPLIFIED: Trust React Router 6's matching more, compute relative path when parent is known if ((hasRelativeRoutes || hasIndexRoute) && parentPath) { const parentPrefix = parentPath.replace('/*', ''); - const normalizedParent = stripTrailingSlash(parentPrefix); + // Normalize both paths to start with '/' for consistent comparison + const normalizedParent = stripTrailingSlash(parentPrefix.startsWith('/') ? parentPrefix : `/${parentPrefix}`); const normalizedPathname = stripTrailingSlash(routeInfo.pathname); // Only compute relative path if pathname is within parent scope @@ -959,12 +972,29 @@ function findRouteByRouteInfo(node: React.ReactNode, routeInfo: RouteInfo, paren for (const child of sortedRoutes) { const childPath = child.props.path as string | undefined; const isAbsoluteRoute = childPath && childPath.startsWith('/'); + + // Determine which pathname to match against: + // - For absolute routes: use the original full pathname + // - For relative routes with a parent: use the computed relative pathname + // - For relative routes at root level (no parent): use the original pathname + // (matchPath will handle the relative-to-absolute normalization) const pathnameToMatch = isAbsoluteRoute ? originalPathname : relativePathnameToMatch; - // Only use derivePathnameToMatch for absolute routes or wildcard patterns; - // non-wildcard relative routes match directly against the computed relative pathname. + // Determine the path portion to match: + // - For absolute routes: use derivePathnameToMatch + // - For relative routes at root level (no parent): use original pathname + // directly since matchPath normalizes both path and pathname + // - For relative routes with parent: use derivePathnameToMatch for wildcards, + // or the computed relative pathname for non-wildcards let pathForMatch: string; - if (isAbsoluteRoute || (childPath && childPath.includes('*'))) { + if (isAbsoluteRoute) { + pathForMatch = derivePathnameToMatch(pathnameToMatch, childPath); + } else if (!parentPath && childPath) { + // Root-level relative route: use the full pathname and let matchPath + // handle the normalization (it adds '/' to both path and pathname) + pathForMatch = originalPathname; + } else if (childPath && childPath.includes('*')) { + // Relative wildcard route with parent path: use derivePathnameToMatch pathForMatch = derivePathnameToMatch(pathnameToMatch, childPath); } else { pathForMatch = pathnameToMatch; diff --git a/packages/react-router/src/ReactRouter/utils/pathMatching.ts b/packages/react-router/src/ReactRouter/utils/pathMatching.ts index 054a2333740..623564a407a 100644 --- a/packages/react-router/src/ReactRouter/utils/pathMatching.ts +++ b/packages/react-router/src/ReactRouter/utils/pathMatching.ts @@ -120,7 +120,10 @@ export const derivePathnameToMatch = (fullPathname: string, routePath?: string): const trimmedPath = fullPathname.startsWith('/') ? fullPathname.slice(1) : fullPathname; if (!trimmedPath) { - return ''; + // For root-level relative routes (pathname is "/" and routePath is relative), + // return the full pathname so matchPath can normalize both. + // This allows routes like at root level to work correctly. + return fullPathname; } const fullSegments = trimmedPath.split('/').filter(Boolean); diff --git a/packages/react-router/test/base/src/App.tsx b/packages/react-router/test/base/src/App.tsx index ccfb3264fad..090702dc0fe 100644 --- a/packages/react-router/test/base/src/App.tsx +++ b/packages/react-router/test/base/src/App.tsx @@ -71,7 +71,8 @@ const App: React.FC = () => { } /> } /> } /> - } /> + {/* Test root-level relative path - no leading slash */} + } /> diff --git a/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx b/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx index 1c22520da24..edeb61abe51 100644 --- a/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx +++ b/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx @@ -118,8 +118,7 @@ const RelativePaths: React.FC = () => { {/* Route with absolute path (has leading slash) - this should work */} } /> - {/* Routes with relative paths (no leading slash) - these should also work - but currently don't match in IonRouterOutlet */} + {/* Routes with relative paths (no leading slash) */} } /> } /> diff --git a/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js b/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js index 9f8599c0c46..32fa334e9b3 100644 --- a/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js +++ b/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js @@ -1,16 +1,9 @@ const port = 3000; /** - * Tests for relative path handling in IonRouterOutlet - * - * Issue: IonRouterOutlet doesn't handle relative paths (without leading slash) - * the same way React Router 6's Routes component does. - * - * In React Router 6, both of these should work identically: - * - } /> - * - } /> - * - * However, IonRouterOutlet only matches the first one (with leading slash). + * Tests for relative path handling in IonRouterOutlet. + * Verifies that routes with relative paths (no leading slash) work + * the same as absolute paths, matching React Router 6 behavior. */ describe('Relative Paths Tests', () => { it('should navigate to the relative paths home page', () => { @@ -27,8 +20,6 @@ describe('Relative Paths Tests', () => { }); it('should navigate to Page B (defined with relative path - no leading slash)', () => { - // This test verifies the bug - Page B route is defined as path="page-b" (no leading slash) - // It should work the same as path="/relative-paths/page-b" but currently doesn't cy.visit(`http://localhost:${port}/relative-paths`); cy.ionPageVisible('relative-paths-home'); cy.ionNav('ion-item', 'Go to Page B'); @@ -37,7 +28,6 @@ describe('Relative Paths Tests', () => { }); it('should navigate to Page C (defined with relative path - no leading slash)', () => { - // Another test for relative path handling cy.visit(`http://localhost:${port}/relative-paths`); cy.ionPageVisible('relative-paths-home'); cy.ionNav('ion-item', 'Go to Page C'); @@ -46,14 +36,12 @@ describe('Relative Paths Tests', () => { }); it('should navigate directly to Page B via URL', () => { - // Direct navigation to a page with a relative path route cy.visit(`http://localhost:${port}/relative-paths/page-b`); cy.ionPageVisible('relative-paths-page-b'); cy.get('[data-testid="page-b-content"]').should('contain', 'Page B'); }); it('should navigate directly to Page C via URL', () => { - // Direct navigation to a page with a relative path route cy.visit(`http://localhost:${port}/relative-paths/page-c`); cy.ionPageVisible('relative-paths-page-c'); cy.get('[data-testid="page-c-content"]').should('contain', 'Page C'); From 4e0be92484cb4f95cdd749f7b2ff97f458c65350 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 10 Dec 2025 14:33:21 -0800 Subject: [PATCH 3/4] chore(react-router): updating comment --- .../test/base/src/pages/relative-paths/RelativePaths.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx b/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx index edeb61abe51..b8a06c70b6b 100644 --- a/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx +++ b/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx @@ -18,10 +18,6 @@ import { Route } from 'react-router-dom'; * This test page verifies that IonRouterOutlet correctly handles * relative paths (paths without a leading slash) the same way * React Router 6's Routes component does. - * - * Issue: https://github.com/ionic-team/ionic-framework/issues/24177#issuecomment-3624311206 - * - Routes with path="help" should work the same as path="/help" - * - IonRouterOutlet should match relative paths correctly */ const RelativePathsHome: React.FC = () => { From f570837a6ede64b91860debf6ab699d2d6521815 Mon Sep 17 00:00:00 2001 From: ShaneK Date: Wed, 10 Dec 2025 16:28:05 -0800 Subject: [PATCH 4/4] chore(react-router): removing redundant tests --- .../pages/relative-paths/RelativePaths.tsx | 26 +------------------ .../base/tests/e2e/specs/relative-paths.cy.js | 14 ---------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx b/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx index edeb61abe51..26ef06bf072 100644 --- a/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx +++ b/packages/react-router/test/base/src/pages/relative-paths/RelativePaths.tsx @@ -43,9 +43,6 @@ const RelativePathsHome: React.FC = () => { Go to Page B (relative path route) - - Go to Page C (relative path route) - @@ -92,35 +89,14 @@ const PageB: React.FC = () => { ); }; -const PageC: React.FC = () => { - return ( - - - - - - - Page C - - - -
- This is Page C - another route defined with relative path -
-
-
- ); -}; - const RelativePaths: React.FC = () => { return ( {/* Route with absolute path (has leading slash) - this should work */} } /> - {/* Routes with relative paths (no leading slash) */} + {/* Route with relative path (no leading slash) */} } /> - } /> {/* Home route - using relative path */} } /> diff --git a/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js b/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js index 32fa334e9b3..b88e061c592 100644 --- a/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js +++ b/packages/react-router/test/base/tests/e2e/specs/relative-paths.cy.js @@ -27,26 +27,12 @@ describe('Relative Paths Tests', () => { cy.get('[data-testid="page-b-content"]').should('contain', 'Page B'); }); - it('should navigate to Page C (defined with relative path - no leading slash)', () => { - cy.visit(`http://localhost:${port}/relative-paths`); - cy.ionPageVisible('relative-paths-home'); - cy.ionNav('ion-item', 'Go to Page C'); - cy.ionPageVisible('relative-paths-page-c'); - cy.get('[data-testid="page-c-content"]').should('contain', 'Page C'); - }); - it('should navigate directly to Page B via URL', () => { cy.visit(`http://localhost:${port}/relative-paths/page-b`); cy.ionPageVisible('relative-paths-page-b'); cy.get('[data-testid="page-b-content"]').should('contain', 'Page B'); }); - it('should navigate directly to Page C via URL', () => { - cy.visit(`http://localhost:${port}/relative-paths/page-c`); - cy.ionPageVisible('relative-paths-page-c'); - cy.get('[data-testid="page-c-content"]').should('contain', 'Page C'); - }); - it('should navigate to Page B and back', () => { cy.visit(`http://localhost:${port}/relative-paths`); cy.ionPageVisible('relative-paths-home');