diff --git a/e2e/pages/supersync.page.ts b/e2e/pages/supersync.page.ts index 087d869d5..fe4b21ea5 100644 --- a/e2e/pages/supersync.page.ts +++ b/e2e/pages/supersync.page.ts @@ -137,6 +137,12 @@ export class SuperSyncPage extends BasePage { const dialogContainer = this.page.locator('mat-dialog-container'); await dialogContainer.waitFor({ state: 'visible', timeout: 5000 }); + // Wait for formly form to initialize inside dialog + // This ensures the form structure is ready before interacting with fields + await this.page + .locator('mat-dialog-container formly-form') + .waitFor({ state: 'visible', timeout: 5000 }); + // Wait for the formly form to be rendered inside the dialog // Under heavy load, the dialog may appear but form rendering is delayed await this.providerSelect.waitFor({ state: 'visible', timeout: 5000 }); @@ -225,8 +231,19 @@ export class SuperSyncPage extends BasePage { intervals: [500, 1000, 1500, 2000], }); + // Wait for formly to re-render SuperSync-specific fields after provider selection + // The hideExpression on these fields triggers a re-render that needs time to complete + await this.page.waitForLoadState('networkidle').catch(() => {}); + await this.page.waitForTimeout(500); + // Fill Access Token first (it's outside the collapsible) - await this.accessTokenInput.waitFor({ state: 'visible' }); + // Use toPass() to handle slow formly rendering of the textarea + await expect(async () => { + await this.accessTokenInput.waitFor({ state: 'visible', timeout: 3000 }); + }).toPass({ + timeout: 15000, + intervals: [500, 1000, 1500, 2000], + }); await this.accessTokenInput.fill(config.accessToken); // Expand "Advanced settings" collapsible to access baseUrl and encryption fields diff --git a/e2e/utils/waits.ts b/e2e/utils/waits.ts index b2d47ad81..440b5b01d 100644 --- a/e2e/utils/waits.ts +++ b/e2e/utils/waits.ts @@ -79,8 +79,17 @@ export const waitForAppReady = async ( } // Wait for route to match (if required) + // Use longer timeout with retry for slow-loading apps (especially second client) if (ensureRoute) { - await page.waitForURL(routeRegex, { timeout: 15000 }); + try { + await page.waitForURL(routeRegex, { timeout: 20000 }); + } catch { + // If route doesn't match, try refreshing once and waiting again + console.log('[waitForAppReady] Route timeout, attempting reload...'); + await page.reload(); + await page.waitForLoadState('domcontentloaded'); + await page.waitForURL(routeRegex, { timeout: 15000 }); + } } // Wait for main route wrapper to be visible (indicates app shell loaded)