Skip to content

Commit 36fdf53

Browse files
committed
test(react-router): trying to make tests more reliable
1 parent bceeff6 commit 36fdf53

6 files changed

Lines changed: 56 additions & 24 deletions

File tree

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

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ import { extractRouteChildren, getRoutesChildren, isNavigateElement } from './ut
2828
const VIEW_UNMOUNT_DELAY_MS = 250;
2929

3030
/**
31-
* Delay in milliseconds to wait for an IonPage element to be mounted before
32-
* proceeding with a page transition.
31+
* Delay (ms) to wait for an IonPage to mount before proceeding with a
32+
* page transition. Only container routes (nested outlets with no direct
33+
* IonPage) actually hit this timeout; normal routes clear it early via
34+
* registerIonPage, so a larger value here doesn't affect the happy path.
3335
*/
34-
const ION_PAGE_WAIT_TIMEOUT_MS = 50;
36+
const ION_PAGE_WAIT_TIMEOUT_MS = 300;
3537

3638
interface StackManagerProps {
3739
routeInfo: RouteInfo;
@@ -1152,6 +1154,13 @@ export class StackManager extends React.PureComponent<StackManagerProps> {
11521154
progressAnimation,
11531155
animationBuilder: routeInfo.routeAnimation,
11541156
});
1157+
1158+
// Ensure entering page is visible after commit. The animation should
1159+
// have removed ion-page-invisible, but in slower environments the
1160+
// commit can resolve before the class is cleaned up.
1161+
if (!progressAnimation) {
1162+
enteringEl.classList.remove('ion-page-invisible');
1163+
}
11551164
};
11561165

11571166
const routerOutlet = this.routerOutletElement!;

packages/react-router/test/base/cypress.config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ export default defineConfig({
55
pageLoadTimeout: 6000000000,
66
screenshotOnRunFailure: false,
77
defaultCommandTimeout: 10000,
8+
retries: {
9+
runMode: 2,
10+
openMode: 0,
11+
},
812
fixturesFolder: 'tests/e2e/fixtures',
913
screenshotsFolder: 'tests/e2e/screenshots',
1014
videosFolder: 'tests/e2e/videos',

packages/react-router/test/base/tests/e2e/specs/index-param-priority.cy.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ describe('Index Param Priority', () => {
141141
cy.get('[data-testid="notfound-page-label"]').should('contain', 'Page not found');
142142

143143
cy.get('#back-to-index-from-notfound').click();
144+
cy.url().should('include', '/index-param-priority');
145+
cy.wait(300);
144146
cy.ionPageVisible('index-param-priority-index');
145147
cy.get('[data-testid="index-page-label"]').should('contain', 'This is the index page');
146148
});

packages/react-router/test/base/tests/e2e/specs/index-route-reuse.cy.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,10 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
2323

2424
// Switch to Tab 2
2525
cy.ionTabClick('Tab 2');
26+
cy.url().should('include', '/index-route-reuse/tab2');
2627
cy.ionPageVisible('irr-tab2-home');
2728
cy.get('[data-testid="irr-tab2-home-content"]').should('be.visible');
2829
cy.get('[data-testid="irr-tab2-home-content"]').should('contain', 'Tab 2 Index Route Content');
29-
30-
// Verify URL changed to tab2
31-
cy.url().should('include', '/index-route-reuse/tab2');
3230
});
3331

3432
it('should show tab3 index content when switching to tab3', () => {
@@ -37,12 +35,10 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
3735

3836
// Switch to Tab 3
3937
cy.ionTabClick('Tab 3');
38+
cy.url().should('include', '/index-route-reuse/tab3');
4039
cy.ionPageVisible('irr-tab3-home');
4140
cy.get('[data-testid="irr-tab3-home-content"]').should('be.visible');
4241
cy.get('[data-testid="irr-tab3-home-content"]').should('contain', 'Tab 3 Index Route Content');
43-
44-
// Verify URL changed to tab3
45-
cy.url().should('include', '/index-route-reuse/tab3');
4642
});
4743

4844
it('should correctly show each tab index when cycling through all tabs', () => {
@@ -52,18 +48,21 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
5248

5349
// Tab 1 -> Tab 2
5450
cy.ionTabClick('Tab 2');
51+
cy.url().should('include', '/index-route-reuse/tab2');
5552
cy.ionPageVisible('irr-tab2-home');
5653
cy.get('[data-testid="irr-tab2-home-content"]').should('be.visible');
5754
cy.get('[data-testid="irr-tab2-home-content"]').should('contain', 'Tab 2 Index Route Content');
5855

5956
// Tab 2 -> Tab 3
6057
cy.ionTabClick('Tab 3');
58+
cy.url().should('include', '/index-route-reuse/tab3');
6159
cy.ionPageVisible('irr-tab3-home');
6260
cy.get('[data-testid="irr-tab3-home-content"]').should('be.visible');
6361
cy.get('[data-testid="irr-tab3-home-content"]').should('contain', 'Tab 3 Index Route Content');
6462

6563
// Tab 3 -> Tab 1 (back to start)
6664
cy.ionTabClick('Tab 1');
65+
cy.url().should('include', '/index-route-reuse/tab1');
6766
cy.ionPageVisible('irr-tab1-home');
6867
cy.get('[data-testid="irr-tab1-home-content"]').should('be.visible');
6968
cy.get('[data-testid="irr-tab1-home-content"]').should('contain', 'Tab 1 Index Route Content');
@@ -80,11 +79,13 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
8079

8180
// Switch to Tab 2
8281
cy.ionTabClick('Tab 2');
82+
cy.url().should('include', '/index-route-reuse/tab2');
8383
cy.ionPageVisible('irr-tab2-home');
8484
cy.get('[data-testid="irr-tab2-home-content"]').should('be.visible');
8585

8686
// Switch back to Tab 1 - should show detail (preserved history)
8787
cy.ionTabClick('Tab 1');
88+
cy.url().should('include', '/index-route-reuse/tab1');
8889
cy.ionPageVisible('irr-tab1-detail');
8990
cy.get('[data-testid="irr-tab1-detail-content"]').should('be.visible');
9091
});
@@ -95,17 +96,21 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
9596

9697
// Rapid switching: Tab1 -> Tab2 -> Tab3 -> Tab2 -> Tab1
9798
cy.ionTabClick('Tab 2');
99+
cy.url().should('include', '/index-route-reuse/tab2');
98100
cy.ionPageVisible('irr-tab2-home');
99101

100102
cy.ionTabClick('Tab 3');
103+
cy.url().should('include', '/index-route-reuse/tab3');
101104
cy.ionPageVisible('irr-tab3-home');
102105

103106
cy.ionTabClick('Tab 2');
107+
cy.url().should('include', '/index-route-reuse/tab2');
104108
cy.ionPageVisible('irr-tab2-home');
105109
cy.get('[data-testid="irr-tab2-home-content"]').should('be.visible');
106110
cy.get('[data-testid="irr-tab2-home-content"]').should('contain', 'Tab 2 Index Route Content');
107111

108112
cy.ionTabClick('Tab 1');
113+
cy.url().should('include', '/index-route-reuse/tab1');
109114
cy.ionPageVisible('irr-tab1-home');
110115
cy.get('[data-testid="irr-tab1-home-content"]').should('be.visible');
111116
cy.get('[data-testid="irr-tab1-home-content"]').should('contain', 'Tab 1 Index Route Content');

packages/react-router/test/base/tests/e2e/specs/nonlinear-forward.cy.js

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@ describe('Non-linear POP Forward Navigation', () => {
1717

1818
// Browser back - this is a non-linear POP because settings route has no pushedByRoute.
1919
// The else branch should push the current location key onto forwardStack.
20-
cy.go('back');
20+
cy.ionGoBack('/routing/tabs/home/details/1');
2121
cy.ionPageVisible('home-details-page-1');
2222
cy.get('ion-tab-button.tab-selected').contains('Home');
2323

2424
// Browser forward - should be detected as forward navigation via forwardStack.
2525
// Without the fix, forwardStack is empty so this falls into the wrong branch
2626
// (else-if, treating it as back navigation with wrong animation).
27-
cy.go('forward');
28-
cy.wait(500);
27+
cy.ionGoForward('/routing/tabs/settings');
2928
cy.ionPageVisible('settings-page');
3029
cy.get('ion-tab-button.tab-selected').contains('Settings');
3130
});
@@ -43,27 +42,25 @@ describe('Non-linear POP Forward Navigation', () => {
4342
cy.ionPageVisible('settings-page');
4443

4544
// Browser back (non-linear POP)
46-
cy.go('back');
45+
cy.ionGoBack('/routing/tabs/home/details/1');
4746
cy.ionPageVisible('home-details-page-1');
4847

4948
// Browser forward
50-
cy.go('forward');
51-
cy.wait(500);
49+
cy.ionGoForward('/routing/tabs/settings');
5250
cy.ionPageVisible('settings-page');
5351

5452
// Browser back again - without the fix, the forward stack is corrupted from
5553
// the previous misclassification, causing this back to be treated as forward.
56-
cy.go('back');
54+
cy.ionGoBack('/routing/tabs/home/details/1');
5755
cy.ionPageVisible('home-details-page-1');
5856
cy.get('ion-tab-button.tab-selected').contains('Home');
5957

6058
// One more forward/back cycle to verify stack integrity
61-
cy.go('forward');
62-
cy.wait(500);
59+
cy.ionGoForward('/routing/tabs/settings');
6360
cy.ionPageVisible('settings-page');
6461
cy.get('ion-tab-button.tab-selected').contains('Settings');
6562

66-
cy.go('back');
63+
cy.ionGoBack('/routing/tabs/home/details/1');
6764
cy.ionPageVisible('home-details-page-1');
6865
cy.get('ion-tab-button.tab-selected').contains('Home');
6966
});
@@ -81,22 +78,21 @@ describe('Non-linear POP Forward Navigation', () => {
8178
cy.ionPageVisible('settings-page');
8279

8380
// Browser back (non-linear POP)
84-
cy.go('back');
81+
cy.ionGoBack('/routing/tabs/home/details/1');
8582
cy.ionPageVisible('home-details-page-1');
8683

8784
// Browser forward to Settings
88-
cy.go('forward');
89-
cy.wait(500);
85+
cy.ionGoForward('/routing/tabs/settings');
9086
cy.ionPageVisible('settings-page');
9187

9288
// Browser back to D1
93-
cy.go('back');
89+
cy.ionGoBack('/routing/tabs/home/details/1');
9490
cy.ionPageVisible('home-details-page-1');
9591

9692
// Browser back to Home. The D1 route lost its pushedByRoute when it was
9793
// recreated via a non-linear POP, so this back also goes through the
9894
// non-linear else branch.
99-
cy.go('back');
95+
cy.ionGoBack('/routing/tabs/home');
10096
cy.ionPageVisible('home-page');
10197
cy.contains('[data-pageid=home-page]', '"routeAction":"pop"');
10298
cy.contains('[data-pageid=home-page]', '"pathname":"/routing/tabs/home"');

packages/react-router/test/base/tests/e2e/support/commands.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,22 @@ Cypress.Commands.add('ionTabClick', (tabText) => {
8989
cy.contains('ion-tab-button', tabText).click({ force: true });
9090
});
9191

92+
Cypress.Commands.add('ionGoBack', (expectedUrlPart) => {
93+
cy.go('back');
94+
if (expectedUrlPart) {
95+
cy.url().should('include', expectedUrlPart);
96+
}
97+
cy.wait(300);
98+
});
99+
100+
Cypress.Commands.add('ionGoForward', (expectedUrlPart) => {
101+
cy.go('forward');
102+
if (expectedUrlPart) {
103+
cy.url().should('include', expectedUrlPart);
104+
}
105+
cy.wait(300);
106+
});
107+
92108
Cypress.Commands.add('ionBackClick', (pageId) => {
93109
cy.get(`div.ion-page[data-pageid=${pageId}]`)
94110
.should('be.visible', true)

0 commit comments

Comments
 (0)