Skip to content

Commit 1d33df4

Browse files
committed
fix(react-router): maintain can-go-back class on nested outlet re-navigation
1 parent 7da275a commit 1d33df4

2 files changed

Lines changed: 98 additions & 0 deletions

File tree

packages/react-router/src/ReactRouter/StackManager.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,15 @@ export class StackManager extends React.PureComponent<StackManagerProps> {
410410
if (enteringEl) {
411411
showIonPageElement(enteringEl);
412412
enteringEl.classList.remove('ion-page-invisible');
413+
414+
// Maintain can-go-back state since we skip transitionPage/commit.
415+
// Without this, the back button disappears on re-navigation to a
416+
// parameterized route within a nested outlet (e.g. welcome -> item -> back -> item).
417+
if (routeInfo.pushedByRoute) {
418+
enteringEl.classList.add('can-go-back');
419+
} else {
420+
enteringEl.classList.remove('can-go-back');
421+
}
413422
}
414423

415424
this.forceUpdate();
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { test, expect } from '@playwright/test';
2+
import { ionPageVisible, ionNav, ionGoBack, withTestingMode } from './utils/test-utils';
3+
4+
/**
5+
* Regression tests for navigating from a nested outlet child page to a different
6+
* nested outlet's child page, going back, then navigating forward again.
7+
*
8+
* Bug: navigating from /nested-outlet2/home/welcome to /nested-outlet2/list/1,
9+
* going back, then clicking "Go to first item" again would show the Item page
10+
* but without the back button (can-go-back class missing on the IonPage wrapper).
11+
*
12+
* Root cause: when entering === leaving view (same parameterized route re-navigated),
13+
* handleReadyEnteringView skipped transitionPage/commit, so can-go-back was never set.
14+
*/
15+
test.describe('Nested outlet 2: revisit cross-outlet navigation', () => {
16+
test('back button should appear on second forward navigation (no animations)', async ({ page }) => {
17+
await page.goto(withTestingMode('/nested-outlet2/home/welcome'));
18+
await ionPageVisible(page, 'welcome');
19+
20+
// First navigation: Welcome -> Item #1
21+
await ionNav(page, 'ion-item', 'Go to first item');
22+
await ionPageVisible(page, 'item');
23+
await expect(page).toHaveURL(/nested-outlet2\/list\/1/);
24+
25+
// Back button should be visible the first time
26+
const backBtn = page.locator('[data-pageid="item"] ion-back-button');
27+
await expect(backBtn).toBeVisible();
28+
29+
// Go back to Welcome
30+
await ionGoBack(page, 'nested-outlet2/home/welcome');
31+
await ionPageVisible(page, 'welcome');
32+
33+
// Second navigation: Welcome -> Item #1 again
34+
await ionNav(page, 'ion-item', 'Go to first item');
35+
await ionPageVisible(page, 'item');
36+
await expect(page).toHaveURL(/nested-outlet2\/list\/1/);
37+
38+
// Back button must still be visible the second time
39+
await expect(backBtn).toBeVisible();
40+
});
41+
42+
test('back button should appear on second forward navigation (with animations)', async ({ page }) => {
43+
await page.goto('/nested-outlet2/home/welcome');
44+
await ionPageVisible(page, 'welcome');
45+
46+
// First navigation: Welcome -> Item #1
47+
await ionNav(page, 'ion-item', 'Go to first item');
48+
await page.waitForTimeout(500);
49+
await ionPageVisible(page, 'item');
50+
await expect(page).toHaveURL(/nested-outlet2\/list\/1/);
51+
52+
// Back button should be visible the first time
53+
const backBtn = page.locator('[data-pageid="item"] ion-back-button');
54+
await expect(backBtn).toBeVisible();
55+
56+
// Go back to Welcome via browser back
57+
await page.goBack();
58+
await page.waitForTimeout(500);
59+
await ionPageVisible(page, 'welcome');
60+
61+
// Second navigation: Welcome -> Item #1 again
62+
await ionNav(page, 'ion-item', 'Go to first item');
63+
await page.waitForTimeout(500);
64+
await ionPageVisible(page, 'item');
65+
await expect(page).toHaveURL(/nested-outlet2\/list\/1/);
66+
67+
// Back button must still be visible the second time
68+
await expect(backBtn).toBeVisible();
69+
});
70+
71+
test('should load list page on second forward navigation from welcome', async ({ page }) => {
72+
await page.goto(withTestingMode('/nested-outlet2/home/welcome'));
73+
await ionPageVisible(page, 'welcome');
74+
75+
// First navigation: Welcome -> List
76+
await ionNav(page, 'ion-item', 'Go to list from Welcome');
77+
await ionPageVisible(page, 'list');
78+
await expect(page).toHaveURL(/nested-outlet2\/list/);
79+
80+
// Go back to Welcome
81+
await ionGoBack(page, 'nested-outlet2/home/welcome');
82+
await ionPageVisible(page, 'welcome');
83+
84+
// Second navigation: Welcome -> List again
85+
await ionNav(page, 'ion-item', 'Go to list from Welcome');
86+
await ionPageVisible(page, 'list');
87+
await expect(page).toHaveURL(/nested-outlet2\/list/);
88+
});
89+
});

0 commit comments

Comments
 (0)