From 51c6bb81d05608b6158f4a76768c7e6be87b40ba Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 15:54:59 -0500 Subject: [PATCH 01/22] test: migrate support case tests from IQE Migrates support case help panel tests from iqe-platform-ui-plugin test_support_case.py to Playwright. Tests verify: - "Open a support case" button appears in help panel support tab - Clicking button opens Red Hat Customer Portal in new tab - Support cases table displays when user has open cases The tests handle both empty state (no cases) and populated state (with cases) gracefully using conditional skipping based on what's rendered. Note: The complex test_support_case_from_apps (testing pre-filled support case data from different apps) was not migrated as it requires cross-domain testing and is better suited for the insights-chrome repository. Requirements: - PLATFORM_UI-INSIGHTS_CHROME - PLATFORM_UI-SUPPORT_CASES Co-Authored-By: Claude Sonnet 4.5 --- playwright/support-case.spec.ts | 152 ++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 playwright/support-case.spec.ts diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts new file mode 100644 index 00000000..184d397a --- /dev/null +++ b/playwright/support-case.spec.ts @@ -0,0 +1,152 @@ +import { test, expect } from '@playwright/test'; +import { disableCookiePrompt } from './test-utils'; + +/** + * Support Case Tests + * + * Migrated from IQE: iqe_platform_ui/tests/test_support_case.py + * + * These tests verify that support case functionality is accessible from the help panel: + * - "Open a support case" button appears in the help menu + * - Clicking the button opens the Red Hat Customer Portal support case page + * + * Note: The original IQE test #3 (test_support_case_from_apps) which tests pre-filled + * support case data from different apps was not migrated here as it requires complex + * cross-domain interaction and is better suited for insights-chrome repository. + * + * Requirements: + * - PLATFORM_UI-INSIGHTS_CHROME + * - PLATFORM_UI-SUPPORT_CASES + */ + +test.describe('Support Case - Help Panel', () => { + test.beforeEach(async ({ page }) => { + // Block trustarc cookie prompts + await disableCookiePrompt(page); + + // Navigate to home page - authentication state is already loaded from global setup + await page.goto('/', { waitUntil: 'load', timeout: 60000 }); + + // Wait for chrome header to be fully loaded + await expect(page.getByText('Hi,')).toBeVisible(); + }); + + test('should display "Open a support case" button in help panel', async ({ page }) => { + // Open the help panel + await page.getByLabel('Toggle help panel').click(); + + // Wait for help panel to load + const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); + await expect(helpPanelTitle).toBeVisible(); + + // Click on "My support cases" tab + const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); + await supportTab.click(); + + // The support panel should show either: + // 1. Empty state with "Open a support case" button (if user has no cases) + // 2. Table of support cases (if user has cases) + // We'll check for both possibilities + + // Wait a moment for the support panel to load (it fetches data from API) + await page.waitForTimeout(2000); + + // Check if empty state is displayed OR table is displayed + const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); + const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); + + const emptyStateVisible = await emptyState.isVisible().catch(() => false); + const tableVisible = await supportTable.isVisible().catch(() => false); + + // At least one should be visible + expect(emptyStateVisible || tableVisible).toBe(true); + + // If empty state is shown, verify the "Open a support case" button is present + if (emptyStateVisible) { + const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); + await expect(openCaseButton).toBeVisible(); + await expect(openCaseButton).toHaveText(/open a support case/i); + } + }); + + test('should open Customer Portal when clicking "Open a support case" button', async ({ page, context }) => { + // Open the help panel + await page.getByLabel('Toggle help panel').click(); + + // Wait for help panel to load + const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); + await expect(helpPanelTitle).toBeVisible(); + + // Click on "My support cases" tab + const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); + await supportTab.click(); + + // Wait a moment for the support panel to load + await page.waitForTimeout(2000); + + // Check if empty state with button is displayed + const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); + const buttonVisible = await openCaseButton.isVisible().catch(() => false); + + // Only run the click test if the button is visible (user has no cases) + // If user has cases, the button won't be in the empty state + if (!buttonVisible) { + test.skip(); + return; + } + + // Set up listener for new page/tab before clicking + const pagePromise = context.waitForEvent('page'); + + // Click the "Open a support case" button + await openCaseButton.click(); + + // Wait for new page to open + const newPage = await pagePromise; + await newPage.waitForLoadState('domcontentloaded', { timeout: 30000 }); + + // Verify the new page URL is the Red Hat Customer Portal support case page + expect(newPage.url()).toContain('access.redhat.com/support'); + + // Clean up - close the new tab + await newPage.close(); + }); + + test('should display support cases table when user has open cases', async ({ page }) => { + // Open the help panel + await page.getByLabel('Toggle help panel').click(); + + // Wait for help panel to load + const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); + await expect(helpPanelTitle).toBeVisible(); + + // Click on "My support cases" tab + const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); + await supportTab.click(); + + // Wait a moment for the support panel to load + await page.waitForTimeout(2000); + + // Check if table is displayed + const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); + const tableVisible = await supportTable.isVisible().catch(() => false); + + // This test only runs if user has support cases + if (!tableVisible) { + test.skip(); + return; + } + + // Verify table is visible + await expect(supportTable).toBeVisible(); + + // Verify pagination is present (shown when there are cases) + const pagination = page.locator('[data-ouia-component-id="help-panel-support-pagination"]'); + await expect(pagination).toBeVisible(); + + // Verify table has at least one row (case) + const tableRows = supportTable.locator('tbody tr'); + const rowCount = await tableRows.count(); + expect(rowCount).toBeGreaterThan(0); + }); +}); From 582df1fd45069e3bb725407963e44d3e7f473650 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 16:00:55 -0500 Subject: [PATCH 02/22] fix: use symbolic timeout constants and improve async waiting - Define timeout constants at module level for better maintainability - Replace page.waitForTimeout() with Playwright's expect().toPass() pattern - Use auto-retry for waiting on API-loaded content - Explicitly specify timeouts on assertions for clarity Timeout constants: - SUPPORT_API_LOAD_TIMEOUT (15s) - Support cases API load time - ELEMENT_VISIBLE_TIMEOUT (10s) - Element visibility wait - EXTERNAL_PAGE_LOAD_TIMEOUT (30s) - External page navigation Co-Authored-By: Claude Sonnet 4.5 --- playwright/support-case.spec.ts | 52 +++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index 184d397a..a1295fe5 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -19,6 +19,11 @@ import { disableCookiePrompt } from './test-utils'; * - PLATFORM_UI-SUPPORT_CASES */ +// Timeout constants +const SUPPORT_API_LOAD_TIMEOUT = 15000; // Time to wait for support cases API to load +const ELEMENT_VISIBLE_TIMEOUT = 10000; // Time to wait for elements to become visible +const EXTERNAL_PAGE_LOAD_TIMEOUT = 30000; // Time to wait for external pages to load + test.describe('Support Case - Help Panel', () => { test.beforeEach(async ({ page }) => { // Block trustarc cookie prompts @@ -48,23 +53,23 @@ test.describe('Support Case - Help Panel', () => { // 2. Table of support cases (if user has cases) // We'll check for both possibilities - // Wait a moment for the support panel to load (it fetches data from API) - await page.waitForTimeout(2000); - - // Check if empty state is displayed OR table is displayed + // The support panel will show either empty state or table after loading + // Use Playwright's auto-retry to wait for one of them to appear const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); - const emptyStateVisible = await emptyState.isVisible().catch(() => false); - const tableVisible = await supportTable.isVisible().catch(() => false); - - // At least one should be visible - expect(emptyStateVisible || tableVisible).toBe(true); + // Wait for either empty state or table to be visible + await expect(async () => { + const emptyStateVisible = await emptyState.isVisible().catch(() => false); + const tableVisible = await supportTable.isVisible().catch(() => false); + expect(emptyStateVisible || tableVisible).toBe(true); + }).toPass({ timeout: SUPPORT_API_LOAD_TIMEOUT }); // If empty state is shown, verify the "Open a support case" button is present + const emptyStateVisible = await emptyState.isVisible().catch(() => false); if (emptyStateVisible) { const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); - await expect(openCaseButton).toBeVisible(); + await expect(openCaseButton).toBeVisible({ timeout: ELEMENT_VISIBLE_TIMEOUT }); await expect(openCaseButton).toHaveText(/open a support case/i); } }); @@ -81,8 +86,16 @@ test.describe('Support Case - Help Panel', () => { const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // Wait a moment for the support panel to load - await page.waitForTimeout(2000); + // The support panel will show either empty state or table after loading + const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); + const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); + + // Wait for either empty state or table to be visible + await expect(async () => { + const emptyStateVisible = await emptyState.isVisible().catch(() => false); + const tableVisible = await supportTable.isVisible().catch(() => false); + expect(emptyStateVisible || tableVisible).toBe(true); + }).toPass({ timeout: SUPPORT_API_LOAD_TIMEOUT }); // Check if empty state with button is displayed const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); @@ -103,7 +116,7 @@ test.describe('Support Case - Help Panel', () => { // Wait for new page to open const newPage = await pagePromise; - await newPage.waitForLoadState('domcontentloaded', { timeout: 30000 }); + await newPage.waitForLoadState('domcontentloaded', { timeout: EXTERNAL_PAGE_LOAD_TIMEOUT }); // Verify the new page URL is the Red Hat Customer Portal support case page expect(newPage.url()).toContain('access.redhat.com/support'); @@ -124,11 +137,18 @@ test.describe('Support Case - Help Panel', () => { const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // Wait a moment for the support panel to load - await page.waitForTimeout(2000); + // The support panel will show either empty state or table after loading + const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); + const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); + + // Wait for either empty state or table to be visible + await expect(async () => { + const emptyStateVisible = await emptyState.isVisible().catch(() => false); + const tableVisible = await supportTable.isVisible().catch(() => false); + expect(emptyStateVisible || tableVisible).toBe(true); + }).toPass({ timeout: SUPPORT_API_LOAD_TIMEOUT }); // Check if table is displayed - const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); const tableVisible = await supportTable.isVisible().catch(() => false); // This test only runs if user has support cases From 7649fa421a924c8a154e03cd11c312ce914ae122 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 16:09:09 -0500 Subject: [PATCH 03/22] refactor: simplify support case tests to follow clear user flow Simplifies all three tests to follow the actual user interaction flow: 1. Click help button to open help panel 2. Wait for help panel to load 3. Click on support tab 4. Verify expected content is visible Key improvements: - Removed complex conditional logic and state checking - Tests now follow clear step-by-step user flow with numbered comments - Uses getByRole('link') to find 'Open a support case' link (works in both states) - Removed unnecessary empty state vs table differentiation in first two tests - Third test uses .or() locator for cleaner either/or waiting The 'Open a support case' link is always visible: - In empty state: as a primary action button - With cases: as a link in the description text Co-Authored-By: Claude Sonnet 4.5 --- playwright/support-case.spec.ts | 109 ++++++++++---------------------- 1 file changed, 35 insertions(+), 74 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index a1295fe5..53924d27 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -36,89 +36,49 @@ test.describe('Support Case - Help Panel', () => { await expect(page.getByText('Hi,')).toBeVisible(); }); - test('should display "Open a support case" button in help panel', async ({ page }) => { - // Open the help panel + test('should display "Open a support case" link in help panel', async ({ page }) => { + // Step 1: Click help button to open help panel await page.getByLabel('Toggle help panel').click(); - // Wait for help panel to load + // Step 2: Wait for help panel to load const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); await expect(helpPanelTitle).toBeVisible(); - // Click on "My support cases" tab + // Step 3: Click on "My support cases" tab const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // The support panel should show either: - // 1. Empty state with "Open a support case" button (if user has no cases) - // 2. Table of support cases (if user has cases) - // We'll check for both possibilities - - // The support panel will show either empty state or table after loading - // Use Playwright's auto-retry to wait for one of them to appear - const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); - const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); - - // Wait for either empty state or table to be visible - await expect(async () => { - const emptyStateVisible = await emptyState.isVisible().catch(() => false); - const tableVisible = await supportTable.isVisible().catch(() => false); - expect(emptyStateVisible || tableVisible).toBe(true); - }).toPass({ timeout: SUPPORT_API_LOAD_TIMEOUT }); - - // If empty state is shown, verify the "Open a support case" button is present - const emptyStateVisible = await emptyState.isVisible().catch(() => false); - if (emptyStateVisible) { - const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); - await expect(openCaseButton).toBeVisible({ timeout: ELEMENT_VISIBLE_TIMEOUT }); - await expect(openCaseButton).toHaveText(/open a support case/i); - } + // Step 4: The "Open a support case" link should be visible + // (It appears in both empty state and when cases exist) + const openCaseLink = page.getByRole('link', { name: /open a support case/i }); + await expect(openCaseLink).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); }); - test('should open Customer Portal when clicking "Open a support case" button', async ({ page, context }) => { - // Open the help panel + test('should open Customer Portal when clicking "Open a support case" link', async ({ page, context }) => { + // Step 1: Click help button to open help panel await page.getByLabel('Toggle help panel').click(); - // Wait for help panel to load + // Step 2: Wait for help panel to load const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); await expect(helpPanelTitle).toBeVisible(); - // Click on "My support cases" tab + // Step 3: Click on "My support cases" tab const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // The support panel will show either empty state or table after loading - const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); - const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); - - // Wait for either empty state or table to be visible - await expect(async () => { - const emptyStateVisible = await emptyState.isVisible().catch(() => false); - const tableVisible = await supportTable.isVisible().catch(() => false); - expect(emptyStateVisible || tableVisible).toBe(true); - }).toPass({ timeout: SUPPORT_API_LOAD_TIMEOUT }); - - // Check if empty state with button is displayed - const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); - const buttonVisible = await openCaseButton.isVisible().catch(() => false); - - // Only run the click test if the button is visible (user has no cases) - // If user has cases, the button won't be in the empty state - if (!buttonVisible) { - test.skip(); - return; - } + // Step 4: Wait for the "Open a support case" link to be visible + const openCaseLink = page.getByRole('link', { name: /open a support case/i }); + await expect(openCaseLink).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); - // Set up listener for new page/tab before clicking + // Step 5: Set up listener for new page/tab before clicking const pagePromise = context.waitForEvent('page'); - // Click the "Open a support case" button - await openCaseButton.click(); + // Step 6: Click the "Open a support case" link + await openCaseLink.click(); - // Wait for new page to open + // Step 7: Wait for new page to open and verify URL const newPage = await pagePromise; await newPage.waitForLoadState('domcontentloaded', { timeout: EXTERNAL_PAGE_LOAD_TIMEOUT }); - - // Verify the new page URL is the Red Hat Customer Portal support case page expect(newPage.url()).toContain('access.redhat.com/support'); // Clean up - close the new tab @@ -126,33 +86,34 @@ test.describe('Support Case - Help Panel', () => { }); test('should display support cases table when user has open cases', async ({ page }) => { - // Open the help panel + // Step 1: Click help button to open help panel await page.getByLabel('Toggle help panel').click(); - // Wait for help panel to load + // Step 2: Wait for help panel to load const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); await expect(helpPanelTitle).toBeVisible(); - // Click on "My support cases" tab + // Step 3: Click on "My support cases" tab const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // The support panel will show either empty state or table after loading - const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); + // Step 4: Wait for support panel to load and check if user has support cases const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); + const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); - // Wait for either empty state or table to be visible - await expect(async () => { - const emptyStateVisible = await emptyState.isVisible().catch(() => false); - const tableVisible = await supportTable.isVisible().catch(() => false); - expect(emptyStateVisible || tableVisible).toBe(true); - }).toPass({ timeout: SUPPORT_API_LOAD_TIMEOUT }); + // Wait for either the table or empty state to appear + try { + await expect(supportTable.or(emptyState)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); + } catch { + // If neither appears within timeout, skip the test + test.skip(); + return; + } - // Check if table is displayed + // Check if table is visible (user has cases) const tableVisible = await supportTable.isVisible().catch(() => false); - - // This test only runs if user has support cases if (!tableVisible) { + // User has no cases, skip this test test.skip(); return; } @@ -160,7 +121,7 @@ test.describe('Support Case - Help Panel', () => { // Verify table is visible await expect(supportTable).toBeVisible(); - // Verify pagination is present (shown when there are cases) + // Verify pagination is present const pagination = page.locator('[data-ouia-component-id="help-panel-support-pagination"]'); await expect(pagination).toBeVisible(); From d7eebf89cff54089865837f45e0d7f1eb5afa00a Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 16:11:59 -0500 Subject: [PATCH 04/22] fix: handle both button and link for 'Open a support case' The 'Open a support case' element is rendered differently depending on state: - Empty state (no cases): PatternFly Button with OUIA ID - Populated state (has cases): Actual link in description text Updated selectors to use .or() locator to find either: - Button: [data-ouia-component-id="help-panel-open-support-case-button"] - Link: getByRole('link', { name: /open a support case/i }) This makes tests work regardless of whether user has support cases. Co-Authored-By: Claude Sonnet 4.5 --- playwright/support-case.spec.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index 53924d27..e8154c09 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -48,10 +48,14 @@ test.describe('Support Case - Help Panel', () => { const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // Step 4: The "Open a support case" link should be visible - // (It appears in both empty state and when cases exist) + // Step 4: The "Open a support case" button/link should be visible + // In empty state: it's a Button with OUIA ID + // In populated state: it's a link in the description text + const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); const openCaseLink = page.getByRole('link', { name: /open a support case/i }); - await expect(openCaseLink).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); + + // Wait for either the button or link to be visible + await expect(openCaseButton.or(openCaseLink)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); }); test('should open Customer Portal when clicking "Open a support case" link', async ({ page, context }) => { @@ -66,15 +70,21 @@ test.describe('Support Case - Help Panel', () => { const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // Step 4: Wait for the "Open a support case" link to be visible + // Step 4: Wait for the "Open a support case" button/link to be visible + // In empty state: it's a Button with OUIA ID + // In populated state: it's a link in the description text + const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); const openCaseLink = page.getByRole('link', { name: /open a support case/i }); - await expect(openCaseLink).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); + + // Wait for either the button or link to be visible + const openCase = openCaseButton.or(openCaseLink); + await expect(openCase).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); // Step 5: Set up listener for new page/tab before clicking const pagePromise = context.waitForEvent('page'); - // Step 6: Click the "Open a support case" link - await openCaseLink.click(); + // Step 6: Click the "Open a support case" button/link + await openCase.click(); // Step 7: Wait for new page to open and verify URL const newPage = await pagePromise; From 57ff94346a28467a277e970aba88b111f25b5635 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 16:15:28 -0500 Subject: [PATCH 05/22] fix: wait for loading skeleton to complete before checking for button/link The SupportPanel shows a SkeletonTable while fetching support cases from the API. We need to wait for this loading state to complete before looking for the 'Open a support case' button/link. Changes: - Added step to wait for either empty state or table to appear (skeleton gone) - Only then check for the button/link visibility - This ensures we're not checking while the loading skeleton is still showing - Removed timeout from final visibility check since we already waited for loading Step flow now: 1. Click help button 2. Wait for help panel 3. Click support tab 4. Wait for loading to complete (empty state or table appears) 5. Verify button/link is visible 6-8. (Test 2 only) Click and verify new tab Co-Authored-By: Claude Sonnet 4.5 --- playwright/support-case.spec.ts | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index e8154c09..87a53170 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -48,14 +48,21 @@ test.describe('Support Case - Help Panel', () => { const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // Step 4: The "Open a support case" button/link should be visible + // Step 4: Wait for the support panel to finish loading + // The panel shows a skeleton loader while fetching support cases from API + // Wait for either empty state or table to appear (skeleton disappears) + const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); + const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); + await expect(emptyState.or(supportTable)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); + + // Step 5: The "Open a support case" button/link should now be visible // In empty state: it's a Button with OUIA ID // In populated state: it's a link in the description text const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); const openCaseLink = page.getByRole('link', { name: /open a support case/i }); - // Wait for either the button or link to be visible - await expect(openCaseButton.or(openCaseLink)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); + // Verify either the button or link is visible + await expect(openCaseButton.or(openCaseLink)).toBeVisible(); }); test('should open Customer Portal when clicking "Open a support case" link', async ({ page, context }) => { @@ -70,23 +77,28 @@ test.describe('Support Case - Help Panel', () => { const supportTab = page.locator('[data-ouia-component-id="help-panel-subtab-support"]'); await supportTab.click(); - // Step 4: Wait for the "Open a support case" button/link to be visible + // Step 4: Wait for the support panel to finish loading + // The panel shows a skeleton loader while fetching support cases from API + // Wait for either empty state or table to appear (skeleton disappears) + const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); + const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); + await expect(emptyState.or(supportTable)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); + + // Step 5: The "Open a support case" button/link should now be visible // In empty state: it's a Button with OUIA ID // In populated state: it's a link in the description text const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); const openCaseLink = page.getByRole('link', { name: /open a support case/i }); - - // Wait for either the button or link to be visible const openCase = openCaseButton.or(openCaseLink); - await expect(openCase).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); + await expect(openCase).toBeVisible(); - // Step 5: Set up listener for new page/tab before clicking + // Step 6: Set up listener for new page/tab before clicking const pagePromise = context.waitForEvent('page'); - // Step 6: Click the "Open a support case" button/link + // Step 7: Click the "Open a support case" button/link await openCase.click(); - // Step 7: Wait for new page to open and verify URL + // Step 8: Wait for new page to open and verify URL const newPage = await pagePromise; await newPage.waitForLoadState('domcontentloaded', { timeout: EXTERNAL_PAGE_LOAD_TIMEOUT }); expect(newPage.url()).toContain('access.redhat.com/support'); From f77fb27ea8dc8376f111c7cf0c069a9424fb02d2 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 16:20:11 -0500 Subject: [PATCH 06/22] refactor(tests): simplify support case link locator Replace dual locator approach (OUIA ID + role) with simple text search. The text 'Open a support case' is the same whether rendered as a Button or Link, so searching by text is cleaner and more maintainable. --- playwright/support-case.spec.ts | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index 87a53170..907876ae 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -56,13 +56,7 @@ test.describe('Support Case - Help Panel', () => { await expect(emptyState.or(supportTable)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); // Step 5: The "Open a support case" button/link should now be visible - // In empty state: it's a Button with OUIA ID - // In populated state: it's a link in the description text - const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); - const openCaseLink = page.getByRole('link', { name: /open a support case/i }); - - // Verify either the button or link is visible - await expect(openCaseButton.or(openCaseLink)).toBeVisible(); + await expect(page.getByText(/open a support case/i)).toBeVisible(); }); test('should open Customer Portal when clicking "Open a support case" link', async ({ page, context }) => { @@ -84,21 +78,13 @@ test.describe('Support Case - Help Panel', () => { const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); await expect(emptyState.or(supportTable)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); - // Step 5: The "Open a support case" button/link should now be visible - // In empty state: it's a Button with OUIA ID - // In populated state: it's a link in the description text - const openCaseButton = page.locator('[data-ouia-component-id="help-panel-open-support-case-button"]'); - const openCaseLink = page.getByRole('link', { name: /open a support case/i }); - const openCase = openCaseButton.or(openCaseLink); - await expect(openCase).toBeVisible(); - - // Step 6: Set up listener for new page/tab before clicking + // Step 5: Set up listener for new page/tab before clicking const pagePromise = context.waitForEvent('page'); - // Step 7: Click the "Open a support case" button/link - await openCase.click(); + // Step 6: Click the "Open a support case" button/link + await page.getByText(/open a support case/i).click(); - // Step 8: Wait for new page to open and verify URL + // Step 7: Wait for new page to open and verify URL const newPage = await pagePromise; await newPage.waitForLoadState('domcontentloaded', { timeout: EXTERNAL_PAGE_LOAD_TIMEOUT }); expect(newPage.url()).toContain('access.redhat.com/support'); From 1f9548d3a954cb98b273f1b9b56090a8edeb6a98 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 16:23:11 -0500 Subject: [PATCH 07/22] fix(tests): validate hostname only for external Customer Portal link Change URL validation to check only the hostname (access.redhat.com) rather than the full path, since we cannot validate page content due to authentication requirements on the external Customer Portal. Also removed unnecessary waitForLoadState and unused timeout constants. --- playwright/support-case.spec.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index 907876ae..548c0809 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -21,8 +21,6 @@ import { disableCookiePrompt } from './test-utils'; // Timeout constants const SUPPORT_API_LOAD_TIMEOUT = 15000; // Time to wait for support cases API to load -const ELEMENT_VISIBLE_TIMEOUT = 10000; // Time to wait for elements to become visible -const EXTERNAL_PAGE_LOAD_TIMEOUT = 30000; // Time to wait for external pages to load test.describe('Support Case - Help Panel', () => { test.beforeEach(async ({ page }) => { @@ -84,10 +82,12 @@ test.describe('Support Case - Help Panel', () => { // Step 6: Click the "Open a support case" button/link await page.getByText(/open a support case/i).click(); - // Step 7: Wait for new page to open and verify URL + // Step 7: Wait for new page to open and verify it navigates to Red Hat Customer Portal const newPage = await pagePromise; - await newPage.waitForLoadState('domcontentloaded', { timeout: EXTERNAL_PAGE_LOAD_TIMEOUT }); - expect(newPage.url()).toContain('access.redhat.com/support'); + + // Verify the destination hostname (we can't validate page content due to auth requirements) + const url = new URL(newPage.url()); + expect(url.hostname).toBe('access.redhat.com'); // Clean up - close the new tab await newPage.close(); From 9a7fbbc6bb65c388f862e86792ad416dbf21c5ab Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 16:25:58 -0500 Subject: [PATCH 08/22] docs: add detailed TODO note for unmigrated test #3 Clarify that test_support_case_from_apps requires complex setup: - API-created support cases - Cross-domain interaction - External portal authentication - Pre-filled data validation May require separate E2E suite or insights-chrome repository. --- playwright/support-case.spec.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index 548c0809..dcda42c1 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -10,9 +10,13 @@ import { disableCookiePrompt } from './test-utils'; * - "Open a support case" button appears in the help menu * - Clicking the button opens the Red Hat Customer Portal support case page * - * Note: The original IQE test #3 (test_support_case_from_apps) which tests pre-filled - * support case data from different apps was not migrated here as it requires complex - * cross-domain interaction and is better suited for insights-chrome repository. + * TODO: Test #3 (test_support_case_from_apps) - Not yet migrated + * This test verifies that support case data is pre-filled correctly when opened from + * different apps. It requires: + * - Complex setup with actual support cases created via API + * - Cross-domain interaction with Customer Portal + * - Authentication on the external portal to validate pre-filled data + * - May be better suited for insights-chrome repository or separate E2E suite * * Requirements: * - PLATFORM_UI-INSIGHTS_CHROME From 3bf3a2abbef79a16b05e33dab05b8f21043421f1 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Thu, 30 Apr 2026 16:47:05 -0500 Subject: [PATCH 09/22] fix(tests): wait for URL navigation and improve skip logic 1. Add waitForURL before asserting hostname to ensure navigation completes (newPage starts at about:blank after pagePromise resolves) 2. Remove try/catch that hides real failures by converting timeouts to skips - Let API load failures fail the test naturally - Only skip when empty state is actually visible (user has no cases) - Removes false negatives from timeout/network issues --- playwright/support-case.spec.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index dcda42c1..672fe3dc 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -89,6 +89,9 @@ test.describe('Support Case - Help Panel', () => { // Step 7: Wait for new page to open and verify it navigates to Red Hat Customer Portal const newPage = await pagePromise; + // Wait for navigation to complete (page starts at about:blank) + await newPage.waitForURL('**/*'); + // Verify the destination hostname (we can't validate page content due to auth requirements) const url = new URL(newPage.url()); expect(url.hostname).toBe('access.redhat.com'); @@ -113,18 +116,12 @@ test.describe('Support Case - Help Panel', () => { const supportTable = page.locator('[data-ouia-component-id="help-panel-support-cases-table"]'); const emptyState = page.locator('[data-ouia-component-id="help-panel-support-empty-state"]'); - // Wait for either the table or empty state to appear - try { - await expect(supportTable.or(emptyState)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); - } catch { - // If neither appears within timeout, skip the test - test.skip(); - return; - } + // Wait for either the table or empty state to appear (let it fail if timeout) + await expect(supportTable.or(emptyState)).toBeVisible({ timeout: SUPPORT_API_LOAD_TIMEOUT }); - // Check if table is visible (user has cases) - const tableVisible = await supportTable.isVisible().catch(() => false); - if (!tableVisible) { + // Check if empty state is visible (user has no cases) + const emptyVisible = await emptyState.isVisible().catch(() => false); + if (emptyVisible) { // User has no cases, skip this test test.skip(); return; From 9f3aef344bec07863fdb0279ff206c03aef567a9 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 10:48:39 -0500 Subject: [PATCH 10/22] fix(tests): use specific URL pattern for Customer Portal navigation Replace broad wildcard waitForURL('**/*') with specific RegExp /access\.redhat\.com/ to await popup navigation precisely and fail faster if navigation goes to wrong domain. --- playwright/support-case.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playwright/support-case.spec.ts b/playwright/support-case.spec.ts index 672fe3dc..d28399bd 100644 --- a/playwright/support-case.spec.ts +++ b/playwright/support-case.spec.ts @@ -89,8 +89,8 @@ test.describe('Support Case - Help Panel', () => { // Step 7: Wait for new page to open and verify it navigates to Red Hat Customer Portal const newPage = await pagePromise; - // Wait for navigation to complete (page starts at about:blank) - await newPage.waitForURL('**/*'); + // Wait for navigation to Red Hat Customer Portal (page starts at about:blank) + await newPage.waitForURL(/access\.redhat\.com/); // Verify the destination hostname (we can't validate page content due to auth requirements) const url = new URL(newPage.url()); From cf7a57b86b4add85e64ffa02d5267cc4e224244c Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 11:24:39 -0500 Subject: [PATCH 11/22] test: migrate feedback tests from IQE Migrated from IQE: iqe_platform_ui/tests/test_feedback.py Test 1 (test_feedback_open): - Opens help panel - Navigates to Share feedback tab - Clicks Share feedback card - Verifies form is visible - Clicks Back button - Verifies return to feedback home Test 2 (test_feedback_submission): - Currently skipped - requires JIRA API integration - TODO: Implement JIRA client to verify ticket creation - Only runs on stage environment Requirements: - PLATFORM_UI-FEEDBACK - PLATFORM_UI-INSIGHTS_CHROME --- playwright/feedback.spec.ts | 102 ++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 playwright/feedback.spec.ts diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts new file mode 100644 index 00000000..c9f68159 --- /dev/null +++ b/playwright/feedback.spec.ts @@ -0,0 +1,102 @@ +import { test, expect } from '@playwright/test'; +import { disableCookiePrompt } from './test-utils'; + +/** + * Feedback Tests + * + * Migrated from IQE: iqe_platform_ui/tests/test_feedback.py + * + * These tests verify that the feedback functionality works correctly in the help panel: + * - Opening and closing feedback forms + * - Submitting feedback and creating JIRA tickets in CRCFEEDBK project + * + * Requirements: + * - PLATFORM_UI-FEEDBACK + * - PLATFORM_UI-INSIGHTS_CHROME + */ + +test.describe('Feedback - Help Panel', () => { + test.beforeEach(async ({ page }) => { + // Block trustarc cookie prompts + await disableCookiePrompt(page); + + // Navigate to home page - authentication state is already loaded from global setup + await page.goto('/', { waitUntil: 'load', timeout: 60000 }); + + // Wait for chrome header to be fully loaded + await expect(page.getByText('Hi,')).toBeVisible(); + }); + + test('should open and close feedback form', async ({ page }) => { + // Step 1: Click help button to open help panel + await page.getByLabel('Toggle help panel').click(); + + // Step 2: Wait for help panel to load + const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); + await expect(helpPanelTitle).toBeVisible(); + + // Step 3: Click on "Share feedback" tab + const feedbackTab = page.locator('[data-ouia-component-id="help-panel-subtab-feedback"]'); + await feedbackTab.click(); + + // Step 4: Verify we're on the feedback home page + await expect(page.getByText('Tell us about your experience')).toBeVisible(); + + // Step 5: Click "Share feedback" card to open the form + const shareFeedbackCard = page.getByText('Share feedback').first(); + await shareFeedbackCard.click(); + + // Step 6: Verify the feedback form is open + await expect(page.getByLabel(/^(Describe|Share)/i)).toBeVisible(); + + // Step 7: Click back button to return to feedback home + await page.getByRole('button', { name: 'Back' }).click(); + + // Step 8: Verify we're back at feedback home + await expect(page.getByText('Tell us about your experience')).toBeVisible(); + }); + + test('should submit feedback and create JIRA ticket', async ({ page }) => { + // Skip this test in non-stage environments + const hostname = new URL(page.url()).hostname; + if (!hostname.includes('stage')) { + test.skip(); + return; + } + + // Step 1: Click help button to open help panel + await page.getByLabel('Toggle help panel').click(); + + // Step 2: Wait for help panel to load + const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); + await expect(helpPanelTitle).toBeVisible(); + + // Step 3: Click on "Share feedback" tab + const feedbackTab = page.locator('[data-ouia-component-id="help-panel-subtab-feedback"]'); + await feedbackTab.click(); + + // Step 4: Click "Share feedback" card to open the form + const shareFeedbackCard = page.getByText('Share feedback').first(); + await shareFeedbackCard.click(); + + // Step 5: Fill in feedback with random text (for JIRA search uniqueness) + const randomText = `AutoTest-${Math.random().toString(36).substring(2, 18)}`; + const feedbackTextarea = page.getByLabel(/^(Describe|Share)/i); + await feedbackTextarea.fill(`Testing insights feedback submission via Playwright automation. Random ID: ${randomText}`); + + // Step 6: Submit the feedback + const submitButton = page.getByRole('button', { name: /submit/i }); + await submitButton.click(); + + // Step 7: Wait for success message + await expect(page.getByText(/feedback sent|thank you/i)).toBeVisible({ timeout: 10000 }); + + // Step 8: Verify JIRA ticket was created using JIRA API + // TODO: Implement JIRA API integration + // - Query JIRA for ticket with randomText in description + // - Verify ticket has correct labels (learning-resources, help-panel-feedback) + // - Verify ticket contains username and URL + // - Mark ticket as Done in cleanup + test.skip(true, 'JIRA API integration not yet implemented'); + }); +}); From c2625410f42eb12cf9bcb36c135359d70f6c7909 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 11:26:05 -0500 Subject: [PATCH 12/22] refactor: verify feedback submission success without JIRA integration Updated test_feedback_submission to only verify the form submission succeeds and displays success message, without requiring JIRA API integration for ticket verification. Changes: - Renamed test to 'should submit feedback successfully' - Removed JIRA API TODO and test.skip - Verifies 'Feedback sent' success message - Verifies 'Thank you' description - Verifies 'Share more feedback' button appears - Added note about manual JIRA ticket verification if needed - Runs on stage and prod environments only --- playwright/feedback.spec.ts | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index c9f68159..ffc15ade 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -56,10 +56,10 @@ test.describe('Feedback - Help Panel', () => { await expect(page.getByText('Tell us about your experience')).toBeVisible(); }); - test('should submit feedback and create JIRA ticket', async ({ page }) => { - // Skip this test in non-stage environments + test('should submit feedback successfully', async ({ page }) => { + // Skip this test in non-stage/prod environments (submission only works there) const hostname = new URL(page.url()).hostname; - if (!hostname.includes('stage')) { + if (!hostname.includes('stage') && !hostname.includes('prod')) { test.skip(); return; } @@ -79,7 +79,7 @@ test.describe('Feedback - Help Panel', () => { const shareFeedbackCard = page.getByText('Share feedback').first(); await shareFeedbackCard.click(); - // Step 5: Fill in feedback with random text (for JIRA search uniqueness) + // Step 5: Fill in feedback with random text const randomText = `AutoTest-${Math.random().toString(36).substring(2, 18)}`; const feedbackTextarea = page.getByLabel(/^(Describe|Share)/i); await feedbackTextarea.fill(`Testing insights feedback submission via Playwright automation. Random ID: ${randomText}`); @@ -88,15 +88,17 @@ test.describe('Feedback - Help Panel', () => { const submitButton = page.getByRole('button', { name: /submit/i }); await submitButton.click(); - // Step 7: Wait for success message - await expect(page.getByText(/feedback sent|thank you/i)).toBeVisible({ timeout: 10000 }); + // Step 7: Verify success message is displayed + await expect(page.getByText('Feedback sent')).toBeVisible({ timeout: 10000 }); + await expect(page.getByText(/thank you/i)).toBeVisible(); - // Step 8: Verify JIRA ticket was created using JIRA API - // TODO: Implement JIRA API integration - // - Query JIRA for ticket with randomText in description - // - Verify ticket has correct labels (learning-resources, help-panel-feedback) - // - Verify ticket contains username and URL - // - Mark ticket as Done in cleanup - test.skip(true, 'JIRA API integration not yet implemented'); + // Step 8: Verify success state shows "Share more feedback" option + await expect(page.getByRole('button', { name: /share more feedback/i })).toBeVisible(); + + // Note: Actual JIRA ticket verification is not performed in this automated test. + // The feedback creates a ticket in https://issues.redhat.com/projects/CRCFEEDBK/issues/ + // Manual verification may be needed to confirm ticket creation with correct labels: + // - learning-resources + // - help-panel-feedback }); }); From e48e124e709a37b42c4209dbd162abe64e50e10e Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 11:42:01 -0500 Subject: [PATCH 13/22] fix: use OUIA ID for feedback home title locator Replace getByText('Tell us about your experience') with OUIA ID locator to avoid strict mode violation from duplicate auto-generated OUIA IDs. Changes: - Use locator('[data-ouia-component-id="feedback-home-title"]') - Reuse the locator variable for both assertions - Fixes: strict mode violation with 2 matching elements --- playwright/feedback.spec.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index ffc15ade..2069941d 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -40,7 +40,8 @@ test.describe('Feedback - Help Panel', () => { await feedbackTab.click(); // Step 4: Verify we're on the feedback home page - await expect(page.getByText('Tell us about your experience')).toBeVisible(); + const feedbackHomeTitle = page.locator('[data-ouia-component-id="feedback-home-title"]'); + await expect(feedbackHomeTitle).toBeVisible(); // Step 5: Click "Share feedback" card to open the form const shareFeedbackCard = page.getByText('Share feedback').first(); @@ -53,7 +54,7 @@ test.describe('Feedback - Help Panel', () => { await page.getByRole('button', { name: 'Back' }).click(); // Step 8: Verify we're back at feedback home - await expect(page.getByText('Tell us about your experience')).toBeVisible(); + await expect(feedbackHomeTitle).toBeVisible(); }); test('should submit feedback successfully', async ({ page }) => { From f4d939bb98f9f658d7c37d7ab8356961c1451247 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:20:24 -0500 Subject: [PATCH 14/22] fix: use correct aria-label for feedback textarea Replace regex pattern getByLabel(/^(Describe|Share)/i) with exact aria-label getByLabel('Feedback text') to correctly target the textarea element instead of matching the tab panel. The TextArea component uses aria-label="Feedback text" from messages.feedbackAriaLabel. --- playwright/feedback.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index 2069941d..cf0ecabe 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -48,7 +48,7 @@ test.describe('Feedback - Help Panel', () => { await shareFeedbackCard.click(); // Step 6: Verify the feedback form is open - await expect(page.getByLabel(/^(Describe|Share)/i)).toBeVisible(); + await expect(page.getByLabel('Feedback text')).toBeVisible(); // Step 7: Click back button to return to feedback home await page.getByRole('button', { name: 'Back' }).click(); @@ -82,7 +82,7 @@ test.describe('Feedback - Help Panel', () => { // Step 5: Fill in feedback with random text const randomText = `AutoTest-${Math.random().toString(36).substring(2, 18)}`; - const feedbackTextarea = page.getByLabel(/^(Describe|Share)/i); + const feedbackTextarea = page.getByLabel('Feedback text'); await feedbackTextarea.fill(`Testing insights feedback submission via Playwright automation. Random ID: ${randomText}`); // Step 6: Submit the feedback From eb5c1b4c2efc814498c7b99384ee045eb62bc062 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:24:21 -0500 Subject: [PATCH 15/22] fix: use textarea ID selector and wait for visibility Replace aria-label selector with ID-based selector and add explicit wait for textarea visibility after clicking Share feedback card. Changes: - Use page.locator('#feedback-description-text') instead of getByLabel() - Add await expect(feedbackTextarea).toBeVisible() before filling - Ensures form transition completes before interaction - Applied to both tests for consistency The textarea ID is more reliable than aria-label which may vary with localization. --- playwright/feedback.spec.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index cf0ecabe..9e2ddcdf 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -48,7 +48,8 @@ test.describe('Feedback - Help Panel', () => { await shareFeedbackCard.click(); // Step 6: Verify the feedback form is open - await expect(page.getByLabel('Feedback text')).toBeVisible(); + const feedbackTextarea = page.locator('#feedback-description-text'); + await expect(feedbackTextarea).toBeVisible(); // Step 7: Click back button to return to feedback home await page.getByRole('button', { name: 'Back' }).click(); @@ -80,9 +81,11 @@ test.describe('Feedback - Help Panel', () => { const shareFeedbackCard = page.getByText('Share feedback').first(); await shareFeedbackCard.click(); - // Step 5: Fill in feedback with random text + // Step 5: Wait for form to appear and fill in feedback + const feedbackTextarea = page.locator('#feedback-description-text'); + await expect(feedbackTextarea).toBeVisible(); + const randomText = `AutoTest-${Math.random().toString(36).substring(2, 18)}`; - const feedbackTextarea = page.getByLabel('Feedback text'); await feedbackTextarea.fill(`Testing insights feedback submission via Playwright automation. Random ID: ${randomText}`); // Step 6: Submit the feedback From e9e5e4c693f2dffc87881a4257904aeb738b7ca2 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:29:59 -0500 Subject: [PATCH 16/22] fix: wait for feedback subtab visibility before clicking Add explicit wait for feedback subtab to be visible before attempting to click it. The subtabs may not be immediately visible when the help panel first opens. This ensures the tab panel has fully rendered before interaction. --- playwright/feedback.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index 9e2ddcdf..41231e08 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -35,8 +35,9 @@ test.describe('Feedback - Help Panel', () => { const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); await expect(helpPanelTitle).toBeVisible(); - // Step 3: Click on "Share feedback" tab + // Step 3: Wait for subtabs to be visible and click "Feedback" subtab const feedbackTab = page.locator('[data-ouia-component-id="help-panel-subtab-feedback"]'); + await expect(feedbackTab).toBeVisible(); await feedbackTab.click(); // Step 4: Verify we're on the feedback home page @@ -73,8 +74,9 @@ test.describe('Feedback - Help Panel', () => { const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); await expect(helpPanelTitle).toBeVisible(); - // Step 3: Click on "Share feedback" tab + // Step 3: Wait for subtabs to be visible and click "Feedback" subtab const feedbackTab = page.locator('[data-ouia-component-id="help-panel-subtab-feedback"]'); + await expect(feedbackTab).toBeVisible(); await feedbackTab.click(); // Step 4: Click "Share feedback" card to open the form From c6cd63f4566759a10f97ee4dec9a7deeefd0c527 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:37:48 -0500 Subject: [PATCH 17/22] refactor: combine feedback tests into comprehensive single test Merged test_feedback_open and test_feedback_submission into one test that covers the full user journey: 1. Opens help panel and navigates to feedback tab 2. Verifies feedback home page 3. Opens Share feedback form 4. Tests Back button navigation (returns to home) 5. Re-opens form 6. Fills and submits feedback 7. Verifies success message 8. Verifies 'Share more feedback' button Benefits: - Eliminates duplicate setup/navigation code - Tests complete user flow in one scenario - Runs only on stage/prod (where submission works) - Still covers all functionality from both original IQE tests Migrated from IQE: - test_feedback_open (@pytest.mark.qa) - test_feedback_submission (@pytest.mark.core) --- playwright/feedback.spec.ts | 47 +++++++++++-------------------------- 1 file changed, 14 insertions(+), 33 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index 41231e08..371202cd 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -27,7 +27,14 @@ test.describe('Feedback - Help Panel', () => { await expect(page.getByText('Hi,')).toBeVisible(); }); - test('should open and close feedback form', async ({ page }) => { + test('should open feedback form, test navigation, and submit successfully', async ({ page }) => { + // Skip this test in non-stage/prod environments (submission only works there) + const hostname = new URL(page.url()).hostname; + if (!hostname.includes('stage') && !hostname.includes('prod')) { + test.skip(); + return; + } + // Step 1: Click help button to open help panel await page.getByLabel('Toggle help panel').click(); @@ -52,53 +59,27 @@ test.describe('Feedback - Help Panel', () => { const feedbackTextarea = page.locator('#feedback-description-text'); await expect(feedbackTextarea).toBeVisible(); - // Step 7: Click back button to return to feedback home + // Step 7: Test Back button navigation await page.getByRole('button', { name: 'Back' }).click(); - - // Step 8: Verify we're back at feedback home await expect(feedbackHomeTitle).toBeVisible(); - }); - - test('should submit feedback successfully', async ({ page }) => { - // Skip this test in non-stage/prod environments (submission only works there) - const hostname = new URL(page.url()).hostname; - if (!hostname.includes('stage') && !hostname.includes('prod')) { - test.skip(); - return; - } - // Step 1: Click help button to open help panel - await page.getByLabel('Toggle help panel').click(); - - // Step 2: Wait for help panel to load - const helpPanelTitle = page.locator('[data-ouia-component-id="help-panel-title"]'); - await expect(helpPanelTitle).toBeVisible(); - - // Step 3: Wait for subtabs to be visible and click "Feedback" subtab - const feedbackTab = page.locator('[data-ouia-component-id="help-panel-subtab-feedback"]'); - await expect(feedbackTab).toBeVisible(); - await feedbackTab.click(); - - // Step 4: Click "Share feedback" card to open the form - const shareFeedbackCard = page.getByText('Share feedback').first(); + // Step 8: Re-open the form to test submission await shareFeedbackCard.click(); - - // Step 5: Wait for form to appear and fill in feedback - const feedbackTextarea = page.locator('#feedback-description-text'); await expect(feedbackTextarea).toBeVisible(); + // Step 9: Fill in feedback with random text const randomText = `AutoTest-${Math.random().toString(36).substring(2, 18)}`; await feedbackTextarea.fill(`Testing insights feedback submission via Playwright automation. Random ID: ${randomText}`); - // Step 6: Submit the feedback + // Step 10: Submit the feedback const submitButton = page.getByRole('button', { name: /submit/i }); await submitButton.click(); - // Step 7: Verify success message is displayed + // Step 11: Verify success message is displayed await expect(page.getByText('Feedback sent')).toBeVisible({ timeout: 10000 }); await expect(page.getByText(/thank you/i)).toBeVisible(); - // Step 8: Verify success state shows "Share more feedback" option + // Step 12: Verify success state shows "Share more feedback" option await expect(page.getByRole('button', { name: /share more feedback/i })).toBeVisible(); // Note: Actual JIRA ticket verification is not performed in this automated test. From 1db6019bd2cac6a0363d8f90ea4be5b55d975f92 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:39:16 -0500 Subject: [PATCH 18/22] docs: clarify test runs locally via stage hostname Updated comment to clarify that the test DOES run locally because the local dev server uses stage.foo.redhat.com:1337 as the hostname, which includes 'stage'. The test only skips on truly local URLs like localhost or 127.0.0.1. --- playwright/feedback.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index 371202cd..847a3316 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -28,7 +28,8 @@ test.describe('Feedback - Help Panel', () => { }); test('should open feedback form, test navigation, and submit successfully', async ({ page }) => { - // Skip this test in non-stage/prod environments (submission only works there) + // Skip this test if not running against stage or prod hostnames + // Note: Local dev (stage.foo.redhat.com:1337) runs this test since hostname includes 'stage' const hostname = new URL(page.url()).hostname; if (!hostname.includes('stage') && !hostname.includes('prod')) { test.skip(); From 8f58a26dc1aac69114e46aae84668bcf6fdd430f Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:40:28 -0500 Subject: [PATCH 19/22] refactor: remove conditional skip from feedback test Remove the hostname-based skip condition. The test now runs on all environments. If feedback submission isn't available (non-stage/prod), the test will fail naturally rather than silently skip. This simplifies the test and makes failures more obvious. --- playwright/feedback.spec.ts | 8 -------- 1 file changed, 8 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index 847a3316..f1db355e 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -28,14 +28,6 @@ test.describe('Feedback - Help Panel', () => { }); test('should open feedback form, test navigation, and submit successfully', async ({ page }) => { - // Skip this test if not running against stage or prod hostnames - // Note: Local dev (stage.foo.redhat.com:1337) runs this test since hostname includes 'stage' - const hostname = new URL(page.url()).hostname; - if (!hostname.includes('stage') && !hostname.includes('prod')) { - test.skip(); - return; - } - // Step 1: Click help button to open help panel await page.getByLabel('Toggle help panel').click(); From 0276778594ac0f7f9698367a61359e36176eca17 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:44:59 -0500 Subject: [PATCH 20/22] fix: use correct card text 'Share general feedback' The card title is 'Share general feedback' not 'Share feedback'. Updated both instances where we click the card (steps 5 and 8). This was causing the click to fail silently since the locator couldn't find the element with the incorrect text. --- playwright/feedback.spec.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index f1db355e..7b1b8e22 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -44,9 +44,8 @@ test.describe('Feedback - Help Panel', () => { const feedbackHomeTitle = page.locator('[data-ouia-component-id="feedback-home-title"]'); await expect(feedbackHomeTitle).toBeVisible(); - // Step 5: Click "Share feedback" card to open the form - const shareFeedbackCard = page.getByText('Share feedback').first(); - await shareFeedbackCard.click(); + // Step 5: Click "Share general feedback" card to open the form + await page.getByText('Share general feedback').click(); // Step 6: Verify the feedback form is open const feedbackTextarea = page.locator('#feedback-description-text'); @@ -57,7 +56,7 @@ test.describe('Feedback - Help Panel', () => { await expect(feedbackHomeTitle).toBeVisible(); // Step 8: Re-open the form to test submission - await shareFeedbackCard.click(); + await page.getByText('Share general feedback').click(); await expect(feedbackTextarea).toBeVisible(); // Step 9: Fill in feedback with random text From 3c7b70f56c918aae102332b5ce7e5bfa30de402e Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:51:14 -0500 Subject: [PATCH 21/22] fix: use exact match for Back button and correct success message 1. Add exact: true to Back button locator to avoid strict mode violation - Prevents partial matches with 'Feedback' and 'Submit feedback' 2. Update success message to match actual text - Changed from 'Feedback sent' to 'feedback shared successfully' - Use case-insensitive regex for flexibility --- playwright/feedback.spec.ts | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index 7b1b8e22..1fc09de0 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -44,34 +44,34 @@ test.describe('Feedback - Help Panel', () => { const feedbackHomeTitle = page.locator('[data-ouia-component-id="feedback-home-title"]'); await expect(feedbackHomeTitle).toBeVisible(); - // Step 5: Click "Share general feedback" card to open the form + // Step 5: Test Back button navigation flow + // Open form await page.getByText('Share general feedback').click(); - - // Step 6: Verify the feedback form is open const feedbackTextarea = page.locator('#feedback-description-text'); await expect(feedbackTextarea).toBeVisible(); - // Step 7: Test Back button navigation - await page.getByRole('button', { name: 'Back' }).click(); + // Click Back and verify return to home + await page.getByRole('button', { name: 'Back', exact: true }).click(); await expect(feedbackHomeTitle).toBeVisible(); - // Step 8: Re-open the form to test submission + // Step 6: Test submission flow (restart from feedback home) + // Open form again await page.getByText('Share general feedback').click(); await expect(feedbackTextarea).toBeVisible(); - // Step 9: Fill in feedback with random text + // Fill in feedback with random text const randomText = `AutoTest-${Math.random().toString(36).substring(2, 18)}`; await feedbackTextarea.fill(`Testing insights feedback submission via Playwright automation. Random ID: ${randomText}`); - // Step 10: Submit the feedback + // Submit the feedback const submitButton = page.getByRole('button', { name: /submit/i }); await submitButton.click(); - // Step 11: Verify success message is displayed - await expect(page.getByText('Feedback sent')).toBeVisible({ timeout: 10000 }); + // Step 7: Verify success message is displayed + await expect(page.getByText(/feedback shared successfully/i)).toBeVisible({ timeout: 10000 }); await expect(page.getByText(/thank you/i)).toBeVisible(); - // Step 12: Verify success state shows "Share more feedback" option + // Step 8: Verify success state shows "Share more feedback" option await expect(page.getByRole('button', { name: /share more feedback/i })).toBeVisible(); // Note: Actual JIRA ticket verification is not performed in this automated test. From b9399ebf8e1ffbb300b509e5b73d6d0fd958f3c2 Mon Sep 17 00:00:00 2001 From: Darth Tweed Date: Fri, 1 May 2026 12:52:46 -0500 Subject: [PATCH 22/22] refactor: replace hard-coded timeouts with symbolic constants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added timeout constants at the top of the test file: - PAGE_LOAD_TIMEOUT = 60000ms (initial page load) - FEEDBACK_SUBMISSION_TIMEOUT = 10000ms (feedback API submission) Replaced hard-coded values: - page.goto timeout: 60000 → PAGE_LOAD_TIMEOUT - Success message visibility: 10000 → FEEDBACK_SUBMISSION_TIMEOUT This improves maintainability and makes timeout values easy to adjust in one place. --- playwright/feedback.spec.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/playwright/feedback.spec.ts b/playwright/feedback.spec.ts index 1fc09de0..bcc94e03 100644 --- a/playwright/feedback.spec.ts +++ b/playwright/feedback.spec.ts @@ -15,13 +15,17 @@ import { disableCookiePrompt } from './test-utils'; * - PLATFORM_UI-INSIGHTS_CHROME */ +// Timeout constants +const PAGE_LOAD_TIMEOUT = 60000; // Time to wait for initial page load +const FEEDBACK_SUBMISSION_TIMEOUT = 10000; // Time to wait for feedback submission to complete + test.describe('Feedback - Help Panel', () => { test.beforeEach(async ({ page }) => { // Block trustarc cookie prompts await disableCookiePrompt(page); // Navigate to home page - authentication state is already loaded from global setup - await page.goto('/', { waitUntil: 'load', timeout: 60000 }); + await page.goto('/', { waitUntil: 'load', timeout: PAGE_LOAD_TIMEOUT }); // Wait for chrome header to be fully loaded await expect(page.getByText('Hi,')).toBeVisible(); @@ -68,7 +72,7 @@ test.describe('Feedback - Help Panel', () => { await submitButton.click(); // Step 7: Verify success message is displayed - await expect(page.getByText(/feedback shared successfully/i)).toBeVisible({ timeout: 10000 }); + await expect(page.getByText(/feedback shared successfully/i)).toBeVisible({ timeout: FEEDBACK_SUBMISSION_TIMEOUT }); await expect(page.getByText(/thank you/i)).toBeVisible(); // Step 8: Verify success state shows "Share more feedback" option