test(react-router): trying to make tests more reliable

This commit is contained in:
ShaneK
2026-03-12 18:11:42 -07:00
parent bceeff65f4
commit beedc8eced
6 changed files with 49 additions and 24 deletions

View File

@@ -28,10 +28,12 @@ import { extractRouteChildren, getRoutesChildren, isNavigateElement } from './ut
const VIEW_UNMOUNT_DELAY_MS = 250;
/**
* Delay in milliseconds to wait for an IonPage element to be mounted before
* proceeding with a page transition.
* Delay (ms) to wait for an IonPage to mount before proceeding with a
* page transition. Only container routes (nested outlets with no direct
* IonPage) actually hit this timeout; normal routes clear it early via
* registerIonPage, so a larger value here doesn't affect the happy path.
*/
const ION_PAGE_WAIT_TIMEOUT_MS = 50;
const ION_PAGE_WAIT_TIMEOUT_MS = 300;
interface StackManagerProps {
routeInfo: RouteInfo;

View File

@@ -5,6 +5,10 @@ export default defineConfig({
pageLoadTimeout: 6000000000,
screenshotOnRunFailure: false,
defaultCommandTimeout: 10000,
retries: {
runMode: 2,
openMode: 0,
},
fixturesFolder: 'tests/e2e/fixtures',
screenshotsFolder: 'tests/e2e/screenshots',
videosFolder: 'tests/e2e/videos',

View File

@@ -141,6 +141,8 @@ describe('Index Param Priority', () => {
cy.get('[data-testid="notfound-page-label"]').should('contain', 'Page not found');
cy.get('#back-to-index-from-notfound').click();
cy.url().should('include', '/index-param-priority');
cy.wait(300);
cy.ionPageVisible('index-param-priority-index');
cy.get('[data-testid="index-page-label"]').should('contain', 'This is the index page');
});

View File

@@ -23,12 +23,10 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
// Switch to Tab 2
cy.ionTabClick('Tab 2');
cy.url().should('include', '/index-route-reuse/tab2');
cy.ionPageVisible('irr-tab2-home');
cy.get('[data-testid="irr-tab2-home-content"]').should('be.visible');
cy.get('[data-testid="irr-tab2-home-content"]').should('contain', 'Tab 2 Index Route Content');
// Verify URL changed to tab2
cy.url().should('include', '/index-route-reuse/tab2');
});
it('should show tab3 index content when switching to tab3', () => {
@@ -37,12 +35,10 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
// Switch to Tab 3
cy.ionTabClick('Tab 3');
cy.url().should('include', '/index-route-reuse/tab3');
cy.ionPageVisible('irr-tab3-home');
cy.get('[data-testid="irr-tab3-home-content"]').should('be.visible');
cy.get('[data-testid="irr-tab3-home-content"]').should('contain', 'Tab 3 Index Route Content');
// Verify URL changed to tab3
cy.url().should('include', '/index-route-reuse/tab3');
});
it('should correctly show each tab index when cycling through all tabs', () => {
@@ -52,18 +48,21 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
// Tab 1 -> Tab 2
cy.ionTabClick('Tab 2');
cy.url().should('include', '/index-route-reuse/tab2');
cy.ionPageVisible('irr-tab2-home');
cy.get('[data-testid="irr-tab2-home-content"]').should('be.visible');
cy.get('[data-testid="irr-tab2-home-content"]').should('contain', 'Tab 2 Index Route Content');
// Tab 2 -> Tab 3
cy.ionTabClick('Tab 3');
cy.url().should('include', '/index-route-reuse/tab3');
cy.ionPageVisible('irr-tab3-home');
cy.get('[data-testid="irr-tab3-home-content"]').should('be.visible');
cy.get('[data-testid="irr-tab3-home-content"]').should('contain', 'Tab 3 Index Route Content');
// Tab 3 -> Tab 1 (back to start)
cy.ionTabClick('Tab 1');
cy.url().should('include', '/index-route-reuse/tab1');
cy.ionPageVisible('irr-tab1-home');
cy.get('[data-testid="irr-tab1-home-content"]').should('be.visible');
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', () => {
// Switch to Tab 2
cy.ionTabClick('Tab 2');
cy.url().should('include', '/index-route-reuse/tab2');
cy.ionPageVisible('irr-tab2-home');
cy.get('[data-testid="irr-tab2-home-content"]').should('be.visible');
// Switch back to Tab 1 - should show detail (preserved history)
cy.ionTabClick('Tab 1');
cy.url().should('include', '/index-route-reuse/tab1');
cy.ionPageVisible('irr-tab1-detail');
cy.get('[data-testid="irr-tab1-detail-content"]').should('be.visible');
});
@@ -95,17 +96,21 @@ describe('Index Route Reuse - Nested Outlet Index Routes', () => {
// Rapid switching: Tab1 -> Tab2 -> Tab3 -> Tab2 -> Tab1
cy.ionTabClick('Tab 2');
cy.url().should('include', '/index-route-reuse/tab2');
cy.ionPageVisible('irr-tab2-home');
cy.ionTabClick('Tab 3');
cy.url().should('include', '/index-route-reuse/tab3');
cy.ionPageVisible('irr-tab3-home');
cy.ionTabClick('Tab 2');
cy.url().should('include', '/index-route-reuse/tab2');
cy.ionPageVisible('irr-tab2-home');
cy.get('[data-testid="irr-tab2-home-content"]').should('be.visible');
cy.get('[data-testid="irr-tab2-home-content"]').should('contain', 'Tab 2 Index Route Content');
cy.ionTabClick('Tab 1');
cy.url().should('include', '/index-route-reuse/tab1');
cy.ionPageVisible('irr-tab1-home');
cy.get('[data-testid="irr-tab1-home-content"]').should('be.visible');
cy.get('[data-testid="irr-tab1-home-content"]').should('contain', 'Tab 1 Index Route Content');

View File

@@ -17,15 +17,14 @@ describe('Non-linear POP Forward Navigation', () => {
// Browser back - this is a non-linear POP because settings route has no pushedByRoute.
// The else branch should push the current location key onto forwardStack.
cy.go('back');
cy.ionGoBack('/routing/tabs/home/details/1');
cy.ionPageVisible('home-details-page-1');
cy.get('ion-tab-button.tab-selected').contains('Home');
// Browser forward - should be detected as forward navigation via forwardStack.
// Without the fix, forwardStack is empty so this falls into the wrong branch
// (else-if, treating it as back navigation with wrong animation).
cy.go('forward');
cy.wait(500);
cy.ionGoForward('/routing/tabs/settings');
cy.ionPageVisible('settings-page');
cy.get('ion-tab-button.tab-selected').contains('Settings');
});
@@ -43,27 +42,25 @@ describe('Non-linear POP Forward Navigation', () => {
cy.ionPageVisible('settings-page');
// Browser back (non-linear POP)
cy.go('back');
cy.ionGoBack('/routing/tabs/home/details/1');
cy.ionPageVisible('home-details-page-1');
// Browser forward
cy.go('forward');
cy.wait(500);
cy.ionGoForward('/routing/tabs/settings');
cy.ionPageVisible('settings-page');
// Browser back again - without the fix, the forward stack is corrupted from
// the previous misclassification, causing this back to be treated as forward.
cy.go('back');
cy.ionGoBack('/routing/tabs/home/details/1');
cy.ionPageVisible('home-details-page-1');
cy.get('ion-tab-button.tab-selected').contains('Home');
// One more forward/back cycle to verify stack integrity
cy.go('forward');
cy.wait(500);
cy.ionGoForward('/routing/tabs/settings');
cy.ionPageVisible('settings-page');
cy.get('ion-tab-button.tab-selected').contains('Settings');
cy.go('back');
cy.ionGoBack('/routing/tabs/home/details/1');
cy.ionPageVisible('home-details-page-1');
cy.get('ion-tab-button.tab-selected').contains('Home');
});
@@ -81,22 +78,21 @@ describe('Non-linear POP Forward Navigation', () => {
cy.ionPageVisible('settings-page');
// Browser back (non-linear POP)
cy.go('back');
cy.ionGoBack('/routing/tabs/home/details/1');
cy.ionPageVisible('home-details-page-1');
// Browser forward to Settings
cy.go('forward');
cy.wait(500);
cy.ionGoForward('/routing/tabs/settings');
cy.ionPageVisible('settings-page');
// Browser back to D1
cy.go('back');
cy.ionGoBack('/routing/tabs/home/details/1');
cy.ionPageVisible('home-details-page-1');
// Browser back to Home. The D1 route lost its pushedByRoute when it was
// recreated via a non-linear POP, so this back also goes through the
// non-linear else branch.
cy.go('back');
cy.ionGoBack('/routing/tabs/home');
cy.ionPageVisible('home-page');
cy.contains('[data-pageid=home-page]', '"routeAction":"pop"');
cy.contains('[data-pageid=home-page]', '"pathname":"/routing/tabs/home"');

View File

@@ -89,6 +89,22 @@ Cypress.Commands.add('ionTabClick', (tabText) => {
cy.contains('ion-tab-button', tabText).click({ force: true });
});
Cypress.Commands.add('ionGoBack', (expectedUrlPart) => {
cy.go('back');
if (expectedUrlPart) {
cy.url().should('include', expectedUrlPart);
}
cy.wait(300);
});
Cypress.Commands.add('ionGoForward', (expectedUrlPart) => {
cy.go('forward');
if (expectedUrlPart) {
cy.url().should('include', expectedUrlPart);
}
cy.wait(300);
});
Cypress.Commands.add('ionBackClick', (pageId) => {
cy.get(`div.ion-page[data-pageid=${pageId}]`)
.should('be.visible', true)