rhdh-e2e-test-utils 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +652 -56
- package/dist/deployment/keycloak/config/keycloak-values.yaml +94 -0
- package/dist/deployment/keycloak/constants.d.ts +29 -0
- package/dist/deployment/keycloak/constants.d.ts.map +1 -0
- package/dist/deployment/keycloak/constants.js +75 -0
- package/dist/deployment/keycloak/deployment.d.ts +89 -0
- package/dist/deployment/keycloak/deployment.d.ts.map +1 -0
- package/dist/deployment/keycloak/deployment.js +437 -0
- package/dist/deployment/keycloak/index.d.ts +2 -0
- package/dist/deployment/keycloak/index.d.ts.map +1 -0
- package/dist/deployment/keycloak/index.js +1 -0
- package/dist/deployment/keycloak/types.d.ts +59 -0
- package/dist/deployment/keycloak/types.d.ts.map +1 -0
- package/dist/deployment/keycloak/types.js +1 -0
- package/dist/deployment/rhdh/config/auth/guest/app-config.yaml +5 -0
- package/dist/deployment/rhdh/config/auth/keycloak/app-config.yaml +19 -0
- package/dist/deployment/rhdh/config/auth/keycloak/dynamic-plugins.yaml +3 -0
- package/dist/deployment/rhdh/config/auth/keycloak/secrets.yaml +12 -0
- package/dist/deployment/rhdh/config/common/app-config-rhdh.yaml +6 -0
- package/dist/deployment/rhdh/config/common/dynamic-plugins.yaml +3 -0
- package/dist/deployment/rhdh/config/common/rhdh-secrets.yaml +7 -0
- package/dist/deployment/rhdh/config/helm/value_file.yaml +7 -0
- package/dist/deployment/rhdh/config/operator/subscription.yaml +21 -0
- package/dist/deployment/rhdh/constants.d.ts +6 -0
- package/dist/deployment/rhdh/constants.d.ts.map +1 -1
- package/dist/deployment/rhdh/constants.js +17 -5
- package/dist/deployment/rhdh/deployment.d.ts +8 -1
- package/dist/deployment/rhdh/deployment.d.ts.map +1 -1
- package/dist/deployment/rhdh/deployment.js +47 -39
- package/dist/deployment/rhdh/index.d.ts +0 -1
- package/dist/deployment/rhdh/index.d.ts.map +1 -1
- package/dist/deployment/rhdh/types.d.ts +4 -1
- package/dist/deployment/rhdh/types.d.ts.map +1 -1
- package/dist/eslint/base.config.d.ts.map +1 -1
- package/dist/eslint/base.config.js +9 -2
- package/dist/playwright/base-config.d.ts +3 -3
- package/dist/playwright/base-config.d.ts.map +1 -1
- package/dist/playwright/base-config.js +5 -4
- package/dist/playwright/fixtures/test.d.ts +4 -1
- package/dist/playwright/fixtures/test.d.ts.map +1 -1
- package/dist/playwright/fixtures/test.js +16 -4
- package/dist/playwright/global-setup.d.ts.map +1 -1
- package/dist/playwright/global-setup.js +36 -1
- package/dist/playwright/helpers/accessibility.d.ts +13 -0
- package/dist/playwright/helpers/accessibility.d.ts.map +1 -0
- package/dist/playwright/helpers/accessibility.js +24 -0
- package/dist/playwright/helpers/api-endpoints.d.ts +11 -0
- package/dist/playwright/helpers/api-endpoints.d.ts.map +1 -0
- package/dist/playwright/helpers/api-endpoints.js +15 -0
- package/dist/playwright/helpers/api-helper.d.ts +77 -0
- package/dist/playwright/helpers/api-helper.d.ts.map +1 -0
- package/dist/playwright/helpers/api-helper.js +285 -0
- package/dist/playwright/helpers/common.d.ts +31 -0
- package/dist/playwright/helpers/common.d.ts.map +1 -0
- package/dist/playwright/helpers/common.js +342 -0
- package/dist/playwright/helpers/index.d.ts +5 -0
- package/dist/playwright/helpers/index.d.ts.map +1 -0
- package/dist/playwright/helpers/index.js +4 -0
- package/dist/playwright/helpers/navbar.d.ts +2 -0
- package/dist/playwright/helpers/navbar.d.ts.map +1 -0
- package/dist/playwright/helpers/navbar.js +1 -0
- package/dist/playwright/helpers/ui-helper.d.ts +106 -0
- package/dist/playwright/helpers/ui-helper.d.ts.map +1 -0
- package/dist/playwright/helpers/ui-helper.js +439 -0
- package/dist/playwright/page-objects/global-obj.d.ts +25 -0
- package/dist/playwright/page-objects/global-obj.d.ts.map +1 -0
- package/dist/playwright/page-objects/global-obj.js +24 -0
- package/dist/playwright/page-objects/page-obj.d.ts +41 -0
- package/dist/playwright/page-objects/page-obj.d.ts.map +1 -0
- package/dist/playwright/page-objects/page-obj.js +40 -0
- package/dist/playwright/pages/catalog-import.d.ts +31 -0
- package/dist/playwright/pages/catalog-import.d.ts.map +1 -0
- package/dist/playwright/pages/catalog-import.js +65 -0
- package/dist/playwright/pages/catalog.d.ts +14 -0
- package/dist/playwright/pages/catalog.d.ts.map +1 -0
- package/dist/playwright/pages/catalog.js +37 -0
- package/dist/playwright/pages/extensions.d.ts +38 -0
- package/dist/playwright/pages/extensions.d.ts.map +1 -0
- package/dist/playwright/pages/extensions.js +110 -0
- package/dist/playwright/pages/home-page.d.ts +10 -0
- package/dist/playwright/pages/home-page.d.ts.map +1 -0
- package/dist/playwright/pages/home-page.js +46 -0
- package/dist/playwright/pages/index.d.ts +6 -0
- package/dist/playwright/pages/index.d.ts.map +1 -0
- package/dist/playwright/pages/index.js +5 -0
- package/dist/playwright/pages/notifications.d.ts +24 -0
- package/dist/playwright/pages/notifications.d.ts.map +1 -0
- package/dist/playwright/pages/notifications.js +112 -0
- package/dist/utils/kubernetes-client.d.ts +9 -0
- package/dist/utils/kubernetes-client.d.ts.map +1 -1
- package/dist/utils/kubernetes-client.js +57 -2
- package/dist/utils/merge-yamls.d.ts +25 -4
- package/dist/utils/merge-yamls.d.ts.map +1 -1
- package/dist/utils/merge-yamls.js +52 -12
- package/package.json +19 -6
package/README.md
CHANGED
|
@@ -13,20 +13,27 @@ A comprehensive test utility package for Red Hat Developer Hub (RHDH) end-to-end
|
|
|
13
13
|
- [Detailed Usage](#detailed-usage)
|
|
14
14
|
- [Playwright Test Fixtures](#playwright-test-fixtures)
|
|
15
15
|
- [Playwright Configuration](#playwright-configuration)
|
|
16
|
+
- [Global Setup](#global-setup)
|
|
16
17
|
- [RHDH Deployment](#rhdh-deployment)
|
|
18
|
+
- [Keycloak Deployment](#keycloak-deployment)
|
|
17
19
|
- [Utilities](#utilities)
|
|
20
|
+
- [Helpers](#helpers)
|
|
21
|
+
- [Page Objects](#page-objects)
|
|
18
22
|
- [ESLint Configuration](#eslint-configuration)
|
|
19
23
|
- [TypeScript Configuration](#typescript-configuration)
|
|
20
24
|
- [Configuration Files](#configuration-files)
|
|
21
25
|
- [Environment Variables](#environment-variables)
|
|
22
26
|
- [Examples](#examples)
|
|
23
27
|
- [Development](#development)
|
|
28
|
+
- [Testing Local Changes in Consumer Projects](#testing-local-changes-in-consumer-projects)
|
|
24
29
|
|
|
25
30
|
## Overview
|
|
26
31
|
|
|
27
32
|
`rhdh-e2e-test-utils` simplifies end-to-end testing for RHDH plugins by providing:
|
|
28
33
|
|
|
29
34
|
- **Automated RHDH Deployment**: Deploy RHDH instances via Helm or the RHDH Operator
|
|
35
|
+
- **Keycloak Integration**: Deploy and configure Keycloak for OIDC authentication testing
|
|
36
|
+
- **Modular Auth Configuration**: Switch between guest and Keycloak authentication with a single option
|
|
30
37
|
- **Playwright Integration**: Custom test fixtures that manage deployment lifecycle
|
|
31
38
|
- **Kubernetes Utilities**: Helper functions for managing namespaces, ConfigMaps, Secrets, and Routes
|
|
32
39
|
- **Configuration Merging**: YAML merging with environment variable substitution
|
|
@@ -35,6 +42,8 @@ A comprehensive test utility package for Red Hat Developer Hub (RHDH) end-to-end
|
|
|
35
42
|
## Features
|
|
36
43
|
|
|
37
44
|
- Deploy RHDH using Helm charts or the RHDH Operator
|
|
45
|
+
- Deploy Keycloak for authentication testing with automatic realm, client, and user configuration
|
|
46
|
+
- Modular authentication configuration (guest, Keycloak)
|
|
38
47
|
- Automatic namespace creation and cleanup
|
|
39
48
|
- Dynamic plugin configuration
|
|
40
49
|
- Helpers for UI, API and common Utils
|
|
@@ -79,7 +88,10 @@ The package provides multiple entry points for different use cases:
|
|
|
79
88
|
| `rhdh-e2e-test-utils/test` | Playwright test fixtures with RHDH deployment |
|
|
80
89
|
| `rhdh-e2e-test-utils/playwright-config` | Base Playwright configuration |
|
|
81
90
|
| `rhdh-e2e-test-utils/rhdh` | RHDH deployment class and types |
|
|
91
|
+
| `rhdh-e2e-test-utils/keycloak` | Keycloak deployment helper for authentication testing |
|
|
82
92
|
| `rhdh-e2e-test-utils/utils` | Utility functions (bash, YAML, Kubernetes) |
|
|
93
|
+
| `rhdh-e2e-test-utils/helpers` | UI, API, and login helper classes |
|
|
94
|
+
| `rhdh-e2e-test-utils/pages` | Page object classes for common RHDH pages |
|
|
83
95
|
| `rhdh-e2e-test-utils/eslint` | ESLint configuration factory |
|
|
84
96
|
| `rhdh-e2e-test-utils/tsconfig` | Base TypeScript configuration |
|
|
85
97
|
|
|
@@ -97,18 +109,15 @@ yarn add @playwright/test rhdh-e2e-test-utils
|
|
|
97
109
|
|
|
98
110
|
```typescript
|
|
99
111
|
// playwright.config.ts
|
|
100
|
-
import { defineConfig } from "
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
],
|
|
110
|
-
})
|
|
111
|
-
);
|
|
112
|
+
import { defineConfig } from "rhdh-e2e-test-utils/playwright-config";
|
|
113
|
+
|
|
114
|
+
export default defineConfig({
|
|
115
|
+
projects: [
|
|
116
|
+
{
|
|
117
|
+
name: "my-plugin",
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
});
|
|
112
121
|
```
|
|
113
122
|
|
|
114
123
|
### 3. Create Your Test
|
|
@@ -129,10 +138,10 @@ test("my plugin test", async ({ page }) => {
|
|
|
129
138
|
|
|
130
139
|
### 4. Create Configuration Files
|
|
131
140
|
|
|
132
|
-
Create a `config/` directory with your RHDH configuration:
|
|
141
|
+
Create a `tests/config/` directory with your RHDH configuration:
|
|
133
142
|
|
|
134
143
|
```
|
|
135
|
-
config/
|
|
144
|
+
tests/config/
|
|
136
145
|
├── app-config-rhdh.yaml # App configuration
|
|
137
146
|
├── dynamic-plugins.yaml # Dynamic plugins configuration
|
|
138
147
|
└── rhdh-secrets.yaml # Secrets (with env var placeholders)
|
|
@@ -166,6 +175,8 @@ import { test, expect } from "rhdh-e2e-test-utils/test";
|
|
|
166
175
|
| Fixture | Scope | Description |
|
|
167
176
|
|---------|-------|-------------|
|
|
168
177
|
| `rhdh` | worker | Shared RHDHDeployment across all tests in a worker |
|
|
178
|
+
| `uiHelper` | test | UIhelper instance for common UI interactions |
|
|
179
|
+
| `loginHelper` | test | LoginHelper instance for authentication flows |
|
|
169
180
|
| `baseURL` | test | Automatically set to the RHDH instance URL |
|
|
170
181
|
|
|
171
182
|
#### Fixture Behavior
|
|
@@ -176,6 +187,7 @@ import { test, expect } from "rhdh-e2e-test-utils/test";
|
|
|
176
187
|
|
|
177
188
|
```typescript
|
|
178
189
|
import { test, expect } from "rhdh-e2e-test-utils/test";
|
|
190
|
+
|
|
179
191
|
test.beforeAll(async ({ rhdh }) => {
|
|
180
192
|
// Configure RHDH (creates namespace, and optional DeploymentOptions)
|
|
181
193
|
await rhdh.configure();
|
|
@@ -187,10 +199,17 @@ test.beforeAll(async ({ rhdh }) => {
|
|
|
187
199
|
await rhdh.deploy();
|
|
188
200
|
});
|
|
189
201
|
|
|
190
|
-
test("example test", async ({ page, rhdh }) => {
|
|
202
|
+
test("example test", async ({ page, rhdh, uiHelper, loginHelper }) => {
|
|
191
203
|
// page.goto("/") will use rhdh.rhdhUrl as base
|
|
192
204
|
await page.goto("/");
|
|
193
205
|
|
|
206
|
+
// Login as guest user
|
|
207
|
+
await loginHelper.loginAsGuest();
|
|
208
|
+
|
|
209
|
+
// Use UI helper for common interactions
|
|
210
|
+
await uiHelper.verifyHeading("Welcome");
|
|
211
|
+
await uiHelper.clickButton("Get Started");
|
|
212
|
+
|
|
194
213
|
// Access deployment info
|
|
195
214
|
console.log(`Namespace: ${rhdh.deploymentConfig.namespace}`);
|
|
196
215
|
console.log(`URL: ${rhdh.rhdhUrl}`);
|
|
@@ -204,24 +223,22 @@ test("example test", async ({ page, rhdh }) => {
|
|
|
204
223
|
|
|
205
224
|
### Playwright Configuration
|
|
206
225
|
|
|
207
|
-
Use `
|
|
226
|
+
Use `defineConfig` for sensible defaults:
|
|
208
227
|
|
|
209
228
|
```typescript
|
|
210
|
-
|
|
211
|
-
import {
|
|
212
|
-
|
|
213
|
-
export default defineConfig(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
})
|
|
224
|
-
);
|
|
229
|
+
// playwright.config.ts
|
|
230
|
+
import { defineConfig } from "rhdh-e2e-test-utils/playwright-config";
|
|
231
|
+
|
|
232
|
+
export default defineConfig({
|
|
233
|
+
projects: [
|
|
234
|
+
{
|
|
235
|
+
name: "tech-radar", // Also used as namespace
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: "catalog",
|
|
239
|
+
},
|
|
240
|
+
],
|
|
241
|
+
});
|
|
225
242
|
```
|
|
226
243
|
|
|
227
244
|
#### Base Configuration Defaults
|
|
@@ -237,6 +254,41 @@ export default defineConfig(
|
|
|
237
254
|
| `trace` | Retain on failure |
|
|
238
255
|
| `screenshot` | Only on failure |
|
|
239
256
|
|
|
257
|
+
#### Global Setup
|
|
258
|
+
|
|
259
|
+
The package includes a global setup function that runs once before all tests. It performs the following:
|
|
260
|
+
|
|
261
|
+
1. **Binary Check**: Verifies that required binaries (`oc`, `kubectl`, `helm`) are installed
|
|
262
|
+
2. **Cluster Router Base**: Fetches the OpenShift ingress domain and sets `K8S_CLUSTER_ROUTER_BASE`
|
|
263
|
+
3. **Keycloak Deployment**: Automatically deploys and configures Keycloak for OIDC authentication
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// playwright.config.ts
|
|
267
|
+
import { defineConfig } from "rhdh-e2e-test-utils/playwright-config";
|
|
268
|
+
|
|
269
|
+
export default defineConfig({
|
|
270
|
+
// Global setup is automatically included
|
|
271
|
+
projects: [{ name: "my-plugin" }],
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
**Keycloak Auto-Deployment Behavior:**
|
|
276
|
+
|
|
277
|
+
- Keycloak is deployed to the `rhdh-keycloak` namespace
|
|
278
|
+
- If Keycloak is already running, deployment is skipped
|
|
279
|
+
- All Keycloak environment variables are automatically set after deployment
|
|
280
|
+
- The following test credentials are created:
|
|
281
|
+
- Username: `test1`, Password: `test1@123`
|
|
282
|
+
- Username: `test2`, Password: `test2@123`
|
|
283
|
+
|
|
284
|
+
**Skip Keycloak Deployment:**
|
|
285
|
+
|
|
286
|
+
If your tests don't require Keycloak/OIDC authentication, set the environment variable:
|
|
287
|
+
|
|
288
|
+
```bash
|
|
289
|
+
SKIP_KEYCLOAK_DEPLOYMENT=true yarn playwright test
|
|
290
|
+
```
|
|
291
|
+
|
|
240
292
|
### RHDH Deployment
|
|
241
293
|
|
|
242
294
|
#### RHDHDeployment Class
|
|
@@ -246,25 +298,33 @@ The core class for managing RHDH deployments:
|
|
|
246
298
|
```typescript
|
|
247
299
|
import { RHDHDeployment } from "rhdh-e2e-test-utils/rhdh";
|
|
248
300
|
|
|
249
|
-
|
|
250
|
-
|
|
301
|
+
// Create deployment with namespace (required)
|
|
302
|
+
const deployment = new RHDHDeployment("my-test-namespace");
|
|
303
|
+
|
|
304
|
+
// Configure with options (call before deploy)
|
|
305
|
+
await deployment.configure({
|
|
251
306
|
version: "1.5", // Optional, uses RHDH_VERSION env
|
|
252
307
|
method: "helm", // Optional, uses INSTALLATION_METHOD env
|
|
308
|
+
auth: "keycloak", // Optional, defaults to "keycloak"
|
|
253
309
|
appConfig: "config/app-config-rhdh.yaml", // Optional
|
|
254
310
|
secrets: "config/rhdh-secrets.yaml", // Optional
|
|
255
311
|
dynamicPlugins: "config/dynamic-plugins.yaml", // Optional
|
|
256
312
|
valueFile: "config/value_file.yaml", // Optional & Helm only
|
|
257
313
|
subscription: "config/subscription.yaml", // Optional & Operator only
|
|
258
314
|
});
|
|
315
|
+
|
|
316
|
+
// Deploy RHDH
|
|
317
|
+
await deployment.deploy();
|
|
259
318
|
```
|
|
260
319
|
|
|
261
320
|
#### Deployment Options
|
|
262
321
|
|
|
263
322
|
```typescript
|
|
264
323
|
type DeploymentOptions = {
|
|
265
|
-
namespace
|
|
324
|
+
namespace?: string; // Kubernetes namespace (set via constructor)
|
|
266
325
|
version?: string; // RHDH version (e.g., "1.5", "1.5.1-CI")
|
|
267
326
|
method?: "helm" | "operator"; // Installation method
|
|
327
|
+
auth?: "guest" | "keycloak"; // Authentication provider (default: "keycloak")
|
|
268
328
|
appConfig?: string; // Path to app-config YAML
|
|
269
329
|
secrets?: string; // Path to secrets YAML
|
|
270
330
|
dynamicPlugins?: string; // Path to dynamic-plugins YAML
|
|
@@ -273,6 +333,17 @@ type DeploymentOptions = {
|
|
|
273
333
|
};
|
|
274
334
|
```
|
|
275
335
|
|
|
336
|
+
#### Authentication Providers
|
|
337
|
+
|
|
338
|
+
The package supports modular authentication configuration. Set the `auth` option to automatically include the appropriate auth-specific configurations:
|
|
339
|
+
|
|
340
|
+
| Provider | Description |
|
|
341
|
+
|----------|-------------|
|
|
342
|
+
| `guest` | Guest authentication for development/testing |
|
|
343
|
+
| `keycloak` | OIDC authentication via Keycloak (default) |
|
|
344
|
+
|
|
345
|
+
Auth-specific configurations are automatically merged with your project configurations. For Keycloak authentication, see [Keycloak Deployment](#keycloak-deployment).
|
|
346
|
+
|
|
276
347
|
#### Deployment Methods
|
|
277
348
|
|
|
278
349
|
##### Helm Deployment
|
|
@@ -317,6 +388,162 @@ await rhdh.deploy();
|
|
|
317
388
|
| `deploymentConfig` | `DeploymentConfig` | Current deployment configuration |
|
|
318
389
|
| `k8sClient` | `KubernetesClientHelper` | Kubernetes client instance |
|
|
319
390
|
|
|
391
|
+
### Keycloak Deployment
|
|
392
|
+
|
|
393
|
+
The package provides a `KeycloakHelper` class for deploying and configuring Keycloak in OpenShift, enabling OIDC authentication testing with RHDH.
|
|
394
|
+
|
|
395
|
+
#### KeycloakHelper Class
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
import { KeycloakHelper } from "rhdh-e2e-test-utils/keycloak";
|
|
399
|
+
|
|
400
|
+
const keycloak = new KeycloakHelper({
|
|
401
|
+
namespace: "rhdh-keycloak", // Optional, defaults to "rhdh-keycloak"
|
|
402
|
+
releaseName: "keycloak", // Optional, defaults to "keycloak"
|
|
403
|
+
adminUser: "admin", // Optional, defaults to "admin"
|
|
404
|
+
adminPassword: "admin123", // Optional, defaults to "admin123"
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Deploy Keycloak using Bitnami Helm chart
|
|
408
|
+
await keycloak.deploy();
|
|
409
|
+
|
|
410
|
+
// Configure realm, client, groups, and users for RHDH
|
|
411
|
+
await keycloak.configureForRHDH();
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
#### Deployment Options
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
type KeycloakDeploymentOptions = {
|
|
418
|
+
namespace?: string; // Kubernetes namespace (default: "rhdh-keycloak")
|
|
419
|
+
releaseName?: string; // Helm release name (default: "keycloak")
|
|
420
|
+
valuesFile?: string; // Custom Helm values file
|
|
421
|
+
adminUser?: string; // Admin username (default: "admin")
|
|
422
|
+
adminPassword?: string; // Admin password (default: "admin123")
|
|
423
|
+
};
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
#### KeycloakHelper API
|
|
427
|
+
|
|
428
|
+
| Method | Description |
|
|
429
|
+
|--------|-------------|
|
|
430
|
+
| `deploy()` | Deploy Keycloak using Helm and wait for it to be ready |
|
|
431
|
+
| `configureForRHDH(options?)` | Configure realm, client, groups, and users for RHDH |
|
|
432
|
+
| `isRunning()` | Check if Keycloak is accessible |
|
|
433
|
+
| `connect(config)` | Connect to an existing Keycloak instance |
|
|
434
|
+
| `createRealm(config)` | Create a new realm |
|
|
435
|
+
| `createClient(realm, config)` | Create a client in a realm |
|
|
436
|
+
| `createGroup(realm, config)` | Create a group in a realm |
|
|
437
|
+
| `createUser(realm, config)` | Create a user with optional group membership |
|
|
438
|
+
| `getUsers(realm)` | Get all users in a realm |
|
|
439
|
+
| `getGroups(realm)` | Get all groups in a realm |
|
|
440
|
+
| `deleteUser(realm, username)` | Delete a user |
|
|
441
|
+
| `deleteGroup(realm, groupName)` | Delete a group |
|
|
442
|
+
| `deleteRealm(realm)` | Delete a realm |
|
|
443
|
+
| `teardown()` | Delete the Keycloak namespace |
|
|
444
|
+
| `waitUntilReady(timeout?)` | Wait for Keycloak StatefulSet to be ready |
|
|
445
|
+
|
|
446
|
+
#### Properties
|
|
447
|
+
|
|
448
|
+
| Property | Type | Description |
|
|
449
|
+
|----------|------|-------------|
|
|
450
|
+
| `keycloakUrl` | `string` | The Keycloak instance URL |
|
|
451
|
+
| `realm` | `string` | Configured realm name |
|
|
452
|
+
| `clientId` | `string` | Configured client ID |
|
|
453
|
+
| `clientSecret` | `string` | Configured client secret |
|
|
454
|
+
| `deploymentConfig` | `KeycloakDeploymentConfig` | Current deployment configuration |
|
|
455
|
+
| `k8sClient` | `KubernetesClientHelper` | Kubernetes client instance |
|
|
456
|
+
|
|
457
|
+
#### Default Configuration
|
|
458
|
+
|
|
459
|
+
When using `configureForRHDH()`, the following defaults are applied:
|
|
460
|
+
|
|
461
|
+
**Default Realm**: `rhdh`
|
|
462
|
+
|
|
463
|
+
**Default Client** (`rhdh-client`):
|
|
464
|
+
- Client secret: `rhdh-client-secret`
|
|
465
|
+
- Standard flow, implicit flow, direct access grants enabled
|
|
466
|
+
- Service accounts enabled with realm-management roles
|
|
467
|
+
|
|
468
|
+
**Default Groups**:
|
|
469
|
+
- `developers`
|
|
470
|
+
- `admins`
|
|
471
|
+
- `viewers`
|
|
472
|
+
|
|
473
|
+
**Default Users**:
|
|
474
|
+
| Username | Password | Groups |
|
|
475
|
+
|----------|----------|--------|
|
|
476
|
+
| `test1` | `test1@123` | developers |
|
|
477
|
+
| `test2` | `test2@123` | developers |
|
|
478
|
+
|
|
479
|
+
#### Example: Full RHDH + Keycloak Setup
|
|
480
|
+
|
|
481
|
+
```typescript
|
|
482
|
+
import { test } from "rhdh-e2e-test-utils/test";
|
|
483
|
+
import { KeycloakHelper } from "rhdh-e2e-test-utils/keycloak";
|
|
484
|
+
|
|
485
|
+
let keycloak: KeycloakHelper;
|
|
486
|
+
|
|
487
|
+
test.beforeAll(async ({ rhdh }) => {
|
|
488
|
+
// Deploy Keycloak
|
|
489
|
+
keycloak = new KeycloakHelper({ namespace: "rhdh-keycloak" });
|
|
490
|
+
await keycloak.deploy();
|
|
491
|
+
await keycloak.configureForRHDH();
|
|
492
|
+
|
|
493
|
+
// Set environment variables for RHDH
|
|
494
|
+
process.env.KEYCLOAK_BASE_URL = keycloak.keycloakUrl;
|
|
495
|
+
process.env.KEYCLOAK_REALM = keycloak.realm;
|
|
496
|
+
process.env.KEYCLOAK_CLIENT_ID = keycloak.clientId;
|
|
497
|
+
process.env.KEYCLOAK_CLIENT_SECRET = keycloak.clientSecret;
|
|
498
|
+
process.env.KEYCLOAK_METADATA_URL = `${keycloak.keycloakUrl}/realms/${keycloak.realm}/.well-known/openid-configuration`;
|
|
499
|
+
process.env.KEYCLOAK_LOGIN_REALM = keycloak.realm;
|
|
500
|
+
|
|
501
|
+
// Deploy RHDH with Keycloak authentication
|
|
502
|
+
await rhdh.configure({ auth: "keycloak" });
|
|
503
|
+
await rhdh.deploy();
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
test("login with Keycloak user", async ({ page, loginHelper }) => {
|
|
507
|
+
await page.goto("/");
|
|
508
|
+
await loginHelper.loginAsKeycloakUser("test1", "test1@123");
|
|
509
|
+
// ... test assertions
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
test.afterAll(async () => {
|
|
513
|
+
await keycloak.teardown();
|
|
514
|
+
});
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
#### Connect to Existing Keycloak
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
import { KeycloakHelper } from "rhdh-e2e-test-utils/keycloak";
|
|
521
|
+
|
|
522
|
+
const keycloak = new KeycloakHelper();
|
|
523
|
+
|
|
524
|
+
// Connect with admin credentials
|
|
525
|
+
await keycloak.connect({
|
|
526
|
+
baseUrl: "https://keycloak.example.com",
|
|
527
|
+
username: "admin",
|
|
528
|
+
password: "admin-password",
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// Or connect with client credentials
|
|
532
|
+
await keycloak.connect({
|
|
533
|
+
baseUrl: "https://keycloak.example.com",
|
|
534
|
+
realm: "my-realm",
|
|
535
|
+
clientId: "admin-client",
|
|
536
|
+
clientSecret: "client-secret",
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// Now you can manage users, groups, etc.
|
|
540
|
+
await keycloak.createUser("my-realm", {
|
|
541
|
+
username: "newuser",
|
|
542
|
+
password: "password123",
|
|
543
|
+
groups: ["developers"],
|
|
544
|
+
});
|
|
545
|
+
```
|
|
546
|
+
|
|
320
547
|
### Utilities
|
|
321
548
|
|
|
322
549
|
#### Bash Command Execution
|
|
@@ -387,6 +614,222 @@ const result = envsubst("Port: ${PORT:-8080}");
|
|
|
387
614
|
const result = envsubst("API: ${API_URL}");
|
|
388
615
|
```
|
|
389
616
|
|
|
617
|
+
### Helpers
|
|
618
|
+
|
|
619
|
+
The package provides helper classes for common testing operations.
|
|
620
|
+
|
|
621
|
+
#### UIhelper
|
|
622
|
+
|
|
623
|
+
A utility class for common UI interactions with Material-UI components:
|
|
624
|
+
|
|
625
|
+
```typescript
|
|
626
|
+
import { UIhelper } from "rhdh-e2e-test-utils/helpers";
|
|
627
|
+
|
|
628
|
+
const uiHelper = new UIhelper(page);
|
|
629
|
+
|
|
630
|
+
// Wait for page to fully load
|
|
631
|
+
await uiHelper.waitForLoad();
|
|
632
|
+
|
|
633
|
+
// Verify headings and text
|
|
634
|
+
await uiHelper.verifyHeading("Welcome to RHDH");
|
|
635
|
+
await uiHelper.verifyText("Some content");
|
|
636
|
+
|
|
637
|
+
// Button interactions
|
|
638
|
+
await uiHelper.clickButton("Submit");
|
|
639
|
+
await uiHelper.clickButtonByLabel("Close");
|
|
640
|
+
|
|
641
|
+
// Navigation
|
|
642
|
+
await uiHelper.openSidebar("Catalog");
|
|
643
|
+
await uiHelper.clickTab("Overview");
|
|
644
|
+
|
|
645
|
+
// Table operations
|
|
646
|
+
await uiHelper.verifyRowsInTable(["row1", "row2"]);
|
|
647
|
+
await uiHelper.verifyCellsInTable(["cell1", "cell2"]);
|
|
648
|
+
|
|
649
|
+
// MUI component interactions
|
|
650
|
+
await uiHelper.selectMuiBox("Kind", "Component");
|
|
651
|
+
await uiHelper.fillTextInputByLabel("Name", "my-component");
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
#### LoginHelper
|
|
655
|
+
|
|
656
|
+
Handles authentication flows for different providers:
|
|
657
|
+
|
|
658
|
+
```typescript
|
|
659
|
+
import { LoginHelper } from "rhdh-e2e-test-utils/helpers";
|
|
660
|
+
|
|
661
|
+
const loginHelper = new LoginHelper(page);
|
|
662
|
+
|
|
663
|
+
// Guest authentication
|
|
664
|
+
await loginHelper.loginAsGuest();
|
|
665
|
+
await loginHelper.signOut();
|
|
666
|
+
|
|
667
|
+
// Keycloak authentication
|
|
668
|
+
await loginHelper.loginAsKeycloakUser("username", "password");
|
|
669
|
+
|
|
670
|
+
// GitHub authentication (requires environment variables)
|
|
671
|
+
await loginHelper.loginAsGithubUser();
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
#### APIHelper
|
|
675
|
+
|
|
676
|
+
Provides utilities for API interactions with both GitHub and Backstage catalog:
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
import { APIHelper } from "rhdh-e2e-test-utils/helpers";
|
|
680
|
+
|
|
681
|
+
// GitHub API operations
|
|
682
|
+
await APIHelper.createGitHubRepo("owner", "repo-name");
|
|
683
|
+
await APIHelper.deleteGitHubRepo("owner", "repo-name");
|
|
684
|
+
const prs = await APIHelper.getGitHubPRs("owner", "repo", "open");
|
|
685
|
+
|
|
686
|
+
// Backstage catalog API operations
|
|
687
|
+
const apiHelper = new APIHelper();
|
|
688
|
+
await apiHelper.setBaseUrl(rhdhUrl);
|
|
689
|
+
await apiHelper.setStaticToken(token);
|
|
690
|
+
|
|
691
|
+
const users = await apiHelper.getAllCatalogUsersFromAPI();
|
|
692
|
+
const groups = await apiHelper.getAllCatalogGroupsFromAPI();
|
|
693
|
+
const locations = await apiHelper.getAllCatalogLocationsFromAPI();
|
|
694
|
+
|
|
695
|
+
// Schedule entity refresh
|
|
696
|
+
await apiHelper.scheduleEntityRefreshFromAPI("my-component", "component", token);
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
#### setupBrowser
|
|
700
|
+
|
|
701
|
+
Utility function for setting up a shared browser context with video recording. Use this in `test.beforeAll` for serial test suites or when you want to persist the browser context across multiple tests (e.g., to avoid repeated logins):
|
|
702
|
+
|
|
703
|
+
```typescript
|
|
704
|
+
import { test } from "@playwright/test";
|
|
705
|
+
import { setupBrowser, LoginHelper } from "rhdh-e2e-test-utils/helpers";
|
|
706
|
+
import type { Page, BrowserContext } from "@playwright/test";
|
|
707
|
+
|
|
708
|
+
test.describe.configure({ mode: "serial" });
|
|
709
|
+
|
|
710
|
+
let page: Page;
|
|
711
|
+
let context: BrowserContext;
|
|
712
|
+
|
|
713
|
+
test.beforeAll(async ({ browser }, testInfo) => {
|
|
714
|
+
// Setup shared browser context with video recording
|
|
715
|
+
({ page, context } = await setupBrowser(browser, testInfo));
|
|
716
|
+
|
|
717
|
+
// Login once, session persists across all tests in this suite
|
|
718
|
+
const loginHelper = new LoginHelper(page);
|
|
719
|
+
await page.goto("/");
|
|
720
|
+
await loginHelper.loginAsKeycloakUser();
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
test.afterAll(async () => {
|
|
724
|
+
await context.close();
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
test("first test - already logged in", async () => {
|
|
728
|
+
await page.goto("/catalog");
|
|
729
|
+
// No need to login again
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
test("second test - session persists", async () => {
|
|
733
|
+
await page.goto("/settings");
|
|
734
|
+
// Still logged in from beforeAll
|
|
735
|
+
});
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
### Page Objects
|
|
739
|
+
|
|
740
|
+
Pre-built page object classes for common RHDH pages:
|
|
741
|
+
|
|
742
|
+
```typescript
|
|
743
|
+
import {
|
|
744
|
+
CatalogPage,
|
|
745
|
+
HomePage,
|
|
746
|
+
CatalogImportPage,
|
|
747
|
+
ExtensionsPage,
|
|
748
|
+
NotificationPage,
|
|
749
|
+
} from "rhdh-e2e-test-utils/pages";
|
|
750
|
+
```
|
|
751
|
+
|
|
752
|
+
#### CatalogPage
|
|
753
|
+
|
|
754
|
+
```typescript
|
|
755
|
+
const catalogPage = new CatalogPage(page);
|
|
756
|
+
|
|
757
|
+
// Navigate to catalog
|
|
758
|
+
await catalogPage.go();
|
|
759
|
+
|
|
760
|
+
// Search for entities
|
|
761
|
+
await catalogPage.search("my-component");
|
|
762
|
+
|
|
763
|
+
// Navigate to specific component
|
|
764
|
+
await catalogPage.goToByName("my-component");
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
#### HomePage
|
|
768
|
+
|
|
769
|
+
```typescript
|
|
770
|
+
const homePage = new HomePage(page);
|
|
771
|
+
|
|
772
|
+
// Verify quick search functionality
|
|
773
|
+
await homePage.verifyQuickSearchBar("search-term");
|
|
774
|
+
|
|
775
|
+
// Verify quick access sections
|
|
776
|
+
await homePage.verifyQuickAccess("Favorites", "My Component");
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
#### CatalogImportPage
|
|
780
|
+
|
|
781
|
+
```typescript
|
|
782
|
+
const catalogImportPage = new CatalogImportPage(page);
|
|
783
|
+
|
|
784
|
+
// Register or refresh an existing component
|
|
785
|
+
const wasAlreadyRegistered = await catalogImportPage.registerExistingComponent(
|
|
786
|
+
"https://github.com/org/repo/blob/main/catalog-info.yaml"
|
|
787
|
+
);
|
|
788
|
+
|
|
789
|
+
// Analyze a component URL
|
|
790
|
+
await catalogImportPage.analyzeComponent("https://github.com/org/repo/blob/main/catalog-info.yaml");
|
|
791
|
+
|
|
792
|
+
// Inspect entity and verify YAML content
|
|
793
|
+
await catalogImportPage.inspectEntityAndVerifyYaml("kind: Component");
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
#### ExtensionsPage
|
|
797
|
+
|
|
798
|
+
```typescript
|
|
799
|
+
const extensionsPage = new ExtensionsPage(page);
|
|
800
|
+
|
|
801
|
+
// Filter by support type
|
|
802
|
+
await extensionsPage.selectSupportTypeFilter("Red Hat");
|
|
803
|
+
|
|
804
|
+
// Verify plugin details
|
|
805
|
+
await extensionsPage.verifyPluginDetails({
|
|
806
|
+
pluginName: "Topology",
|
|
807
|
+
badgeLabel: "Red Hat support",
|
|
808
|
+
badgeText: "Red Hat",
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
// Search and verify results
|
|
812
|
+
await extensionsPage.waitForSearchResults("catalog");
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
#### NotificationPage
|
|
816
|
+
|
|
817
|
+
```typescript
|
|
818
|
+
const notificationPage = new NotificationPage(page);
|
|
819
|
+
|
|
820
|
+
// Navigate to notifications
|
|
821
|
+
await notificationPage.clickNotificationsNavBarItem();
|
|
822
|
+
|
|
823
|
+
// Check notification content
|
|
824
|
+
await notificationPage.notificationContains("Build completed");
|
|
825
|
+
|
|
826
|
+
// Manage notifications
|
|
827
|
+
await notificationPage.markAllNotificationsAsRead();
|
|
828
|
+
await notificationPage.selectSeverity("critical");
|
|
829
|
+
await notificationPage.viewSaved();
|
|
830
|
+
await notificationPage.sortByNewestOnTop();
|
|
831
|
+
```
|
|
832
|
+
|
|
390
833
|
### ESLint Configuration
|
|
391
834
|
|
|
392
835
|
Pre-configured ESLint rules for Playwright tests:
|
|
@@ -414,23 +857,40 @@ Extend the base tsconfig:
|
|
|
414
857
|
|
|
415
858
|
### Default Configuration Structure
|
|
416
859
|
|
|
417
|
-
The package includes default configurations
|
|
860
|
+
The package includes default configurations organized in a modular structure:
|
|
418
861
|
|
|
419
862
|
```
|
|
420
|
-
src/deployment/rhdh/
|
|
421
|
-
├──
|
|
422
|
-
│ ├── app-config-rhdh.yaml
|
|
423
|
-
│ ├── dynamic-plugins.yaml
|
|
424
|
-
│ └── rhdh-secrets.yaml
|
|
863
|
+
src/deployment/rhdh/config/
|
|
864
|
+
├── common/ # Base configurations (always applied)
|
|
865
|
+
│ ├── app-config-rhdh.yaml # Base app configuration
|
|
866
|
+
│ ├── dynamic-plugins.yaml # Default dynamic plugins
|
|
867
|
+
│ └── rhdh-secrets.yaml # Base secrets template
|
|
868
|
+
├── auth/ # Auth-specific configurations
|
|
869
|
+
│ ├── guest/
|
|
870
|
+
│ │ └── app-config.yaml # Guest auth configuration
|
|
871
|
+
│ └── keycloak/
|
|
872
|
+
│ ├── app-config.yaml # Keycloak OIDC configuration
|
|
873
|
+
│ ├── dynamic-plugins.yaml # Keycloak-specific plugins
|
|
874
|
+
│ └── secrets.yaml # Keycloak secrets template
|
|
425
875
|
├── helm/
|
|
426
|
-
│ └── value_file.yaml
|
|
876
|
+
│ └── value_file.yaml # Default Helm values
|
|
427
877
|
└── operator/
|
|
428
|
-
└── subscription.yaml
|
|
878
|
+
└── subscription.yaml # Default Backstage CR
|
|
429
879
|
```
|
|
430
880
|
|
|
881
|
+
### Configuration Merging
|
|
882
|
+
|
|
883
|
+
Configurations are merged in the following order (later overrides earlier):
|
|
884
|
+
|
|
885
|
+
1. **Common configs** (`config/common/`) - Base configurations
|
|
886
|
+
2. **Auth configs** (`config/auth/{provider}/`) - Auth-provider-specific configurations
|
|
887
|
+
3. **Project configs** (`tests/config/`) - Your project's custom configurations
|
|
888
|
+
|
|
889
|
+
This allows you to use built-in defaults while only overriding what you need.
|
|
890
|
+
|
|
431
891
|
### Project Configuration
|
|
432
892
|
|
|
433
|
-
Create these files in your project's `config/` directory:
|
|
893
|
+
Create these files in your project's `tests/config/` directory:
|
|
434
894
|
|
|
435
895
|
#### app-config-rhdh.yaml
|
|
436
896
|
|
|
@@ -443,15 +903,12 @@ backend:
|
|
|
443
903
|
allow:
|
|
444
904
|
- host: ${MY_BACKEND_HOST}
|
|
445
905
|
|
|
446
|
-
auth:
|
|
447
|
-
environment: development
|
|
448
|
-
providers:
|
|
449
|
-
guest:
|
|
450
|
-
dangerouslyAllowOutsideDevelopment: true
|
|
451
|
-
|
|
452
906
|
# Plugin-specific config
|
|
453
907
|
techRadar:
|
|
454
908
|
url: "http://${DATA_SOURCE_URL}/tech-radar"
|
|
909
|
+
|
|
910
|
+
# Note: Auth configuration is automatically included based on the 'auth' option
|
|
911
|
+
# You only need to add auth config here if you want to override the defaults
|
|
455
912
|
```
|
|
456
913
|
|
|
457
914
|
#### dynamic-plugins.yaml
|
|
@@ -508,6 +965,22 @@ stringData:
|
|
|
508
965
|
|----------|-------------|
|
|
509
966
|
| `CI` | If set, namespaces are auto-deleted after tests |
|
|
510
967
|
| `CHART_URL` | Custom Helm chart URL (default: `oci://quay.io/rhdh/chart`) |
|
|
968
|
+
| `SKIP_KEYCLOAK_DEPLOYMENT` | Set to `true` to skip automatic Keycloak deployment in global setup |
|
|
969
|
+
|
|
970
|
+
### Keycloak Environment Variables (for `auth: "keycloak"`)
|
|
971
|
+
|
|
972
|
+
When using Keycloak authentication, these environment variables are required:
|
|
973
|
+
|
|
974
|
+
| Variable | Description |
|
|
975
|
+
|----------|-------------|
|
|
976
|
+
| `KEYCLOAK_BASE_URL` | Keycloak instance URL |
|
|
977
|
+
| `KEYCLOAK_METADATA_URL` | OIDC metadata URL (e.g., `{KEYCLOAK_BASE_URL}/realms/{realm}/.well-known/openid-configuration`) |
|
|
978
|
+
| `KEYCLOAK_CLIENT_ID` | OIDC client ID |
|
|
979
|
+
| `KEYCLOAK_CLIENT_SECRET` | OIDC client secret |
|
|
980
|
+
| `KEYCLOAK_REALM` | Keycloak realm name |
|
|
981
|
+
| `KEYCLOAK_LOGIN_REALM` | Login realm (usually same as `KEYCLOAK_REALM`) |
|
|
982
|
+
|
|
983
|
+
These are automatically set when using `KeycloakHelper.configureForRHDH()`. See [Keycloak Deployment](#keycloak-deployment) for details.
|
|
511
984
|
|
|
512
985
|
|
|
513
986
|
## Examples
|
|
@@ -515,21 +988,70 @@ stringData:
|
|
|
515
988
|
### Custom Deployment Configuration
|
|
516
989
|
|
|
517
990
|
```typescript
|
|
518
|
-
import {
|
|
991
|
+
import { test } from "rhdh-e2e-test-utils/test";
|
|
519
992
|
|
|
520
993
|
test.beforeAll(async ({ rhdh }) => {
|
|
521
|
-
rhdh.configure({
|
|
522
|
-
namespace: "custom-test-ns",
|
|
994
|
+
await rhdh.configure({
|
|
523
995
|
version: "1.5",
|
|
524
996
|
method: "helm",
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
997
|
+
auth: "keycloak", // or "guest" for development
|
|
998
|
+
appConfig: "tests/config/app-config.yaml",
|
|
999
|
+
secrets: "tests/config/secrets.yaml",
|
|
1000
|
+
dynamicPlugins: "tests/config/plugins.yaml",
|
|
1001
|
+
valueFile: "tests/config/values.yaml",
|
|
529
1002
|
});
|
|
530
1003
|
|
|
531
1004
|
await rhdh.deploy();
|
|
1005
|
+
});
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
### Guest Authentication (Development)
|
|
1009
|
+
|
|
1010
|
+
```typescript
|
|
1011
|
+
import { test } from "rhdh-e2e-test-utils/test";
|
|
1012
|
+
|
|
1013
|
+
test.beforeAll(async ({ rhdh }) => {
|
|
1014
|
+
await rhdh.configure({ auth: "guest" });
|
|
1015
|
+
await rhdh.deploy();
|
|
1016
|
+
});
|
|
532
1017
|
|
|
1018
|
+
test("test with guest login", async ({ page, loginHelper }) => {
|
|
1019
|
+
await page.goto("/");
|
|
1020
|
+
await loginHelper.loginAsGuest();
|
|
1021
|
+
// ... test assertions
|
|
1022
|
+
});
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
### Using Helpers and Page Objects
|
|
1026
|
+
|
|
1027
|
+
```typescript
|
|
1028
|
+
import { test, expect } from "rhdh-e2e-test-utils/test";
|
|
1029
|
+
import { CatalogPage } from "rhdh-e2e-test-utils/pages";
|
|
1030
|
+
import { APIHelper } from "rhdh-e2e-test-utils/helpers";
|
|
1031
|
+
|
|
1032
|
+
test.beforeAll(async ({ rhdh }) => {
|
|
1033
|
+
await rhdh.deploy();
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
test("catalog interaction", async ({ page, uiHelper, loginHelper }) => {
|
|
1037
|
+
// Login
|
|
1038
|
+
await loginHelper.loginAsKeycloakUser();
|
|
1039
|
+
|
|
1040
|
+
// Use page object for catalog operations
|
|
1041
|
+
const catalogPage = new CatalogPage(page);
|
|
1042
|
+
await catalogPage.go();
|
|
1043
|
+
await catalogPage.search("my-component");
|
|
1044
|
+
|
|
1045
|
+
// Use UI helper for assertions
|
|
1046
|
+
await uiHelper.verifyRowsInTable(["my-component"]);
|
|
1047
|
+
});
|
|
1048
|
+
|
|
1049
|
+
test("API operations", async ({ rhdh }) => {
|
|
1050
|
+
// Create GitHub repo via API
|
|
1051
|
+
await APIHelper.createGitHubRepo("my-org", "test-repo");
|
|
1052
|
+
|
|
1053
|
+
// Clean up
|
|
1054
|
+
await APIHelper.deleteGitHubRepo("my-org", "test-repo");
|
|
533
1055
|
});
|
|
534
1056
|
```
|
|
535
1057
|
|
|
@@ -562,6 +1084,80 @@ yarn build
|
|
|
562
1084
|
| `yarn prettier:check` | Check code formatting |
|
|
563
1085
|
| `yarn prettier:fix` | Auto-fix code formatting |
|
|
564
1086
|
|
|
1087
|
+
### Testing Local Changes in Consumer Projects
|
|
1088
|
+
|
|
1089
|
+
When developing features or fixes in `rhdh-e2e-test-utils`, you can test your local changes in a consumer project (e.g., a plugin's e2e-tests) before publishing.
|
|
1090
|
+
|
|
1091
|
+
#### 1. Build your local changes
|
|
1092
|
+
|
|
1093
|
+
```bash
|
|
1094
|
+
cd /path/to/rhdh-e2e-test-utils
|
|
1095
|
+
yarn build
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
#### 2. Update the consumer project's package.json
|
|
1099
|
+
|
|
1100
|
+
In your e2e-tests project, update the dependency to point to your local package using the `file:` protocol:
|
|
1101
|
+
|
|
1102
|
+
```json
|
|
1103
|
+
"rhdh-e2e-test-utils": "file:/path/to/rhdh-e2e-test-utils"
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
Example:
|
|
1107
|
+
```json
|
|
1108
|
+
"rhdh-e2e-test-utils": "file:/Users/yourname/Documents/rhdh/rhdh-e2e-test-utils"
|
|
1109
|
+
```
|
|
1110
|
+
|
|
1111
|
+
#### 3. Install dependencies in the consumer project
|
|
1112
|
+
|
|
1113
|
+
```bash
|
|
1114
|
+
yarn install
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
#### 4. Run tests with NODE_PRESERVE_SYMLINKS
|
|
1118
|
+
|
|
1119
|
+
When running tests with a local symlinked package, you **must** set the `NODE_PRESERVE_SYMLINKS` environment variable:
|
|
1120
|
+
|
|
1121
|
+
```bash
|
|
1122
|
+
NODE_PRESERVE_SYMLINKS=1 yarn test
|
|
1123
|
+
NODE_PRESERVE_SYMLINKS=1 yarn test:headed
|
|
1124
|
+
NODE_PRESERVE_SYMLINKS=1 yarn test:ui
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
> **Why is NODE_PRESERVE_SYMLINKS needed?**
|
|
1128
|
+
>
|
|
1129
|
+
> When using local packages via `file:` protocol, the package manager creates a symlink. Node.js follows symlinks by default and tries to resolve peer dependencies (like `@playwright/test`) from the original package location. This causes duplicate Playwright instances which fails with:
|
|
1130
|
+
> ```
|
|
1131
|
+
> Error: Requiring @playwright/test second time
|
|
1132
|
+
> ```
|
|
1133
|
+
> Setting `NODE_PRESERVE_SYMLINKS=1` tells Node.js to resolve dependencies from the symlink location (your project's `node_modules`) instead of the original package location.
|
|
1134
|
+
|
|
1135
|
+
#### 5. Rebuild after making changes
|
|
1136
|
+
|
|
1137
|
+
When you make further changes to `rhdh-e2e-test-utils`, rebuild before running tests:
|
|
1138
|
+
|
|
1139
|
+
```bash
|
|
1140
|
+
cd /path/to/rhdh-e2e-test-utils
|
|
1141
|
+
yarn build
|
|
1142
|
+
```
|
|
1143
|
+
|
|
1144
|
+
Then run your tests again in the consumer project (no need to reinstall).
|
|
1145
|
+
|
|
1146
|
+
#### 6. Restore the published version
|
|
1147
|
+
|
|
1148
|
+
After testing, restore the published version in the consumer project's `package.json`:
|
|
1149
|
+
|
|
1150
|
+
```json
|
|
1151
|
+
"rhdh-e2e-test-utils": "^1.0.0"
|
|
1152
|
+
```
|
|
1153
|
+
|
|
1154
|
+
Then run:
|
|
1155
|
+
```bash
|
|
1156
|
+
yarn install
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
You can now run tests normally without `NODE_PRESERVE_SYMLINKS`.
|
|
1160
|
+
|
|
565
1161
|
### CI/CD
|
|
566
1162
|
|
|
567
1163
|
The project includes GitHub Actions workflows:
|