diff --git a/frontend/e2e/pages/web-terminal-config-page.ts b/frontend/e2e/pages/web-terminal-config-page.ts index 1df2ff15c49..ac90ea30a8c 100644 --- a/frontend/e2e/pages/web-terminal-config-page.ts +++ b/frontend/e2e/pages/web-terminal-config-page.ts @@ -14,7 +14,7 @@ export class WebTerminalConfigPage extends BasePage { async navigateToWebTerminalConfig(): Promise { await this.goTo('/k8s/cluster/operator.openshift.io~v1~Console/cluster'); - await this.waitForLoadingComplete(10_000); + await this.waitForLoadingComplete(30_000); const customizeButton = this.page.getByRole('button', { name: 'Customize' }); // eslint-disable-next-line no-restricted-syntax await customizeButton @@ -25,17 +25,17 @@ export class WebTerminalConfigPage extends BasePage { await this.robustClick(customizeButton.first()); } else { const actionsMenu = this.page.getByTestId('actions-menu-button'); - await this.robustClick(actionsMenu); + await this.robustClick(actionsMenu, { timeout: 60_000 }); const customizeAction = this.page.locator('[data-test-action="Customize"]:not([disabled])'); await this.robustClick(customizeAction); } - await this.waitForLoadingComplete(10_000); + await this.waitForLoadingComplete(30_000); await this.clickWebTerminalTab(); } async clickWebTerminalTab(): Promise { const tab = this.page.getByRole('tab', { name: 'Web Terminal' }); - await this.robustClick(tab, { timeout: 60_000 }); + await this.robustClick(tab, { timeout: 60_000, retries: 1 }); await this.waitForLoadingComplete(5_000); } diff --git a/frontend/e2e/pages/web-terminal-page.ts b/frontend/e2e/pages/web-terminal-page.ts index b810bd8e04e..70056e02e6e 100644 --- a/frontend/e2e/pages/web-terminal-page.ts +++ b/frontend/e2e/pages/web-terminal-page.ts @@ -26,26 +26,12 @@ export class WebTerminalPage extends BasePage { private readonly closeTerminalButton = this.page.getByLabel(/Close terminal/); private readonly inactivityMessageArea = this.page.locator('div.co-cloudshell-exec__error-msg'); - async waitForTerminalIconVisible(maxRetries = 10): Promise { + async waitForTerminalIconVisible(): Promise { await warmupSPA(this.page); - try { - // eslint-disable-next-line no-restricted-syntax - await this.terminalIcon.waitFor({ state: 'visible', timeout: 30_000 }); - return; - } catch { - // Icon not visible on first load — retry with reloads - } - for (let attempt = 0; attempt < maxRetries; attempt++) { - await this.page.reload(); - try { - // eslint-disable-next-line no-restricted-syntax - await this.terminalIcon.waitFor({ state: 'visible', timeout: 15_000 }); - return; - } catch { - // Retry - } - } - throw new Error(`Terminal icon not visible after ${maxRetries} retries`); + await expect(async () => { + await this.page.reload({ waitUntil: 'domcontentloaded' }); + await expect(this.terminalIcon).toBeVisible({ timeout: 15_000 }); + }).toPass({ intervals: [2_000, 5_000, 10_000], timeout: 120_000 }); } async clickTerminalIcon(): Promise { @@ -54,7 +40,7 @@ export class WebTerminalPage extends BasePage { await this.loadingBox.waitFor({ state: 'detached', timeout: 60_000 }).catch(() => {}); } - async waitForTerminalWindow(timeoutMs = 60_000): Promise { + async waitForTerminalWindow(timeoutMs = 120_000): Promise { await expect(this.terminalContainer).toBeVisible({ timeout: timeoutMs }); await expect(this.terminalWindow).toBeVisible({ timeout: timeoutMs }); } diff --git a/frontend/e2e/setup/admin-auth.setup.ts b/frontend/e2e/setup/admin-auth.setup.ts index 54f64063583..ad3a9554461 100644 --- a/frontend/e2e/setup/admin-auth.setup.ts +++ b/frontend/e2e/setup/admin-auth.setup.ts @@ -2,17 +2,14 @@ import * as path from 'path'; import { test as setup } from '@playwright/test'; -import { performLogin, saveStorageState } from './login-helper'; +import { getAdminCredentials, performLogin, saveStorageState } from './login-helper'; const adminStorageState = path.resolve(import.meta.dirname, '..', '.auth', 'kubeadmin.json'); setup('login as kubeadmin', async ({ page }) => { setup.skip(process.env.SKIP_GLOBAL_SETUP === 'true', 'SKIP_GLOBAL_SETUP is set'); - const baseURL = process.env.WEB_CONSOLE_URL || 'http://localhost:9000'; - const username = process.env.OPENSHIFT_USERNAME || 'kubeadmin'; - const password = process.env.BRIDGE_KUBEADMIN_PASSWORD || ''; - - await performLogin(page, baseURL, username, password, 'kube:admin'); + const { username, password, idpName } = getAdminCredentials(); + await performLogin(page, username, password, idpName); await saveStorageState(page, adminStorageState); }); diff --git a/frontend/e2e/setup/developer-auth.setup.ts b/frontend/e2e/setup/developer-auth.setup.ts index 328139b4b74..f3ed714a26d 100644 --- a/frontend/e2e/setup/developer-auth.setup.ts +++ b/frontend/e2e/setup/developer-auth.setup.ts @@ -2,21 +2,16 @@ import * as path from 'path'; import { test as setup } from '@playwright/test'; -import { performLogin, saveStorageState } from './login-helper'; +import { getDeveloperCredentials, performLogin, saveStorageState } from './login-helper'; const developerStorageState = path.resolve(import.meta.dirname, '..', '.auth', 'developer.json'); setup('login as developer', async ({ page }) => { setup.skip(process.env.SKIP_GLOBAL_SETUP === 'true', 'SKIP_GLOBAL_SETUP is set'); - const htpasswdUser = process.env.BRIDGE_HTPASSWD_USERNAME; - const htpasswdPass = process.env.BRIDGE_HTPASSWD_PASSWORD; + const creds = getDeveloperCredentials(); + setup.skip(!creds, 'No developer credentials configured'); - setup.skip(!htpasswdUser || !htpasswdPass, 'No developer credentials configured'); - - const baseURL = process.env.WEB_CONSOLE_URL || 'http://localhost:9000'; - const htpasswdIdp = process.env.BRIDGE_HTPASSWD_IDP || htpasswdUser!; - - await performLogin(page, baseURL, htpasswdUser!, htpasswdPass!, htpasswdIdp); + await performLogin(page, creds!.username, creds!.password, creds!.idpName); await saveStorageState(page, developerStorageState); }); diff --git a/frontend/e2e/setup/login-helper.ts b/frontend/e2e/setup/login-helper.ts index a05875dc50a..459edb7dd56 100644 --- a/frontend/e2e/setup/login-helper.ts +++ b/frontend/e2e/setup/login-helper.ts @@ -6,14 +6,40 @@ import { expect } from '@playwright/test'; const STORAGE_STATE_DIR = path.resolve(import.meta.dirname, '..', '.auth'); +export function getBaseURL(): string { + return process.env.WEB_CONSOLE_URL || 'http://localhost:9000'; +} + +export function getAdminCredentials(): { username: string; password: string; idpName: string } { + return { + username: process.env.OPENSHIFT_USERNAME || 'kubeadmin', + password: process.env.BRIDGE_KUBEADMIN_PASSWORD || '', + idpName: 'kube:admin', + }; +} + +export function getDeveloperCredentials(): { + username: string; + password: string; + idpName: string; +} | null { + const username = process.env.BRIDGE_HTPASSWD_USERNAME; + const password = process.env.BRIDGE_HTPASSWD_PASSWORD; + if (!username || !password) return null; + return { + username, + password, + idpName: process.env.BRIDGE_HTPASSWD_IDP || username, + }; +} + export async function performLogin( page: Page, - baseURL: string, username: string, password: string, idpName?: string, ): Promise { - await page.goto(baseURL, { timeout: 90_000, waitUntil: 'domcontentloaded' }); + await page.goto(getBaseURL(), { timeout: 90_000, waitUntil: 'domcontentloaded' }); const authDisabled = await page .evaluate(() => (window as any).SERVER_FLAGS?.authDisabled) diff --git a/frontend/e2e/tests/webterminal/developer/web-terminal-basic.spec.ts b/frontend/e2e/tests/webterminal/developer/web-terminal-basic.spec.ts index d6dabcbfdfd..24d43a86a5a 100644 --- a/frontend/e2e/tests/webterminal/developer/web-terminal-basic.spec.ts +++ b/frontend/e2e/tests/webterminal/developer/web-terminal-basic.spec.ts @@ -24,6 +24,7 @@ test.describe('Web Terminal basic user', () => { }); test('open terminal with advanced timeout', async ({ page }) => { + test.slow(); const webTerminal = new WebTerminalPage(page); await test.step('Open terminal with 1-minute timeout', async () => { @@ -45,6 +46,7 @@ test.describe('Web Terminal basic user', () => { }); test('verify Open in new tab button', async ({ page }) => { + test.slow(); const webTerminal = new WebTerminalPage(page); await test.step('Wait for terminal icon and open terminal', async () => { diff --git a/frontend/e2e/tests/webterminal/developer/web-terminal-devuser.spec.ts b/frontend/e2e/tests/webterminal/developer/web-terminal-devuser.spec.ts index e816ae011ad..498c08274c6 100644 --- a/frontend/e2e/tests/webterminal/developer/web-terminal-devuser.spec.ts +++ b/frontend/e2e/tests/webterminal/developer/web-terminal-devuser.spec.ts @@ -54,6 +54,7 @@ test.describe('Web Terminal for Developer user', () => { test( 'create new project and use Web Terminal', async ({ page, k8sClient, cleanup }) => { + test.slow(); const webTerminal = new WebTerminalPage(page); cleanup.trackNamespace(NEW_PROJECT); @@ -88,6 +89,7 @@ test.describe('Web Terminal for Developer user', () => { // eslint-disable-next-line playwright/expect-expect test('open Web Terminal for existing project', async ({ page, k8sClient }) => { + test.slow(); const webTerminal = new WebTerminalPage(page); await test.step('Wait for terminal icon and open terminal', async () => { diff --git a/frontend/e2e/tests/webterminal/web-terminal-admin.spec.ts b/frontend/e2e/tests/webterminal/web-terminal-admin.spec.ts index afce4f0cb64..8322735ef6c 100644 --- a/frontend/e2e/tests/webterminal/web-terminal-admin.spec.ts +++ b/frontend/e2e/tests/webterminal/web-terminal-admin.spec.ts @@ -2,7 +2,7 @@ import type { Page } from '@playwright/test'; import { test, expect } from '../../fixtures'; import type KubernetesClient from '../../clients/kubernetes-client'; -import { getEditorContent, warmupSPA } from '../../pages/base-page'; +import { getEditorContent } from '../../pages/base-page'; import { WebTerminalPage } from '../../pages/web-terminal-page'; import { ensureWebTerminalOperatorInstalled, @@ -88,6 +88,7 @@ test.describe('Web Terminal for Admin user', () => { test( 'open and close multiple terminal tabs', async ({ page }) => { + test.slow(); const webTerminal = new WebTerminalPage(page); await test.step('Wait for terminal icon and start terminal', async () => { @@ -120,6 +121,7 @@ test.describe('Web Terminal for Admin user', () => { test( 'start terminal with timeout and verify DevWorkspace', async ({ page, k8sClient }) => { + test.slow(); const webTerminal = new WebTerminalPage(page); await test.step('Open terminal with 10-minute timeout', async () => { @@ -139,6 +141,7 @@ test.describe('Web Terminal for Admin user', () => { test( 'start terminal with defaults and verify DevWorkspace', async ({ page, k8sClient }) => { + test.slow(); const webTerminal = new WebTerminalPage(page); await test.step('Open terminal with default settings', async () => { diff --git a/frontend/e2e/tests/webterminal/web-terminal-config.spec.ts b/frontend/e2e/tests/webterminal/web-terminal-config.spec.ts index dd24603d1fa..59ee1e2e7ad 100644 --- a/frontend/e2e/tests/webterminal/web-terminal-config.spec.ts +++ b/frontend/e2e/tests/webterminal/web-terminal-config.spec.ts @@ -27,6 +27,7 @@ test.describe('Customization of web terminal options', () => { test( 'navigate to Web Terminal Configuration page', async ({ page }) => { + test.slow(); const configPage = new WebTerminalConfigPage(page); await test.step('Navigate to Consoles and open Customize', async () => { @@ -42,6 +43,7 @@ test.describe('Customization of web terminal options', () => { test( 'change timeout and image with persist checkboxes', async ({ page }) => { + test.slow(); const configPage = new WebTerminalConfigPage(page); await test.step('Navigate to Web Terminal Configuration', async () => { @@ -68,6 +70,7 @@ test.describe('Customization of web terminal options', () => { test( 'change timeout to Hours and verify values persist after tab switch', async ({ page }) => { + test.slow(); const configPage = new WebTerminalConfigPage(page); await test.step('Navigate to Web Terminal Configuration', async () => { @@ -98,6 +101,7 @@ test.describe('Customization of web terminal options', () => { test( 'save without persist checkboxes', async ({ page }) => { + test.slow(); const configPage = new WebTerminalConfigPage(page); await test.step('Navigate to Web Terminal Configuration', async () => { @@ -121,6 +125,7 @@ test.describe('Customization of web terminal options', () => { test( 'verify unchecked checkboxes persist after tab switch', async ({ page }) => { + test.slow(); const configPage = new WebTerminalConfigPage(page); await test.step('Navigate to Web Terminal Configuration', async () => {