Skip to content

Commit e4729a7

Browse files
feat(e2e): harden browser lifecycle, smoke gate, and naming
Close browser contexts in teardownBrowser, add teardown to auth-provider specs, wait for /healthcheck before smoke login and drop 10 retries, replace dispatchEvent clicks with native Playwright actions, and rename BackstageShowcase to RhdhInstance with dedicated table page object. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent c9f8ecd commit e4729a7

17 files changed

Lines changed: 120 additions & 82 deletions

e2e-tests/playwright.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ export default defineConfig({
9292
{
9393
name: PW_PROJECT.SMOKE_TEST,
9494
testMatch: "**/playwright/e2e/smoke-test.spec.ts",
95-
retries: 10,
9695
},
9796
{
9897
name: PW_PROJECT.SHOWCASE,

e2e-tests/playwright/e2e/auth-providers/github.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect, Page, BrowserContext } from "@support/coverage/test";
22
import RHDHDeployment from "../../utils/authentication-providers/rhdh-deployment";
3-
import { Common, setupBrowser } from "../../utils/common";
3+
import { Common, setupBrowser, teardownBrowser } from "../../utils/common";
44
import { UIhelper } from "../../utils/ui-helper";
55
import { NO_USER_FOUND_IN_CATALOG_ERROR_MESSAGE } from "../../utils/constants";
66
let page: Page;
@@ -355,6 +355,9 @@ test.describe("Configure Github Provider", async () => {
355355
});
356356

357357
test.afterAll(async () => {
358+
if (page !== undefined) {
359+
await teardownBrowser(page, test.info());
360+
}
358361
console.log("[TEST] Starting cleanup...");
359362
await deployment.killRunningProcess();
360363
console.log("[TEST] Cleanup completed");

e2e-tests/playwright/e2e/auth-providers/gitlab.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect, Page, BrowserContext } from "@support/coverage/test";
22
import RHDHDeployment from "../../utils/authentication-providers/rhdh-deployment";
3-
import { Common, setupBrowser } from "../../utils/common";
3+
import { Common, setupBrowser, teardownBrowser } from "../../utils/common";
44
import { UIhelper } from "../../utils/ui-helper";
55
import { GitLabHelper } from "../../utils/authentication-providers/gitlab-helper";
66
let page: Page;
@@ -247,6 +247,9 @@ test.describe("Configure GitLab Provider", async () => {
247247
});
248248

249249
test.afterAll(async () => {
250+
if (page !== undefined) {
251+
await teardownBrowser(page, test.info());
252+
}
250253
console.log("[TEST] Starting cleanup...");
251254

252255
// Delete the dynamically created OAuth application

e2e-tests/playwright/e2e/auth-providers/ldap.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect, Page, BrowserContext } from "@support/coverage/test";
22
import RHDHDeployment from "../../utils/authentication-providers/rhdh-deployment";
3-
import { Common, setupBrowser } from "../../utils/common";
3+
import { Common, setupBrowser, teardownBrowser } from "../../utils/common";
44
import { UIhelper } from "../../utils/ui-helper";
55
import { MSClient } from "../../utils/authentication-providers/msgraph-helper";
66

@@ -340,6 +340,9 @@ test.describe("Configure LDAP Provider", () => {
340340
});
341341

342342
test.afterAll(async () => {
343+
if (page !== undefined) {
344+
await teardownBrowser(page, test.info());
345+
}
343346
console.log("[TEST] Starting cleanup...");
344347

345348
// Clean up NSG rule

e2e-tests/playwright/e2e/auth-providers/microsoft.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect, Page, BrowserContext } from "@support/coverage/test";
22
import RHDHDeployment from "../../utils/authentication-providers/rhdh-deployment";
3-
import { Common, setupBrowser } from "../../utils/common";
3+
import { Common, setupBrowser, teardownBrowser } from "../../utils/common";
44
import { UIhelper } from "../../utils/ui-helper";
55
import { MSClient } from "../../utils/authentication-providers/msgraph-helper";
66
import { NO_USER_FOUND_IN_CATALOG_ERROR_MESSAGE } from "../../utils/constants";
@@ -387,6 +387,9 @@ test.describe("Configure Microsoft Provider", async () => {
387387
});
388388

389389
test.afterAll(async () => {
390+
if (page !== undefined) {
391+
await teardownBrowser(page, test.info());
392+
}
390393
console.log("[TEST] Starting cleanup...");
391394
await deployment.killRunningProcess();
392395

e2e-tests/playwright/e2e/auth-providers/oidc.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { test, expect, Page, BrowserContext } from "@support/coverage/test";
22
import RHDHDeployment from "../../utils/authentication-providers/rhdh-deployment";
3-
import { Common, setupBrowser } from "../../utils/common";
3+
import { Common, setupBrowser, teardownBrowser } from "../../utils/common";
44
import { UIhelper } from "../../utils/ui-helper";
55
import { KeycloakHelper } from "../../utils/authentication-providers/keycloak-helper";
66
import { NO_USER_FOUND_IN_CATALOG_ERROR_MESSAGE } from "../../utils/constants";
@@ -535,6 +535,9 @@ test.describe("Configure OIDC provider (using RHBK)", async () => {
535535
});
536536

537537
test.afterAll(async () => {
538+
if (page !== undefined) {
539+
await teardownBrowser(page, test.info());
540+
}
538541
console.log("[TEST] Starting cleanup...");
539542
await deployment.killRunningProcess();
540543
console.log("[TEST] Cleanup completed");

e2e-tests/playwright/e2e/github-happy-path.spec.ts

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@ import { test, expect, Page, BrowserContext } from "@support/coverage/test";
22
import { UIhelper } from "../utils/ui-helper";
33
import { Common, setupBrowser, teardownBrowser } from "../utils/common";
44
import { RESOURCES } from "../support/test-data/resources";
5-
import {
6-
BackstageShowcase,
7-
CatalogImport,
8-
} from "../support/pages/catalog-import";
5+
import { RhdhInstance, CatalogImport } from "../support/pages/catalog-import";
96
import { TEMPLATES } from "../support/test-data/templates";
107

118
type GithubPullRequest = { title: string; number: string };
@@ -38,11 +35,11 @@ function parseGithubPullRequests(data: unknown): GithubPullRequest[] {
3835
});
3936
}
4037

41-
async function getShowcasePullRequests(
38+
async function getRhdhPullRequests(
4239
state: "open" | "closed" | "all",
4340
paginated = false,
4441
): Promise<GithubPullRequest[]> {
45-
const data: unknown = await BackstageShowcase.getShowcasePRs(
42+
const data: unknown = await RhdhInstance.getRhdhPullRequests(
4643
state,
4744
paginated,
4845
);
@@ -57,7 +54,7 @@ test.describe.fixme("GitHub Happy path", () => {
5754
let common: Common;
5855
let uiHelper: UIhelper;
5956
let catalogImport: CatalogImport;
60-
let backstageShowcase: BackstageShowcase;
57+
let rhdhInstance: RhdhInstance;
6158

6259
const component =
6360
"https://github.com/redhat-developer/rhdh/blob/main/catalog-entities/all.yaml";
@@ -72,7 +69,7 @@ test.describe.fixme("GitHub Happy path", () => {
7269
uiHelper = new UIhelper(page);
7370
common = new Common(page);
7471
catalogImport = new CatalogImport(page);
75-
backstageShowcase = new BackstageShowcase(page);
72+
rhdhInstance = new RhdhInstance(page);
7673
test.info().setTimeout(600 * 1000);
7774
});
7875

@@ -173,15 +170,15 @@ test.describe.fixme("GitHub Happy path", () => {
173170
await page.getByRole("button", { name: "20" }).click();
174171
await page.getByRole("option", { name: "10", exact: true }).click();
175172

176-
await backstageShowcase.verifyPRStatisticsRendered();
177-
await backstageShowcase.verifyAboutCardIsDisplayed();
173+
await rhdhInstance.verifyPRStatisticsRendered();
174+
await rhdhInstance.verifyAboutCardIsDisplayed();
178175
});
179176

180177
test("Verify that the Pull/Merge Requests tab renders the 5 most recently updated Open Pull Requests", async () => {
181178
await uiHelper.clickTab("Pull/Merge Requests");
182-
const openPRs = await getShowcasePullRequests("open");
179+
const openPRs = await getRhdhPullRequests("open");
183180
await expect(
184-
backstageShowcase.verifyPRRows(openPRs, 0, 5),
181+
rhdhInstance.verifyPRRows(openPRs, 0, 5),
185182
).resolves.toBeUndefined();
186183
});
187184

@@ -191,16 +188,16 @@ test.describe.fixme("GitHub Happy path", () => {
191188
await expect(closedButton).toBeVisible();
192189
await expect(closedButton).toBeEnabled();
193190
await closedButton.click();
194-
const closedPRs = await getShowcasePullRequests("closed");
191+
const closedPRs = await getRhdhPullRequests("closed");
195192
await common.waitForLoad();
196193
await expect(
197-
backstageShowcase.verifyPRRows(closedPRs, 0, 5),
194+
rhdhInstance.verifyPRRows(closedPRs, 0, 5),
198195
).resolves.toBeUndefined();
199196
});
200197

201198
test("Click on the arrows to verify that the next/previous/first/last pages of PRs are loaded", async () => {
202199
console.log("Fetching all PRs from GitHub");
203-
const allPRs = await getShowcasePullRequests("all", true);
200+
const allPRs = await getRhdhPullRequests("all", true);
204201

205202
console.log("Clicking on ALL button");
206203
// Use semantic selector and wait for button to be ready (no force needed)
@@ -209,30 +206,30 @@ test.describe.fixme("GitHub Happy path", () => {
209206
await expect(allButton).toBeEnabled();
210207
await allButton.click();
211208
await expect(
212-
backstageShowcase.verifyPRRows(allPRs, 0, 5),
209+
rhdhInstance.verifyPRRows(allPRs, 0, 5),
213210
).resolves.toBeUndefined();
214211

215212
console.log("Clicking on Next Page button");
216-
await backstageShowcase.clickNextPage();
213+
await rhdhInstance.clickNextPage();
217214
await expect(
218-
backstageShowcase.verifyPRRows(allPRs, 5, 10),
215+
rhdhInstance.verifyPRRows(allPRs, 5, 10),
219216
).resolves.toBeUndefined();
220217

221218
// const lastPagePRs = Math.floor((allPRs.length - 1) / 5) * 5;
222219
// redhat-developer/rhdh have more than 1000 PRs open/closed and by default the latest 1000 PR results are displayed.
223220
const lastPagePRs = 996;
224221

225222
console.log("Clicking on Last Page button");
226-
await backstageShowcase.clickLastPage();
223+
await rhdhInstance.clickLastPage();
227224
await expect(
228-
backstageShowcase.verifyPRRows(allPRs, lastPagePRs, 1000),
225+
rhdhInstance.verifyPRRows(allPRs, lastPagePRs, 1000),
229226
).resolves.toBeUndefined();
230227

231228
console.log("Clicking on Previous Page button");
232-
await backstageShowcase.clickPreviousPage();
229+
await rhdhInstance.clickPreviousPage();
233230
await common.waitForLoad();
234231
await expect(
235-
backstageShowcase.verifyPRRows(allPRs, lastPagePRs - 5, lastPagePRs - 1),
232+
rhdhInstance.verifyPRRows(allPRs, lastPagePRs - 5, lastPagePRs - 1),
236233
).resolves.toBeUndefined();
237234
});
238235

@@ -241,15 +238,15 @@ test.describe.fixme("GitHub Happy path", () => {
241238
await uiHelper.clickLink("Red Hat Developer Hub");
242239
await common.clickOnGHloginPopup();
243240
await uiHelper.clickTab("Pull/Merge Requests");
244-
const allPRs = await getShowcasePullRequests("open");
241+
const allPRs = await getRhdhPullRequests("open");
245242
await expect(
246-
backstageShowcase.verifyPRRowsPerPage(5, allPRs),
243+
rhdhInstance.verifyPRRowsPerPage(5, allPRs),
247244
).resolves.toBeUndefined();
248245
await expect(
249-
backstageShowcase.verifyPRRowsPerPage(10, allPRs),
246+
rhdhInstance.verifyPRRowsPerPage(10, allPRs),
250247
).resolves.toBeUndefined();
251248
await expect(
252-
backstageShowcase.verifyPRRowsPerPage(20, allPRs),
249+
rhdhInstance.verifyPRRowsPerPage(20, allPRs),
253250
).resolves.toBeUndefined();
254251
});
255252

e2e-tests/playwright/e2e/smoke-test.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { test } from "@support/coverage/test";
22
import { UIhelper } from "../utils/ui-helper";
33
import { Common } from "../utils/common";
4+
import { waitForRhdhReady } from "../utils/wait-for-rhdh-ready";
45

56
test.describe("Smoke test", { tag: "@smoke" }, () => {
67
let uiHelper: UIhelper;
@@ -13,13 +14,14 @@ test.describe("Smoke test", { tag: "@smoke" }, () => {
1314
});
1415
});
1516

16-
test.beforeEach(async ({ page }) => {
17+
test.beforeEach(async ({ page, request }) => {
18+
await waitForRhdhReady(request);
1719
uiHelper = new UIhelper(page);
1820
common = new Common(page);
1921
await common.loginAsGuest();
2022
});
2123

22-
test("Verify the Homepage renders", async () => {
24+
test("Verify the RHDH instance homepage renders", async () => {
2325
await uiHelper.verifyHeading("Welcome back!");
2426
});
2527
});

e2e-tests/playwright/support/page-objects/page-obj.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export const KUBERNETES_COMPONENTS = {
140140

141141
/**
142142
* BACKSTAGE_SHOWCASE_COMPONENTS - Table pagination selectors
143+
* @deprecated Use RHDH_INSTANCE_TABLE from ./rhdh-instance-table instead
143144
*/
144145
export const BACKSTAGE_SHOWCASE_COMPONENTS = {
145146
// Legacy selectors - maintained for backward compatibility
@@ -153,48 +154,21 @@ export const BACKSTAGE_SHOWCASE_COMPONENTS = {
153154
/** @deprecated Use pagination role-based selector */
154155
tablePageSelectBox: 'div[class*="MuiTablePagination-input"]',
155156

156-
// Semantic methods - preferred
157-
/**
158-
* Get next page button
159-
* ✅ Already semantic, but wrapped for consistency
160-
* @example BACKSTAGE_SHOWCASE_COMPONENTS.getNextPageButton(page).click()
161-
*/
162157
getNextPageButton: (page: Page): Locator =>
163158
page.getByRole("button", { name: "Next Page" }),
164159

165-
/**
166-
* Get previous page button
167-
* @example BACKSTAGE_SHOWCASE_COMPONENTS.getPreviousPageButton(page).click()
168-
*/
169160
getPreviousPageButton: (page: Page): Locator =>
170161
page.getByRole("button", { name: "Previous Page" }),
171162

172-
/**
173-
* Get last page button
174-
* @example BACKSTAGE_SHOWCASE_COMPONENTS.getLastPageButton(page).click()
175-
*/
176163
getLastPageButton: (page: Page): Locator =>
177164
page.getByRole("button", { name: "Last Page" }),
178165

179-
/**
180-
* Get first page button
181-
* @example BACKSTAGE_SHOWCASE_COMPONENTS.getFirstPageButton(page).click()
182-
*/
183166
getFirstPageButton: (page: Page): Locator =>
184167
page.getByRole("button", { name: "First Page" }),
185168

186-
/**
187-
* Get table rows
188-
* ✅ Preferred over tableRows
189-
* @example const rows = BACKSTAGE_SHOWCASE_COMPONENTS.getTableRows(page)
190-
*/
191169
getTableRows: (page: Page): Locator =>
192170
SemanticSelectors.table(page).locator("tbody tr"),
193171

194-
/**
195-
* Get specific table row by content
196-
* @example const row = BACKSTAGE_SHOWCASE_COMPONENTS.getTableRow(page, 'Guest User')
197-
*/
198172
getTableRow: (page: Page, text: string | RegExp): Locator =>
199173
SemanticSelectors.tableRow(page, text),
200174
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Page } from "@playwright/test";
2+
import { SemanticSelectors } from "../selectors/semantic-selectors";
3+
4+
/**
5+
* Table pagination helpers for RHDH instance catalog entity pages.
6+
*/
7+
export const RHDH_INSTANCE_TABLE = {
8+
getNextPageButton: (page: Page) =>
9+
page.getByRole("button", { name: "Next Page" }),
10+
11+
getPreviousPageButton: (page: Page) =>
12+
page.getByRole("button", { name: "Previous Page" }),
13+
14+
getLastPageButton: (page: Page) =>
15+
page.getByRole("button", { name: "Last Page" }),
16+
17+
getFirstPageButton: (page: Page) =>
18+
page.getByRole("button", { name: "First Page" }),
19+
20+
getTableRows: (page: Page) => SemanticSelectors.table(page).getByRole("row"),
21+
22+
getTableRow: (page: Page, text: string | RegExp) =>
23+
SemanticSelectors.tableRow(page, text),
24+
};

0 commit comments

Comments
 (0)