From 5c28a95f6c40627ff9f216281871747e361980c3 Mon Sep 17 00:00:00 2001 From: Triona Doyle Date: Tue, 28 Apr 2026 13:11:01 +0100 Subject: [PATCH 1/3] Add login via local credentials test Signed-off-by: Triona Doyle --- test/ui-e2e/tests/admin-login.spec.ts | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 test/ui-e2e/tests/admin-login.spec.ts diff --git a/test/ui-e2e/tests/admin-login.spec.ts b/test/ui-e2e/tests/admin-login.spec.ts new file mode 100644 index 00000000000..51d7d954077 --- /dev/null +++ b/test/ui-e2e/tests/admin-login.spec.ts @@ -0,0 +1,39 @@ +import { test, expect } from '@playwright/test'; +import { execSync } from 'node:child_process'; + +test('Log into Argo CD as local admin', async ({ browser }) => { + const rawOutput = execSync( + 'oc extract secret/openshift-gitops-cluster -n openshift-gitops --keys=admin.password --to=-' + ).toString(); + + //get credentials + const password = rawOutput.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'))[0]; + + const routeUrl = execSync( + 'oc get route openshift-gitops-server -n openshift-gitops -o jsonpath="{.spec.host}"' + ).toString().trim(); + + //Fresh context to avoid any cached state issues + const context = await browser.newContext({ + storageState: { cookies: [], origins: [] }, + ignoreHTTPSErrors: true + }); + + //Navigate and wait for the page to be loaded + const page = await context.newPage(); + const loginUrl = `https://${routeUrl}/login?dex=none`; + await page.goto(loginUrl, { waitUntil: 'load' }); + + const userField = page.getByRole('textbox').first(); + await userField.waitFor({ state: 'visible', timeout: 20000 }); + + //Fill and Sign In + await userField.fill('admin'); + await page.locator('input[type="password"]').fill(password); + await page.getByRole('button', { name: /sign in/i }).click(); + + //Verify we're logged in + await expect(page.locator('.sidebar, [data-testid="sidebar"]').first()).toBeVisible({ timeout: 20000 }); + + await context.close(); +}); \ No newline at end of file From c0d3b2bf54fc2b2ebb5c96b171ca6fa907e26e3c Mon Sep 17 00:00:00 2001 From: Triona Doyle Date: Thu, 28 May 2026 10:37:42 +0100 Subject: [PATCH 2/3] address coderabbit feedback for timeouts and cross-version locators Signed-off-by: Triona Doyle --- test/ui-e2e/tests/admin-login.spec.ts | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/test/ui-e2e/tests/admin-login.spec.ts b/test/ui-e2e/tests/admin-login.spec.ts index 51d7d954077..c21b54b201d 100644 --- a/test/ui-e2e/tests/admin-login.spec.ts +++ b/test/ui-e2e/tests/admin-login.spec.ts @@ -2,16 +2,29 @@ import { test, expect } from '@playwright/test'; import { execSync } from 'node:child_process'; test('Log into Argo CD as local admin', async ({ browser }) => { - const rawOutput = execSync( - 'oc extract secret/openshift-gitops-cluster -n openshift-gitops --keys=admin.password --to=-' - ).toString(); + let rawOutput: string; + let routeUrl: string; + + try { + rawOutput = execSync( + 'oc extract secret/openshift-gitops-cluster -n openshift-gitops --keys=admin.password --to=-', + { timeout: 15000, stdio: 'pipe' } + ).toString(); + } catch (error) { + throw new Error("Failed to extract admin password. Please check your cluster connection and oc CLI."); + } //get credentials const password = rawOutput.split('\n').map(l => l.trim()).filter(l => l && !l.startsWith('#'))[0]; - const routeUrl = execSync( - 'oc get route openshift-gitops-server -n openshift-gitops -o jsonpath="{.spec.host}"' - ).toString().trim(); + try { + routeUrl = execSync( + 'oc get route openshift-gitops-server -n openshift-gitops -o jsonpath="{.spec.host}"', + { timeout: 15000, stdio: 'pipe' } + ).toString().trim(); + } catch (error) { + throw new Error("Failed to fetch Argo CD route. Please check your cluster connection and oc CLI."); + } //Fresh context to avoid any cached state issues const context = await browser.newContext({ @@ -24,7 +37,7 @@ test('Log into Argo CD as local admin', async ({ browser }) => { const loginUrl = `https://${routeUrl}/login?dex=none`; await page.goto(loginUrl, { waitUntil: 'load' }); - const userField = page.getByRole('textbox').first(); + const userField = page.getByLabel(/username/i); await userField.waitFor({ state: 'visible', timeout: 20000 }); //Fill and Sign In From 36cc94daf03e21237bb13a0ceeb3fb85a6784f9a Mon Sep 17 00:00:00 2001 From: Triona Doyle Date: Thu, 28 May 2026 11:02:58 +0100 Subject: [PATCH 3/3] Address coderabbit suggestion: ensure Playwright context closes cleanly on failure Signed-off-by: Triona Doyle --- test/ui-e2e/tests/admin-login.spec.ts | 39 ++++++++++++++------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/test/ui-e2e/tests/admin-login.spec.ts b/test/ui-e2e/tests/admin-login.spec.ts index c21b54b201d..581c47ed846 100644 --- a/test/ui-e2e/tests/admin-login.spec.ts +++ b/test/ui-e2e/tests/admin-login.spec.ts @@ -32,21 +32,24 @@ test('Log into Argo CD as local admin', async ({ browser }) => { ignoreHTTPSErrors: true }); - //Navigate and wait for the page to be loaded - const page = await context.newPage(); - const loginUrl = `https://${routeUrl}/login?dex=none`; - await page.goto(loginUrl, { waitUntil: 'load' }); - - const userField = page.getByLabel(/username/i); - await userField.waitFor({ state: 'visible', timeout: 20000 }); - - //Fill and Sign In - await userField.fill('admin'); - await page.locator('input[type="password"]').fill(password); - await page.getByRole('button', { name: /sign in/i }).click(); - - //Verify we're logged in - await expect(page.locator('.sidebar, [data-testid="sidebar"]').first()).toBeVisible({ timeout: 20000 }); - - await context.close(); -}); \ No newline at end of file + try { + //Navigate and wait for the page to be loaded + const page = await context.newPage(); + const loginUrl = `https://${routeUrl}/login?dex=none`; + await page.goto(loginUrl, { waitUntil: 'load' }); + + const userField = page.getByLabel(/username/i); + await userField.waitFor({ state: 'visible', timeout: 20000 }); + + //Fill and Sign In + await userField.fill('admin'); + await page.locator('input[type="password"]').fill(password); + await page.getByRole('button', { name: /sign in/i }).click(); + + //Verify we're logged in + await expect(page.locator('.sidebar, [data-testid="sidebar"]').first()).toBeVisible({ timeout: 20000 }); + } finally { + // This guarantees the context closes even if an assertion fails above! + await context.close(); + } + }); \ No newline at end of file