Skip to content

Commit 2d1beca

Browse files
committed
feat(helpers): add BUI-aware waits and shared catalog/notification helpers
- Extend WAIT_OBJECTS; add waitForAppReady() and fix openSidebar click - Add getSessionAuthToken, CatalogApiHelper, and RhdhNotificationsApi - Update NotificationPage with additive MUI + BUI selectors - Add unit tests and docs for all of the above - Bump version to 2.2.0 Assisted-By: Cursor Desktop rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED
1 parent 1987a9e commit 2d1beca

26 files changed

Lines changed: 1276 additions & 150 deletions

docs/.vitepress/config.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default defineConfig({
3333
{ text: "Examples", link: "/examples/" },
3434
{ text: "Overlay Testing", link: "/overlay/" },
3535
{
36-
text: "v1.1.39",
36+
text: "v2.2.0",
3737
items: [{ text: "Changelog", link: "/changelog" }],
3838
},
3939
],
@@ -121,6 +121,14 @@ export default defineConfig({
121121
{ text: "LoginHelper", link: "/guide/helpers/login-helper" },
122122
{ text: "APIHelper", link: "/guide/helpers/api-helper" },
123123
{ text: "AuthApiHelper", link: "/guide/helpers/auth-api-helper" },
124+
{
125+
text: "CatalogApiHelper",
126+
link: "/guide/helpers/catalog-api-helper",
127+
},
128+
{
129+
text: "RhdhNotificationsApi",
130+
link: "/guide/helpers/notifications-api-helper",
131+
},
124132
{ text: "RbacApiHelper", link: "/guide/helpers/rbac-api-helper" },
125133
],
126134
},
@@ -227,6 +235,14 @@ export default defineConfig({
227235
{ text: "LoginHelper", link: "/api/helpers/login-helper" },
228236
{ text: "APIHelper", link: "/api/helpers/api-helper" },
229237
{ text: "AuthApiHelper", link: "/api/helpers/auth-api-helper" },
238+
{
239+
text: "CatalogApiHelper",
240+
link: "/api/helpers/catalog-api-helper",
241+
},
242+
{
243+
text: "RhdhNotificationsApi",
244+
link: "/api/helpers/notifications-api-helper",
245+
},
230246
{ text: "RbacApiHelper", link: "/api/helpers/rbac-api-helper" },
231247
],
232248
},

docs/api/helpers/auth-api-helper.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,28 @@ const token = await authApiHelper.getToken();
5151
// Custom provider
5252
const token = await authApiHelper.getToken('github');
5353
```
54+
55+
## `getSessionAuthToken()`
56+
57+
```typescript
58+
async function getSessionAuthToken(
59+
page: Page,
60+
uiHelper: UIhelper,
61+
baseUrl: string,
62+
): Promise<string>
63+
```
64+
65+
Polls `AuthApiHelper.getToken()` until a non-empty token is returned. Navigates to `baseUrl` and calls `uiHelper.waitForAppReady()` when the first attempt fails.
66+
67+
| Parameter | Type | Description |
68+
| --------- | ---- | ----------- |
69+
| `page` | `Page` | Authenticated Playwright page |
70+
| `uiHelper` | `UIhelper` | Used for `waitForAppReady()` after navigation |
71+
| `baseUrl` | `string` | RHDH base URL (e.g. `process.env.RHDH_BASE_URL`) |
72+
73+
**Returns** `Promise<string>`Backstage identity bearer token.
74+
75+
## Related Pages
76+
77+
- [AuthApiHelper Guide](/guide/helpers/auth-api-helper) — usage guide
78+
- [CatalogApiHelper](/api/helpers/catalog-api-helper) — typical consumer of session tokens
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# CatalogApiHelper API
2+
3+
Static helper for RHDH catalog entity lookups via the REST API.
4+
5+
## Import
6+
7+
```typescript
8+
import { CatalogApiHelper } from "@red-hat-developer-hub/e2e-test-utils/helpers";
9+
```
10+
11+
## Methods
12+
13+
### `entityExists()`
14+
15+
```typescript
16+
static async entityExists(
17+
baseUrl: string,
18+
token: string,
19+
kind: string,
20+
name: string,
21+
namespace?: string,
22+
): Promise<boolean>
23+
```
24+
25+
Returns `true` if the entity exists. Returns `false` on HTTP 404. Rethrows other HTTP errors.
26+
27+
### `getEntity()`
28+
29+
```typescript
30+
static async getEntity(
31+
baseUrl: string,
32+
token: string,
33+
kind: string,
34+
name: string,
35+
namespace?: string,
36+
): Promise<unknown>
37+
```
38+
39+
Fetches `GET /api/catalog/entities/by-name/{kind}/{namespace}/{name}`.
40+
41+
### `getEntityDescription()`
42+
43+
```typescript
44+
static async getEntityDescription(
45+
baseUrl: string,
46+
token: string,
47+
kind: string,
48+
name: string,
49+
namespace?: string,
50+
): Promise<string | undefined>
51+
```
52+
53+
Returns `metadata.description` from the entity JSON.
54+
55+
### `getGroupEntity()`
56+
57+
```typescript
58+
static async getGroupEntity(
59+
baseUrl: string,
60+
token: string,
61+
groupName: string,
62+
): Promise<unknown>
63+
```
64+
65+
### `getGroupMembers()`
66+
67+
```typescript
68+
static async getGroupMembers(
69+
baseUrl: string,
70+
token: string,
71+
groupName: string,
72+
): Promise<string[]>
73+
```
74+
75+
### `dispose()`
76+
77+
```typescript
78+
static async dispose(): Promise<void>
79+
```
80+
81+
Disposes the internal Playwright `APIRequestContext`.
82+
83+
## Related Pages
84+
85+
- [CatalogApiHelper Guide](/guide/helpers/catalog-api-helper) — usage guide and polling patterns
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# RhdhNotificationsApi API
2+
3+
Typed REST helper for the RHDH notifications API.
4+
5+
## Import
6+
7+
```typescript
8+
import {
9+
RhdhNotificationsApi,
10+
type NotificationRequest,
11+
type NotificationPayload,
12+
type NotificationRecipients,
13+
type NotificationSeverity,
14+
} from "@red-hat-developer-hub/e2e-test-utils/helpers";
15+
```
16+
17+
## Factory
18+
19+
### `build()`
20+
21+
```typescript
22+
static async build(token: string): Promise<RhdhNotificationsApi>
23+
```
24+
25+
Creates an API client using `${RHDH_BASE_URL}/api/` as the base URL.
26+
27+
## Methods
28+
29+
### `createNotification()`
30+
31+
```typescript
32+
async createNotification(
33+
notification: NotificationRequest,
34+
): Promise<APIResponse>
35+
```
36+
37+
`POST /api/notifications`
38+
39+
### `markAllNotificationsAsRead()`
40+
41+
```typescript
42+
async markAllNotificationsAsRead(): Promise<APIResponse>
43+
```
44+
45+
`PATCH /api/notifications` with `{ ids: [], read: true }`.
46+
47+
## Types
48+
49+
### `NotificationSeverity`
50+
51+
```typescript
52+
type NotificationSeverity = "critical" | "high" | "normal" | "low";
53+
```
54+
55+
### `NotificationRequest`
56+
57+
```typescript
58+
interface NotificationRequest {
59+
recipients: NotificationRecipients;
60+
payload: NotificationPayload;
61+
}
62+
```
63+
64+
### `BroadcastRecipients`
65+
66+
```typescript
67+
type BroadcastRecipients = { type: "broadcast" };
68+
```
69+
70+
### `EntityRecipients`
71+
72+
```typescript
73+
type EntityRecipients = {
74+
type: "entity";
75+
entityRef: string | string[];
76+
excludeEntityRef?: string | string[];
77+
};
78+
```
79+
80+
## Related Pages
81+
82+
- [RhdhNotificationsApi Guide](/guide/helpers/notifications-api-helper) — usage examples

docs/api/helpers/ui-helper.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# UIhelper API
22

3-
UI interaction helper for Material-UI components.
3+
UI interaction helper for RHDH components (MUI and BUI).
44

55
## Import
66

@@ -22,7 +22,13 @@ new UIhelper(page: Page)
2222
```typescript
2323
async waitForLoad(timeout?: number): Promise<void>
2424
```
25-
Wait for page to fully load.
25+
Wait for MUI and BUI loading indicators to clear. Default timeout: `120000` ms.
26+
27+
#### `waitForAppReady()`
28+
```typescript
29+
async waitForAppReady(timeout?: number): Promise<void>
30+
```
31+
Alias for `waitForLoad()`.
2632

2733
#### `dismissQuickstartIfVisible()`
2834
```typescript

docs/api/index.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ Complete API documentation for all exports from `@red-hat-developer-hub/e2e-test
3535
- [UIhelper](/api/helpers/ui-helper) - UI interaction methods
3636
- [LoginHelper](/api/helpers/login-helper) - Authentication methods
3737
- [APIHelper](/api/helpers/api-helper) - API interaction methods
38+
- [AuthApiHelper](/api/helpers/auth-api-helper) - Backstage identity tokens
39+
- [`getSessionAuthToken`](/api/helpers/auth-api-helper#getsessionauthtoken) - Resilient token retrieval
40+
- [CatalogApiHelper](/api/helpers/catalog-api-helper) - Catalog REST polling
41+
- [RhdhNotificationsApi](/api/helpers/notifications-api-helper) - Notifications REST API
42+
- [RbacApiHelper](/api/helpers/rbac-api-helper) - RBAC policy management
3843

3944
### Page Objects
4045

docs/api/pages/notification-page.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ import { NotificationPage } from "@red-hat-developer-hub/e2e-test-utils/pages";
1111
## Constructor
1212

1313
```typescript
14-
new NotificationPage(page: Page)
14+
new NotificationPage(page: Page, uiHelper?: UIhelper)
1515
```
1616

17-
Creates a new NotificationPage instance with an internal `UIhelper`.
17+
Creates a new NotificationPage instance. When `uiHelper` is omitted, an internal `UIhelper` is created.
1818

1919
| Parameter | Type | Description |
2020
|-----------|------|-------------|
2121
| `page` | `Page` | Playwright Page object |
22+
| `uiHelper` | `UIhelper` | Optional fixture UIhelper for shared wait/navigation behavior |
23+
24+
Supports both MUI (legacy) and BUI (new frontend system) selectors.
2225

2326
## Methods
2427

@@ -42,17 +45,20 @@ async selectAllNotifications(): Promise<void>
4245

4346
Select all notifications using the header checkbox.
4447

45-
#### `selectNotification(nth?)`
48+
#### `selectNotification(textOrNth?)`
4649

4750
```typescript
48-
async selectNotification(nth?: number): Promise<void>
51+
async selectNotification(
52+
textOrNth?: string | RegExp | number,
53+
): Promise<void>
4954
```
5055

51-
Select a specific notification by index.
56+
Select a notification by row title or by checkbox index.
5257

53-
| Parameter | Type | Default | Description |
54-
|-----------|------|---------|-------------|
55-
| `nth` | `number` | `1` | Zero-based index of the notification to select |
58+
| Parameter | Type | Description |
59+
|-----------|------|-------------|
60+
| `textOrNth` | `string \| RegExp` | Row title to select (preferred) |
61+
| `textOrNth` | `number` | Zero-based checkbox index (legacy) |
5662

5763
### Notification Content
5864

docs/changelog.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,21 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
## [2.1.1] - Current
5+
## [2.2.0] - Current
6+
7+
### Added
8+
9+
- **`UIhelper.waitForAppReady()`**: Waits for MUI and BUI loading indicators to clear (extends `WAIT_OBJECTS` with BUI progress/spinner selectors).
10+
- **`getSessionAuthToken()`**: Retrieves a bearer token from the logged-in browser session without unnecessary navigation.
11+
- **`CatalogApiHelper`**: Static catalog API helper (`entityExists`, `getEntity`, `getEntityDescription`, `getGroupMembers`) for event-driven discovery polling.
12+
- **`RhdhNotificationsApi`**: Typed notifications REST helper with valid broadcast/entity recipient shapes and lowercase severity values.
13+
14+
### Changed
15+
16+
- **`NotificationPage`**: Additive MUI + BUI support — tries legacy selectors (`loading-indicator`, `Severity`, `getByTitle`) and BUI selectors (`Min severity`, `aria-label` bulk actions, row checkboxes). Optional `uiHelper` constructor argument. `selectNotification` accepts a row title (`string`/`RegExp`) or legacy checkbox index (`number`).
17+
- **`UIhelper.openSidebar`**: Uses a real `.click()` instead of `dispatchEvent("click")` for more reliable navigation.
18+
19+
## [2.1.1]
620

721
### Changed
822

docs/guide/helpers/auth-api-helper.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,35 @@ try {
7575

7676
## Related Pages
7777

78+
- [getSessionAuthToken](#getsessionauthtoken) — resilient token retrieval after login
7879
- [RbacApiHelper](/guide/helpers/rbac-api-helper) — uses tokens obtained from `AuthApiHelper`
7980
- [LoginHelper](/guide/helpers/login-helper) — authenticates the browser session before calling `getToken`
81+
- [CatalogApiHelper](/guide/helpers/catalog-api-helper) — catalog REST queries with a bearer token
8082
- [APIHelper](/guide/helpers/api-helper) — catalog and GitHub API operations
8183
- [Common Patterns](/overlay/reference/patterns#fetching-a-token-to-use-with-rbacapihelper) — example of using `getToken` with `RbacApiHelper`
84+
85+
## `getSessionAuthToken(page, uiHelper, baseUrl)`
86+
87+
Standalone function that retrieves a Backstage bearer token from the logged-in browser session. Unlike calling `AuthApiHelper.getToken()` directly, it polls until a token is available and navigates to `baseUrl` only when the first attempt fails.
88+
89+
```typescript
90+
import {
91+
AuthApiHelper,
92+
getSessionAuthToken,
93+
} from "@red-hat-developer-hub/e2e-test-utils/helpers";
94+
95+
test.beforeEach(async ({ page, uiHelper, loginHelper }) => {
96+
await loginHelper.loginAsKeycloakUser();
97+
});
98+
99+
test("catalog API", async ({ page, uiHelper }) => {
100+
const token = await getSessionAuthToken(
101+
page,
102+
uiHelper,
103+
process.env.RHDH_BASE_URL!,
104+
);
105+
// use token with CatalogApiHelper, RbacApiHelper, etc.
106+
});
107+
```
108+
109+
Use this in discovery tests that need a stable token after Keycloak login without duplicating retry logic in each workspace.

0 commit comments

Comments
 (0)