@red-hat-developer-hub/e2e-test-utils 1.1.23 → 1.1.24

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.
@@ -10,9 +10,25 @@ export declare class RHDHDeployment {
10
10
  }): Promise<void>;
11
11
  private _applyAppConfig;
12
12
  private _applySecrets;
13
+ /** Shared merge strategy for dynamic plugin arrays. */
14
+ private static readonly pluginMergeOpts;
15
+ /**
16
+ * Merges package defaults + auth config (+ optional user config) into a
17
+ * single dynamic plugins configuration.
18
+ */
19
+ private _mergeBaseConfigs;
20
+ /**
21
+ * Merges a generated plugin config with the base (defaults + auth) config.
22
+ */
23
+ private _mergeGeneratedWithBase;
13
24
  /**
14
25
  * Builds the merged dynamic plugins configuration.
15
- * Merges: package defaults + auth config + user config + metadata (for PR builds).
26
+ *
27
+ * 1. Assembles raw config: user-provided OR auto-generated from metadata
28
+ * 2. Processes for deployment: injects metadata (PR) + resolves all packages to OCI
29
+ *
30
+ * The processing step is shared — processPluginsForDeployment handles
31
+ * both PR and nightly via isNightlyJob() and GIT_PR_NUMBER detection.
16
32
  */
17
33
  private _buildDynamicPluginsConfig;
18
34
  private _applyDynamicPlugins;
@@ -27,6 +43,7 @@ export declare class RHDHDeployment {
27
43
  scaleDownAndRestart(): Promise<void>;
28
44
  waitUntilReady(timeout?: number): Promise<void>;
29
45
  teardown(): Promise<void>;
46
+ private _deploymentExists;
30
47
  private _resolveChartVersion;
31
48
  /**
32
49
  * Resolve the semantic version from the "next" tag by looking up the
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../../src/deployment/rhdh/deployment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAoB1E,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAGjB,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc;IAClB,SAAS,yBAAgC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,gBAAgB,CAAC;gBAE9B,SAAS,EAAE,MAAM;IAKvB,MAAM,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAuCpD,eAAe;YAmBf,aAAa;IAqB3B;;;OAGG;YACW,0BAA0B;YA6D1B,oBAAoB;YAWpB,eAAe;YAmCf,mBAAmB;IAiD3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAWrC;;;;OAIG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC,cAAc,CAAC,OAAO,GAAE,MAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBpD,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAIjB,oBAAoB;IAsClC;;;OAGG;YACW,0BAA0B;IAwCxC,OAAO,CAAC,sBAAsB;IAqCxB,SAAS,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrE,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,SAAS;CAMlB"}
1
+ {"version":3,"file":"deployment.d.ts","sourceRoot":"","sources":["../../../src/deployment/rhdh/deployment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAwB1E,OAAO,KAAK,EACV,iBAAiB,EACjB,gBAAgB,EAGjB,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc;IAClB,SAAS,yBAAgC;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,gBAAgB,CAAC;gBAE9B,SAAS,EAAE,MAAM;IAKvB,MAAM,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YA0CpD,eAAe;YAmBf,aAAa;IAqB3B,uDAAuD;IACvD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAE5B;IAEX;;;OAGG;YACW,iBAAiB;IAY/B;;OAEG;YACW,uBAAuB;IAgBrC;;;;;;;;OAQG;YACW,0BAA0B;YAsC1B,oBAAoB;YAWpB,eAAe;YA6Df,mBAAmB;IAoE3B,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAWrC;;;;OAIG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC,cAAc,CAAC,OAAO,GAAE,MAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IA6BpD,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAIjB,iBAAiB;YASjB,oBAAoB;IAsClC;;;OAGG;YACW,0BAA0B;IAwCxC,OAAO,CAAC,sBAAsB;IAoCxB,SAAS,CAAC,iBAAiB,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrE,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,IAAI;IAIZ,OAAO,CAAC,SAAS;CAMlB"}
@@ -1,9 +1,12 @@
1
1
  import { KubernetesClientHelper } from "../../utils/kubernetes-client.js";
2
+ import { WorkspacePaths } from "../../utils/workspace-paths.js";
2
3
  import { $ } from "../../utils/bash.js";
3
4
  import yaml from "js-yaml";
4
- import { test } from "@playwright/test";
5
+ import os from "os";
6
+ import path from "path";
7
+ import { test, request, expect } from "@playwright/test";
5
8
  import { mergeYamlFilesIfExists, deepMerge } from "../../utils/merge-yamls.js";
6
- import { loadAndInjectPluginMetadata, generateDynamicPluginsConfigFromMetadata, getNormalizedPluginMergeKey, disablePluginWrappers, } from "../../utils/plugin-metadata.js";
9
+ import { generatePluginsFromMetadata, processPluginsForDeployment, getNormalizedPluginMergeKey, disablePluginWrappers, } from "../../utils/plugin-metadata.js";
7
10
  import { envsubst } from "../../utils/common.js";
8
11
  import { runOnce } from "../../playwright/run-once.js";
9
12
  import cloneDeepWith from "lodash.clonedeepwith";
@@ -31,8 +34,11 @@ export class RHDHDeployment {
31
34
  await this._applyAppConfig();
32
35
  await this._applySecrets();
33
36
  if (this.deploymentConfig.method === "helm") {
37
+ const isUpgrade = await this._deploymentExists();
34
38
  await this._deployWithHelm(this.deploymentConfig.valueFile);
35
- await this.scaleDownAndRestart(); // Restart as helm does not monitor config changes
39
+ if (isUpgrade) {
40
+ await this.scaleDownAndRestart(); // Restart as helm does not monitor config changes
41
+ }
36
42
  }
37
43
  else {
38
44
  await this._applyDynamicPlugins();
@@ -69,51 +75,70 @@ export class RHDHDeployment {
69
75
  });
70
76
  await this.k8sClient.applySecretFromObject("rhdh-secrets", substituted, this.deploymentConfig.namespace);
71
77
  }
78
+ /** Shared merge strategy for dynamic plugin arrays. */
79
+ static pluginMergeOpts = {
80
+ arrayMergeStrategy: { byKey: "package" },
81
+ };
82
+ /**
83
+ * Merges package defaults + auth config (+ optional user config) into a
84
+ * single dynamic plugins configuration.
85
+ */
86
+ async _mergeBaseConfigs(userConfigPath) {
87
+ const authConfig = AUTH_CONFIG_PATHS[this.deploymentConfig.auth];
88
+ const paths = [
89
+ DEFAULT_CONFIG_PATHS.dynamicPlugins,
90
+ authConfig.dynamicPlugins,
91
+ ...(userConfigPath ? [userConfigPath] : []),
92
+ ];
93
+ return await mergeYamlFilesIfExists(paths, RHDHDeployment.pluginMergeOpts);
94
+ }
95
+ /**
96
+ * Merges a generated plugin config with the base (defaults + auth) config.
97
+ */
98
+ async _mergeGeneratedWithBase(generatedConfig) {
99
+ const baseConfig = await this._mergeBaseConfigs();
100
+ // Use normalizeKey so OCI and local path for the same logical plugin
101
+ // (e.g., keycloak from metadata OCI + auth local path with -dynamic suffix)
102
+ // are deduplicated; generated (metadata) wins so OCI URL is kept.
103
+ return deepMerge(baseConfig, generatedConfig, {
104
+ arrayMergeStrategy: {
105
+ byKey: "package",
106
+ normalizeKey: (item) => getNormalizedPluginMergeKey(item),
107
+ },
108
+ });
109
+ }
72
110
  /**
73
111
  * Builds the merged dynamic plugins configuration.
74
- * Merges: package defaults + auth config + user config + metadata (for PR builds).
112
+ *
113
+ * 1. Assembles raw config: user-provided OR auto-generated from metadata
114
+ * 2. Processes for deployment: injects metadata (PR) + resolves all packages to OCI
115
+ *
116
+ * The processing step is shared — processPluginsForDeployment handles
117
+ * both PR and nightly via isNightlyJob() and GIT_PR_NUMBER detection.
75
118
  */
76
119
  async _buildDynamicPluginsConfig() {
77
120
  const userConfigPath = this.deploymentConfig.dynamicPlugins;
78
121
  const userConfigExists = userConfigPath && fs.existsSync(userConfigPath);
79
- const authConfig = AUTH_CONFIG_PATHS[this.deploymentConfig.auth];
80
122
  const wrapperPlugins = disablePluginWrappers(this.deploymentConfig.disableWrappers);
81
- // If user's dynamic-plugins config doesn't exist, auto-generate from metadata
82
- if (!userConfigExists) {
83
- this._log(`Dynamic plugins config not found at '${userConfigPath}', auto-generating from metadata...`);
84
- const metadataConfig = await generateDynamicPluginsConfigFromMetadata();
85
- // Merge with package defaults and auth config. Use normalized plugin key so
86
- // the same logical plugin (e.g. keycloak from metadata OCI + auth local path)
87
- // is deduplicated; metadata (source) wins so OCI URL is kept on PR builds.
88
- const authPlugins = await mergeYamlFilesIfExists([DEFAULT_CONFIG_PATHS.dynamicPlugins, authConfig.dynamicPlugins], { arrayMergeStrategy: { byKey: "package" } });
89
- const dynamicPlugins = deepMerge(authPlugins, metadataConfig, {
90
- arrayMergeStrategy: {
91
- byKey: "package",
92
- normalizeKey: (item) => getNormalizedPluginMergeKey(item),
93
- },
94
- });
95
- if (!process.env.GIT_PR_NUMBER) {
96
- return dynamicPlugins;
97
- }
98
- return deepMerge(dynamicPlugins, wrapperPlugins, {
99
- arrayMergeStrategy: "concat",
100
- });
123
+ let config;
124
+ if (userConfigExists) {
125
+ this._log(`Using user config: ${userConfigPath}`);
126
+ config = await this._mergeBaseConfigs(userConfigPath);
101
127
  }
102
- // User config exists - merge provided configs and inject metadata for listed plugins only
103
- let dynamicPluginsConfig = await mergeYamlFilesIfExists([
104
- DEFAULT_CONFIG_PATHS.dynamicPlugins,
105
- authConfig.dynamicPlugins,
106
- userConfigPath,
107
- ], { arrayMergeStrategy: { byKey: "package" } });
108
- // Inject plugin metadata configuration for plugins in the config
109
- dynamicPluginsConfig =
110
- await loadAndInjectPluginMetadata(dynamicPluginsConfig);
128
+ else {
129
+ this._log(`No user config at '${userConfigPath}', auto-generating from metadata...`);
130
+ const generated = await generatePluginsFromMetadata(WorkspacePaths.metadataDir);
131
+ config = await this._mergeGeneratedWithBase(generated);
132
+ }
133
+ // Process for deployment: inject metadata (PR only) + resolve all packages to OCI
134
+ let result = await processPluginsForDeployment(config, WorkspacePaths.metadataDir);
135
+ // Disable wrapper plugins (PR builds only)
111
136
  if (process.env.GIT_PR_NUMBER) {
112
- dynamicPluginsConfig = deepMerge(dynamicPluginsConfig, wrapperPlugins, {
137
+ result = deepMerge(result, wrapperPlugins, {
113
138
  arrayMergeStrategy: "concat",
114
139
  });
115
140
  }
116
- return dynamicPluginsConfig;
141
+ return result;
117
142
  }
118
143
  async _applyDynamicPlugins() {
119
144
  const dynamicPluginsYaml = await this._buildDynamicPluginsConfig();
@@ -133,23 +158,64 @@ export class RHDHDeployment {
133
158
  valueFileObject.global = {};
134
159
  }
135
160
  valueFileObject.global.dynamic = await this._buildDynamicPluginsConfig();
161
+ // Set catalog index image if CATALOG_INDEX_IMAGE env var is provided.
162
+ // The catalog index provides dynamic-plugins.default.yaml with default plugin
163
+ // configurations and versions for the RHDH release.
164
+ const catalogIndexImage = process.env.CATALOG_INDEX_IMAGE;
165
+ if (catalogIndexImage) {
166
+ const [imageRef, tag] = catalogIndexImage.split(":");
167
+ const firstSlash = imageRef.indexOf("/");
168
+ valueFileObject.global.catalogIndex = {
169
+ image: {
170
+ registry: imageRef.substring(0, firstSlash),
171
+ repository: imageRef.substring(firstSlash + 1),
172
+ tag: tag || "latest",
173
+ },
174
+ };
175
+ this._log(`Catalog index image: ${catalogIndexImage}`);
176
+ }
136
177
  this._logBoxen("Dynamic Plugins", valueFileObject.global.dynamic);
137
- fs.writeFileSync(`/tmp/${this.deploymentConfig.namespace}-value-file.yaml`, yaml.dump(valueFileObject));
178
+ // Escape {{inherit}} for Helm's Go template engine.
179
+ // The RHDH chart uses `tpl` on dynamic plugin values, so {{inherit}} would be
180
+ // interpreted as a Go template action. Escaping to {{ "{{inherit}}" }} produces
181
+ // the literal string {{inherit}} after template rendering.
182
+ const valuesYaml = yaml
183
+ .dump(valueFileObject)
184
+ .replace(/\{\{inherit\}\}/g, '{{ "{{inherit}}" }}');
185
+ const valueFilePath = path.join(os.tmpdir(), `${this.deploymentConfig.namespace}-value-file.yaml`);
186
+ fs.writeFileSync(valueFilePath, valuesYaml);
138
187
  await $ `
139
188
  helm upgrade redhat-developer-hub -i "${process.env.CHART_URL || CHART_URL}" --version "${chartVersion}" \
140
- -f "/tmp/${this.deploymentConfig.namespace}-value-file.yaml" \
189
+ -f "${valueFilePath}" \
141
190
  --set global.clusterRouterBase="${process.env.K8S_CLUSTER_ROUTER_BASE}" \
142
191
  --namespace="${this.deploymentConfig.namespace}"
143
192
  `;
144
193
  this._log(`Helm deployment completed successfully`);
145
194
  }
146
195
  async _deployWithOperator(subscription) {
147
- const subscriptionObject = await mergeYamlFilesIfExists([
196
+ const subscriptionObject = (await mergeYamlFilesIfExists([
148
197
  DEFAULT_CONFIG_PATHS.operator.subscription,
149
198
  subscription,
150
- ]);
199
+ ]));
200
+ // Set catalog index image if CATALOG_INDEX_IMAGE env var is provided.
201
+ const catalogIndexImage = process.env.CATALOG_INDEX_IMAGE;
202
+ if (catalogIndexImage) {
203
+ const spec = (subscriptionObject.spec ??= {});
204
+ const app = (spec.application ??= {});
205
+ const extraEnvs = (app.extraEnvs ??=
206
+ {});
207
+ const envs = (extraEnvs.envs ??=
208
+ []);
209
+ envs.push({
210
+ name: "CATALOG_INDEX_IMAGE",
211
+ value: catalogIndexImage,
212
+ containers: ["install-dynamic-plugins"],
213
+ });
214
+ this._log(`Catalog index image: ${catalogIndexImage}`);
215
+ }
151
216
  this._logBoxen("Subscription", subscriptionObject);
152
- fs.writeFileSync(`/tmp/${this.deploymentConfig.namespace}-subscription.yaml`, yaml.dump(subscriptionObject));
217
+ const subscriptionFilePath = path.join(os.tmpdir(), `${this.deploymentConfig.namespace}-subscription.yaml`);
218
+ fs.writeFileSync(subscriptionFilePath, yaml.dump(subscriptionObject));
153
219
  const version = this.deploymentConfig.version;
154
220
  const isSemanticVersion = /^\d+(\.\d+)?$/.test(version);
155
221
  // Use main branch for non-semantic versions (e.g., "next", "latest")
@@ -178,7 +244,7 @@ export class RHDHDeployment {
178
244
  echo "Backstage CRD is created."
179
245
  ' || echo "Error: Timed out waiting for Backstage CRD creation."
180
246
 
181
- oc apply -f "/tmp/${this.deploymentConfig.namespace}-subscription.yaml" -n "${this.deploymentConfig.namespace}"
247
+ oc apply -f "${subscriptionFilePath}" -n "${this.deploymentConfig.namespace}"
182
248
  `;
183
249
  this._log("Operator deployment executed successfully.");
184
250
  }
@@ -200,19 +266,37 @@ export class RHDHDeployment {
200
266
  await $ `oc scale deployment -l 'app.kubernetes.io/instance in (redhat-developer-hub,developer-hub)' --replicas=1 -n ${namespace}`;
201
267
  }
202
268
  async waitUntilReady(timeout = 500) {
203
- this._log(`Waiting for RHDH deployment to be ready in namespace ${this.deploymentConfig.namespace}...`);
269
+ const namespace = this.deploymentConfig.namespace;
204
270
  const labelSelector = "app.kubernetes.io/instance in (redhat-developer-hub,developer-hub)";
271
+ const startTime = Date.now();
205
272
  try {
206
- await this.k8sClient.waitForPodsWithFailureDetection(this.deploymentConfig.namespace, labelSelector, timeout);
207
- this._log(`RHDH deployment is ready in namespace ${this.deploymentConfig.namespace}`);
273
+ await this.k8sClient.waitForPodsWithFailureDetection(namespace, labelSelector, timeout);
208
274
  }
209
275
  catch (error) {
210
- throw new Error(`RHDH deployment failed in namespace ${this.deploymentConfig.namespace}: ${error instanceof Error ? error.message : error}`);
276
+ throw new Error(`RHDH deployment failed in ${namespace}: ${error instanceof Error ? error.message : error}`);
211
277
  }
278
+ // Use remaining timeout for route readiness check
279
+ const remaining = timeout * 1000 - (Date.now() - startTime);
280
+ await expect(async () => {
281
+ const context = await request.newContext({ ignoreHTTPSErrors: true });
282
+ const response = await context.get(this.rhdhUrl);
283
+ await context.dispose();
284
+ expect(response.ok()).toBeTruthy();
285
+ }).toPass({ timeout: Math.max(remaining, 30_000), intervals: [5_000] });
286
+ this._log(`RHDH is ready in ${namespace}`);
212
287
  }
213
288
  async teardown() {
214
289
  await this.k8sClient.deleteNamespace(this.deploymentConfig.namespace);
215
290
  }
291
+ async _deploymentExists() {
292
+ try {
293
+ await $ `oc get deployment redhat-developer-hub -n ${this.deploymentConfig.namespace} --no-headers 2>/dev/null`;
294
+ return true;
295
+ }
296
+ catch {
297
+ return false;
298
+ }
299
+ }
216
300
  async _resolveChartVersion(version) {
217
301
  let resolvedVersion = version;
218
302
  // Handle "next" tag by looking up the corresponding version from downstream image
@@ -278,23 +362,23 @@ export class RHDHDeployment {
278
362
  version,
279
363
  namespace: input.namespace ?? this.deploymentConfig.namespace,
280
364
  auth: input.auth ?? "keycloak",
281
- appConfig: input.appConfig ?? `tests/config/app-config-rhdh.yaml`,
282
- secrets: input.secrets ?? `tests/config/rhdh-secrets.yaml`,
283
- dynamicPlugins: input.dynamicPlugins ?? `tests/config/dynamic-plugins.yaml`,
365
+ appConfig: input.appConfig ?? WorkspacePaths.appConfig,
366
+ secrets: input.secrets ?? WorkspacePaths.secrets,
367
+ dynamicPlugins: input.dynamicPlugins ?? WorkspacePaths.dynamicPlugins,
284
368
  disableWrappers: input.disableWrappers ?? [],
285
369
  };
286
370
  if (method === "helm") {
287
371
  return {
288
372
  ...base,
289
373
  method,
290
- valueFile: input.valueFile ?? `tests/config/value_file.yaml`,
374
+ valueFile: input.valueFile ?? WorkspacePaths.valueFile,
291
375
  };
292
376
  }
293
377
  else if (method === "operator") {
294
378
  return {
295
379
  ...base,
296
380
  method,
297
- subscription: input.subscription ?? `tests/config/subscription.yaml`,
381
+ subscription: input.subscription ?? WorkspacePaths.subscription,
298
382
  };
299
383
  }
300
384
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../../src/playwright/fixtures/test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,KAAK,0BAA0B,GAAG;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AAEF,KAAK,4BAA4B,GAAG;IAClC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AA2CF,eAAO,MAAM,IAAI;;CAEf,CAAC;AAEH,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../../src/playwright/fixtures/test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAIzC,KAAK,0BAA0B,GAAG;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,WAAW,CAAC;CAC1B,CAAC;AAEF,KAAK,4BAA4B,GAAG;IAClC,oBAAoB,EAAE,cAAc,CAAC;CACtC,CAAC;AAkDF,eAAO,MAAM,IAAI;;CAEf,CAAC;AAEH,cAAc,kBAAkB,CAAC"}
@@ -2,10 +2,18 @@ import { RHDHDeployment } from "../../deployment/rhdh/index.js";
2
2
  import { test as base } from "@playwright/test";
3
3
  import { LoginHelper, UIhelper } from "../helpers/index.js";
4
4
  import { runOnce } from "../run-once.js";
5
+ import { $ } from "../../utils/bash.js";
6
+ import path from "path";
5
7
  const baseTest = base.extend({
6
8
  rhdhDeploymentWorker: [
7
9
  // eslint-disable-next-line no-empty-pattern
8
10
  async ({}, use, workerInfo) => {
11
+ // Set CWD to the workspace's e2e-tests directory so that relative
12
+ // config paths resolve correctly even when Playwright runs from the repo root.
13
+ // Each worker is a separate process, so this doesn't affect other workers.
14
+ const e2eRoot = path.resolve(workerInfo.project.testDir, "..");
15
+ process.chdir(e2eRoot);
16
+ $.cwd = e2eRoot;
9
17
  const rhdhDeployment = new RHDHDeployment(workerInfo.project.name);
10
18
  await rhdhDeployment.configure();
11
19
  await use(rhdhDeployment);
@@ -1 +1 @@
1
- {"version":3,"file":"ui-helper.d.ts","sourceRoot":"","sources":["../../../src/playwright/helpers/ui-helper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ui-helper.d.ts","sourceRoot":"","sources":["../../../src/playwright/helpers/ui-helper.ts"],"names":[],"mappings":"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"}
@@ -134,6 +134,7 @@ export class UIhelper {
134
134
  async goToPageUrl(url, heading) {
135
135
  await this.page.goto(url);
136
136
  await expect(this.page).toHaveURL(url);
137
+ await this.waitForLoad();
137
138
  if (heading) {
138
139
  await this.verifyHeading(heading);
139
140
  }
@@ -1,15 +1,27 @@
1
- import type { Reporter, Suite } from "@playwright/test/reporter";
1
+ import type { Reporter, Suite, TestCase, TestResult } from "@playwright/test/reporter";
2
2
  /**
3
- * Playwright reporter that deletes namespaces after all tests complete.
4
- * Runs in the main process, so it survives worker restarts.
5
- * Only active when process.env.CI is set.
3
+ * Playwright reporter that deletes namespaces per-project as soon as all tests
4
+ * in that project finish. This frees cluster resources early instead of waiting
5
+ * for the entire suite to complete.
6
+ *
7
+ * Handles retries: a test is only counted as done when it passes/is skipped,
8
+ * or exhausts all retry attempts.
9
+ *
10
+ * Falls back in onEnd() to clean up any projects that didn't complete naturally
11
+ * (e.g., interrupted runs, maxFailures).
12
+ *
13
+ * Only active when process.env.CI === "true".
6
14
  *
7
15
  * By default, deletes the namespace matching the project name.
8
16
  * For custom namespaces, consumers can register them via registerTeardownNamespace().
9
17
  */
10
18
  export default class TeardownReporter implements Reporter {
11
- private _projects;
19
+ private _projectTestCounts;
20
+ private _projectCompleted;
21
+ private _pendingDeletions;
12
22
  onBegin(_config: unknown, suite: Suite): void;
23
+ onTestEnd(test: TestCase, result: TestResult): void;
13
24
  onEnd(): Promise<void>;
25
+ private _deleteProjectNamespaces;
14
26
  }
15
27
  //# sourceMappingURL=teardown-reporter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"teardown-reporter.d.ts","sourceRoot":"","sources":["../../src/playwright/teardown-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAIjE;;;;;;;GAOG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,YAAW,QAAQ;IACvD,OAAO,CAAC,SAAS,CAAqB;IAEtC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAOvC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CA2B7B"}
1
+ {"version":3,"file":"teardown-reporter.d.ts","sourceRoot":"","sources":["../../src/playwright/teardown-reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,UAAU,EACX,MAAM,2BAA2B,CAAC;AAInC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,OAAO,OAAO,gBAAiB,YAAW,QAAQ;IACvD,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,iBAAiB,CAAoC;IAE7D,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAa7C,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI;IA0B7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAed,wBAAwB;CAuBvC"}
@@ -1,25 +1,68 @@
1
1
  import { KubernetesClientHelper } from "../utils/kubernetes-client.js";
2
2
  import { getTeardownNamespaces } from "./teardown-namespaces.js";
3
3
  /**
4
- * Playwright reporter that deletes namespaces after all tests complete.
5
- * Runs in the main process, so it survives worker restarts.
6
- * Only active when process.env.CI is set.
4
+ * Playwright reporter that deletes namespaces per-project as soon as all tests
5
+ * in that project finish. This frees cluster resources early instead of waiting
6
+ * for the entire suite to complete.
7
+ *
8
+ * Handles retries: a test is only counted as done when it passes/is skipped,
9
+ * or exhausts all retry attempts.
10
+ *
11
+ * Falls back in onEnd() to clean up any projects that didn't complete naturally
12
+ * (e.g., interrupted runs, maxFailures).
13
+ *
14
+ * Only active when process.env.CI === "true".
7
15
  *
8
16
  * By default, deletes the namespace matching the project name.
9
17
  * For custom namespaces, consumers can register them via registerTeardownNamespace().
10
18
  */
11
19
  export default class TeardownReporter {
12
- _projects = new Set();
20
+ _projectTestCounts = new Map();
21
+ _projectCompleted = new Map();
22
+ _pendingDeletions = new Map();
13
23
  onBegin(_config, suite) {
14
24
  for (const test of suite.allTests()) {
15
25
  const name = test.parent.project()?.name;
16
- if (name)
17
- this._projects.add(name);
26
+ if (name) {
27
+ this._projectTestCounts.set(name, (this._projectTestCounts.get(name) ?? 0) + 1);
28
+ this._projectCompleted.set(name, 0);
29
+ }
30
+ }
31
+ }
32
+ onTestEnd(test, result) {
33
+ if (process.env.CI !== "true")
34
+ return;
35
+ const project = test.parent.project();
36
+ if (!project)
37
+ return;
38
+ const isDone = result.status === "passed" ||
39
+ result.status === "skipped" ||
40
+ result.retry >= project.retries;
41
+ if (!isDone)
42
+ return;
43
+ const name = project.name;
44
+ const completed = (this._projectCompleted.get(name) ?? 0) + 1;
45
+ this._projectCompleted.set(name, completed);
46
+ // Start deletion immediately (fire-and-forget here, awaited in onEnd)
47
+ if (completed === this._projectTestCounts.get(name) &&
48
+ !this._pendingDeletions.has(name)) {
49
+ this._pendingDeletions.set(name, this._deleteProjectNamespaces(name));
18
50
  }
19
51
  }
20
52
  async onEnd() {
21
- if (!process.env.CI)
53
+ if (process.env.CI !== "true")
22
54
  return;
55
+ // Await all in-flight deletions started from onTestEnd
56
+ await Promise.all(this._pendingDeletions.values());
57
+ // Fallback: clean up projects that didn't complete naturally
58
+ // (e.g., interrupted run, maxFailures hit)
59
+ for (const [project] of this._projectTestCounts) {
60
+ if (!this._pendingDeletions.has(project)) {
61
+ await this._deleteProjectNamespaces(project);
62
+ }
63
+ }
64
+ }
65
+ async _deleteProjectNamespaces(projectName) {
23
66
  let k8sClient;
24
67
  try {
25
68
  k8sClient = new KubernetesClientHelper();
@@ -28,13 +71,11 @@ export default class TeardownReporter {
28
71
  console.error(`[TeardownReporter] Cannot connect to cluster, skipping teardown:`, error);
29
72
  return;
30
73
  }
31
- for (const projectName of this._projects) {
32
- const customNamespaces = getTeardownNamespaces(projectName);
33
- const namespaces = customNamespaces.length > 0 ? customNamespaces : [projectName];
34
- for (const ns of namespaces) {
35
- console.log(`[TeardownReporter] Deleting namespace "${ns}" (project: ${projectName})`);
36
- await k8sClient.deleteNamespace(ns);
37
- }
74
+ const customNamespaces = getTeardownNamespaces(projectName);
75
+ const namespaces = customNamespaces.length > 0 ? customNamespaces : [projectName];
76
+ for (const ns of namespaces) {
77
+ console.log(`[TeardownReporter] Deleting namespace "${ns}" (project: ${projectName})`);
78
+ await k8sClient.deleteNamespace(ns);
38
79
  }
39
80
  }
40
81
  }
@@ -2,4 +2,5 @@ export { envsubst, requireEnv } from "./common.js";
2
2
  export { $, runQuietUnlessFailure } from "./bash.js";
3
3
  export { mergeYamlFiles, mergeYamlFilesIfExists, mergeYamlFilesToFile, } from "./merge-yamls.js";
4
4
  export { KubernetesClientHelper } from "./kubernetes-client.js";
5
+ export { WorkspacePaths } from "./workspace-paths.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,CAAC,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,CAAC,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC"}
@@ -2,3 +2,4 @@ export { envsubst, requireEnv } from "./common.js";
2
2
  export { $, runQuietUnlessFailure } from "./bash.js";
3
3
  export { mergeYamlFiles, mergeYamlFilesIfExists, mergeYamlFilesToFile, } from "./merge-yamls.js";
4
4
  export { KubernetesClientHelper } from "./kubernetes-client.js";
5
+ export { WorkspacePaths } from "./workspace-paths.js";
@@ -1 +1 @@
1
- {"version":3,"file":"kubernetes-client.d.ts","sourceRoot":"","sources":["../../src/utils/kubernetes-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAO/C;;GAEG;AACH,cAAM,sBAAsB;IAC1B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,iBAAiB,CAAuB;;IAoChD;;OAEG;IACG,uBAAuB,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IA8C3B;;OAEG;IACG,0BAA0B,CAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IA+B3B;;UAEM;IAmBN;;OAEG;IAsBH;;OAEG;YACW,YAAY;IA8B1B;;OAEG;IACG,wBAAwB,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IA0ChB;;OAEG;IACG,qBAAqB,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,EAC7C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAqChB;;OAEG;IACG,eAAe,CACnB,SAAS,EAAE,MAAM,EACjB,eAAe,GAAE,OAAc,EAC/B,cAAc,GAAE,MAAY,GAC3B,OAAO,CAAC,IAAI,CAAC;IAyBhB;;OAEG;YACW,yBAAyB;IAsCvC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;IACG,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAc3E;;OAEG;IACG,uBAAuB,CAC3B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,MAAY,EAC5B,cAAc,GAAE,MAAa,GAC5B,OAAO,CAAC,OAAO,CAAC;IAiBnB;;;OAGG;IACG,uBAAuB,IAAI,OAAO,CAAC,MAAM,CAAC;IAsBhD;;;;;;OAMG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBxE;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAQnC;IAEH;;;;;;;;OAQG;IACG,+BAA+B,CACnC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,cAAc,GAAE,MAAY,EAC5B,cAAc,GAAE,MAAa,GAC5B,OAAO,CAAC,IAAI,CAAC;IA8FhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CA8BzB;AAED,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
1
+ {"version":3,"file":"kubernetes-client.d.ts","sourceRoot":"","sources":["../../src/utils/kubernetes-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,yBAAyB,CAAC;AAO/C;;GAEG;AACH,cAAM,sBAAsB;IAC1B,OAAO,CAAC,GAAG,CAAiB;IAC5B,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,iBAAiB,CAAuB;;IAoChD;;OAEG;IACG,uBAAuB,CAC3B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,EACjB,cAAc,EAAE,MAAM,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IA8C3B;;OAEG;IACG,0BAA0B,CAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;IA+B3B;;UAEM;IAmBN;;OAEG;IAsBH;;OAEG;YACW,YAAY;IA8B1B;;OAEG;IACG,wBAAwB,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IA0ChB;;OAEG;IACG,qBAAqB,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,EAC7C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAqChB;;OAEG;IACG,eAAe,CACnB,SAAS,EAAE,MAAM,EACjB,eAAe,GAAE,OAAc,EAC/B,cAAc,GAAE,MAAY,GAC3B,OAAO,CAAC,IAAI,CAAC;IAyBhB;;OAEG;YACW,yBAAyB;IAsCvC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;OAEG;IACG,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAc3E;;OAEG;IACG,uBAAuB,CAC3B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,cAAc,GAAE,MAAY,EAC5B,cAAc,GAAE,MAAa,GAC5B,OAAO,CAAC,OAAO,CAAC;IAiBnB;;;OAGG;IACG,uBAAuB,IAAI,OAAO,CAAC,MAAM,CAAC;IAsBhD;;;;;;OAMG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkBxE;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAmBxB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAQnC;IAEH;;;;;;;;OAQG;IACG,+BAA+B,CACnC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,EACrB,cAAc,GAAE,MAAY,EAC5B,cAAc,GAAE,MAAa,GAC5B,OAAO,CAAC,IAAI,CAAC;IA2FhB;;OAEG;IACH,OAAO,CAAC,gBAAgB;CA8BzB;AAED,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
@@ -514,8 +514,6 @@ class KubernetesClientHelper {
514
514
  try {
515
515
  console.log(`\n[K8sHelper] ─── Pod Status ───`);
516
516
  await $ `oc get pods -n ${namespace} -l ${labelSelector} -o wide`;
517
- console.log(`\n[K8sHelper] ─── Pod Details ───`);
518
- await $ `oc describe pods -n ${namespace} -l ${labelSelector}`;
519
517
  console.log(`\n[K8sHelper] ─── Namespace Events ───`);
520
518
  await $ `oc get events -n ${namespace} --sort-by='.lastTimestamp'`;
521
519
  console.log(`\n[K8sHelper] ─── Pod Logs ───`);