@camunda/e2e-test-suite 0.0.923 → 0.0.925

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.
@@ -1197,12 +1197,20 @@ class ModelerCreatePage {
1197
1197
  .getByText('Deploy process')
1198
1198
  .locator('..')
1199
1199
  .getByRole('button', { name: 'Deploy' });
1200
- // Keyed on the test id, not the label: the button reads "Configure test
1201
- // case" since camunda-hub a90fd06 and "Configure scenario" before it. The
1202
- // test id survived that rename but was itself renamed to match the label in
1203
- // camunda-hub b3958a1649 ("remove obsolete Play test mode feature flags"),
1204
- // so the old `play-configuration-*` id no longer exists in the DOM.
1205
- const configureScenarioButton = this.page.getByTestId('configure-test-case-button');
1200
+ // Both attributes on this button have been renamed by camunda-hub, in
1201
+ // separate commits: a90fd06 changed the label from "Configure scenario" to
1202
+ // "Configure test case", and b3958a1649 (#27259, 2026-08-07) then changed
1203
+ // the test id from `play-configuration-configure-scenario-button` to
1204
+ // `configure-test-case-button`. Match current test id, then pre-rename test
1205
+ // id, then either label, so a further rename of any single attribute cannot
1206
+ // break the step.
1207
+ const configureScenarioButton = this.page
1208
+ .getByTestId('configure-test-case-button')
1209
+ .or(this.page.getByTestId('play-configuration-configure-scenario-button'))
1210
+ .or(this.page.getByRole('button', {
1211
+ name: /^Configure (test case|scenario)$/,
1212
+ }))
1213
+ .first();
1206
1214
  // Wait up to 15s for EITHER the new-flow setup panel OR the legacy Continue
1207
1215
  // button to appear. Using .or() avoids separate sequential timeouts that would
1208
1216
  // both expire before the page finishes loading on a slow cluster.
@@ -1049,10 +1049,20 @@ class ModelerCreatePage {
1049
1049
  .getByText('Deploy process')
1050
1050
  .locator('..')
1051
1051
  .getByRole('button', { name: 'Deploy' });
1052
- // Keyed on the test id, not the label: the button reads "Configure test
1053
- // case" since camunda-hub a90fd06 and "Configure scenario" before it, while
1054
- // the test id kept its original wording across the rename.
1055
- const configureScenarioButton = this.page.getByTestId('play-configuration-configure-scenario-button');
1052
+ // Both attributes on this button have been renamed by camunda-hub, in
1053
+ // separate commits: a90fd06 changed the label from "Configure scenario" to
1054
+ // "Configure test case", and b3958a1649 (#27259, 2026-08-07) then changed
1055
+ // the test id from `play-configuration-configure-scenario-button` to
1056
+ // `configure-test-case-button`. Match current test id, then pre-rename test
1057
+ // id, then either label, so a further rename of any single attribute cannot
1058
+ // break the step.
1059
+ const configureScenarioButton = this.page
1060
+ .getByTestId('configure-test-case-button')
1061
+ .or(this.page.getByTestId('play-configuration-configure-scenario-button'))
1062
+ .or(this.page.getByRole('button', {
1063
+ name: /^Configure (test case|scenario)$/,
1064
+ }))
1065
+ .first();
1056
1066
  // Wait up to 15s for EITHER the new-flow setup panel OR the legacy Continue
1057
1067
  // button to appear.
1058
1068
  const setupOrContinue = setupDeployButton.or(this.continueToPlayButton);
@@ -1198,10 +1198,20 @@ class ModelerCreatePage {
1198
1198
  .getByText('Deploy process')
1199
1199
  .locator('..')
1200
1200
  .getByRole('button', { name: 'Deploy' });
1201
- // Keyed on the test id, not the label: the button reads "Configure test
1202
- // case" since camunda-hub a90fd06 and "Configure scenario" before it, while
1203
- // the test id kept its original wording across the rename.
1204
- const configureScenarioButton = this.page.getByTestId('play-configuration-configure-scenario-button');
1201
+ // Both attributes on this button have been renamed by camunda-hub, in
1202
+ // separate commits: a90fd06 changed the label from "Configure scenario" to
1203
+ // "Configure test case", and b3958a1649 (#27259, 2026-08-07) then changed
1204
+ // the test id from `play-configuration-configure-scenario-button` to
1205
+ // `configure-test-case-button`. Match current test id, then pre-rename test
1206
+ // id, then either label, so a further rename of any single attribute cannot
1207
+ // break the step.
1208
+ const configureScenarioButton = this.page
1209
+ .getByTestId('configure-test-case-button')
1210
+ .or(this.page.getByTestId('play-configuration-configure-scenario-button'))
1211
+ .or(this.page.getByRole('button', {
1212
+ name: /^Configure (test case|scenario)$/,
1213
+ }))
1214
+ .first();
1205
1215
  // Wait up to 15s for EITHER the new-flow setup panel OR the legacy Continue
1206
1216
  // button to appear. Using .or() avoids separate sequential timeouts that would
1207
1217
  // both expire before the page finishes loading on a slow cluster.
@@ -1146,15 +1146,19 @@ class ModelerCreatePage {
1146
1146
  .getByText('Deploy process')
1147
1147
  .locator('..')
1148
1148
  .getByRole('button', { name: 'Deploy' });
1149
- // The button reads "Configure test case" since camunda-hub a90fd06 and
1150
- // "Configure scenario" before it. camunda-hub b3958a1649 then renamed its
1151
- // test id from `play-configuration-configure-scenario-button` to
1152
- // `configure-test-case-button` (see
1153
- // TestMode/ConfigurationOverlay/index.tsx). Accept the pre-rename test id
1154
- // too so the page object works either side of the rename.
1149
+ // Both attributes on this button have been renamed by camunda-hub, in
1150
+ // separate commits: a90fd06 changed the label from "Configure scenario" to
1151
+ // "Configure test case", and b3958a1649 (#27259, 2026-08-07) then changed
1152
+ // the test id from `play-configuration-configure-scenario-button` to
1153
+ // `configure-test-case-button`. Match current test id, then pre-rename test
1154
+ // id, then either label, so a further rename of any single attribute cannot
1155
+ // break the step.
1155
1156
  const configureScenarioButton = this.page
1156
1157
  .getByTestId('configure-test-case-button')
1157
1158
  .or(this.page.getByTestId('play-configuration-configure-scenario-button'))
1159
+ .or(this.page.getByRole('button', {
1160
+ name: /^Configure (test case|scenario)$/,
1161
+ }))
1158
1162
  .first();
1159
1163
  // Wait up to 15s for EITHER the new-flow setup panel OR the legacy Continue
1160
1164
  // button to appear. Using .or() avoids separate sequential timeouts that would
@@ -890,13 +890,19 @@ class ModelerCreatePage {
890
890
  .getByText('Deploy process')
891
891
  .locator('..')
892
892
  .getByRole('button', { name: 'Deploy' });
893
- // camunda-hub a90fd06 renamed this step to "Configure test case" AND
894
- // renamed its test id to `configure-test-case-button` (see
895
- // TestMode/ConfigurationOverlay/index.tsx). Accept the pre-rename test id
896
- // too so the page object works either side of the rename.
893
+ // Both attributes on this button have been renamed by camunda-hub, in
894
+ // separate commits: a90fd06 changed the label from "Configure scenario" to
895
+ // "Configure test case", and b3958a1649 (#27259, 2026-08-07) then changed
896
+ // the test id from `play-configuration-configure-scenario-button` to
897
+ // `configure-test-case-button`. Match current test id, then pre-rename test
898
+ // id, then either label, so a further rename of any single attribute cannot
899
+ // break the step.
897
900
  const configureScenarioButton = this.page
898
901
  .getByTestId('configure-test-case-button')
899
902
  .or(this.page.getByTestId('play-configuration-configure-scenario-button'))
903
+ .or(this.page.getByRole('button', {
904
+ name: /^Configure (test case|scenario)$/,
905
+ }))
900
906
  .first();
901
907
  // Wait up to 15s for EITHER the new-flow setup panel OR the legacy Continue
902
908
  // button to appear. Using .or() avoids separate sequential timeouts that would
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.updateClusterDataFilters = exports.getClusterDataFilters = exports.getTestClusterUuid = exports.authConsoleManagementAPI = exports.updateCollectionScope = exports.createSingleProcessReport = exports.createDashboard = exports.createCollection = exports.getOptimizeCookieSm = exports.getOptimizeCoockie = exports.createStringClusterVariable = exports.createJsonClusterVariable = exports.waitForProcessInstanceVisible = exports.createProcessInstance = exports.deployProcess = exports.waitForInboundWebhookRegistered = exports.waitForConnectorsReady = exports.validateMcpServerHealth = exports.authC8runAPI = exports.authSmAPI = exports.authSaasAPI = exports.authAPI = exports.buildZeebeApiUrl = exports.retryOn500 = exports.sendRequestAndAssertResponse = exports.assertUnauthorizedResponseBody = exports.expectUnauthorizedErrorBody = exports.assertResponseStatus = exports.getApiRequestContext = void 0;
7
7
  const test_1 = require("@playwright/test");
8
8
  const sleep_1 = require("./sleep");
9
+ const randomSleep_1 = require("./randomSleep");
9
10
  const fs_1 = __importDefault(require("fs"));
10
11
  const path_1 = __importDefault(require("path"));
11
12
  const os_1 = __importDefault(require("os"));
@@ -604,7 +605,14 @@ async function createStringClusterVariable(authToken, environment = 'saas', cust
604
605
  exports.createStringClusterVariable = createStringClusterVariable;
605
606
  async function getOptimizeCoockie(page) {
606
607
  const optimizeUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
607
- const maxLoginAttempts = 3;
608
+ const maxLoginAttempts = 4;
609
+ // This hook runs once per worker that picks up any test from an Optimize
610
+ // describe, so with 37 workers dozens of full interactive Auth0 logins for
611
+ // the same user fire within the same second. Stagger the first navigation to
612
+ // spread that burst -- it is enough on its own to trip Auth0's tenant-wide
613
+ // rate limit, which then fails every worker at once. Retries back off via
614
+ // randomSleep below, so this only needs to run once.
615
+ await (0, randomSleep_1.randomSleep)(0, 15000);
608
616
  // Auth0 can fail or rate-limit concurrent logins. Retry the whole flow if
609
617
  // loginToApp throws (e.g. waitForURL times out after a bad Auth0 redirect).
610
618
  for (let loginAttempt = 0; loginAttempt < maxLoginAttempts; loginAttempt++) {
@@ -616,9 +624,18 @@ async function getOptimizeCoockie(page) {
616
624
  }
617
625
  catch (error) {
618
626
  if (loginAttempt < maxLoginAttempts - 1) {
627
+ const rateLimited = String(error).includes(utils_1.AUTH0_RATE_LIMIT);
619
628
  console.warn(`getOptimizeCoockie: login attempt ${loginAttempt + 1} failed, retrying after backoff...`, error);
620
629
  await page.goto('about:blank');
621
- await page.waitForTimeout(5000 * (loginAttempt + 1));
630
+ if (rateLimited) {
631
+ // Auth0 rate-limit windows commonly last 30-90s. Back off long
632
+ // enough to outlast the window; a 5-10s backoff just retries inside
633
+ // the same window and burns the attempt budget for nothing.
634
+ await (0, randomSleep_1.randomSleep)(60000, 90000);
635
+ }
636
+ else {
637
+ await (0, randomSleep_1.randomSleep)(10000, 20000);
638
+ }
622
639
  }
623
640
  else {
624
641
  throw error;
@@ -1,2 +1,3 @@
1
1
  import { Page } from '@playwright/test';
2
+ export declare const AUTH0_RATE_LIMIT = "AUTH0_RATE_LIMIT";
2
3
  export declare function loginToApp(appName: string, page: Page): Promise<void>;
@@ -1,25 +1,50 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.loginToApp = void 0;
3
+ exports.loginToApp = exports.AUTH0_RATE_LIMIT = void 0;
4
4
  const test_1 = require("@playwright/test");
5
5
  const LoginPage_1 = require("../pages/8.8/LoginPage");
6
+ exports.AUTH0_RATE_LIMIT = 'AUTH0_RATE_LIMIT';
7
+ async function throwIfRateLimited(loginPage) {
8
+ const rateLimited = await loginPage.rateLimitError
9
+ .first()
10
+ .isVisible()
11
+ .catch(() => false);
12
+ if (rateLimited) {
13
+ throw new Error(`${exports.AUTH0_RATE_LIMIT}: identity provider returned an error page`);
14
+ }
15
+ }
6
16
  async function loginToApp(appName, page) {
7
17
  await page.goto(appName, { waitUntil: 'domcontentloaded', timeout: 60000 });
8
18
  await page.waitForLoadState('networkidle', { timeout: 30000 }).catch(() => { });
9
19
  const loginPage = new LoginPage_1.LoginPage(page);
10
- await (0, test_1.expect)(loginPage.usernameInput).toBeVisible({ timeout: 60000 });
20
+ // Auth0 serves a tenant-wide rate-limit error page that carries none of the
21
+ // usual auth controls. Settle on whichever of the two actually renders, then
22
+ // classify: waiting on usernameInput alone burns the full 60s before the
23
+ // caller can tell a rate limit apart from a slow login form, and the caller
24
+ // needs that distinction to pick a backoff long enough to outlast the window.
25
+ await (0, test_1.expect)(loginPage.usernameInput.or(loginPage.rateLimitError.first())).toBeVisible({ timeout: 60000 });
26
+ await throwIfRateLimited(loginPage);
11
27
  await loginPage.fillUsername(process.env.C8_USERNAME);
12
28
  await (0, test_1.expect)(loginPage.usernameInput).toHaveValue(process.env.C8_USERNAME);
13
29
  await (0, test_1.expect)(loginPage.loginMessage).toBeVisible();
14
30
  await loginPage.clickContinueButton();
15
- await (0, test_1.expect)(loginPage.passwordInput).toBeVisible({ timeout: 90000 });
31
+ await (0, test_1.expect)(loginPage.passwordInput.or(loginPage.rateLimitError.first())).toBeVisible({ timeout: 90000 });
32
+ await throwIfRateLimited(loginPage);
16
33
  await loginPage.fillPassword(process.env.C8_PASSWORD);
17
34
  await (0, test_1.expect)(loginPage.passwordHeading).toBeVisible({ timeout: 90000 });
18
35
  await loginPage.clickLoginButton();
19
- await page.waitForURL((url) => url.toString().startsWith(appName), {
20
- timeout: 60000,
21
- waitUntil: 'commit',
22
- });
36
+ try {
37
+ await page.waitForURL((url) => url.toString().startsWith(appName), {
38
+ timeout: 60000,
39
+ waitUntil: 'commit',
40
+ });
41
+ }
42
+ catch (error) {
43
+ // Auth0 can also serve the rate-limit page as the response to the password
44
+ // submit, in which case the redirect back to appName never happens.
45
+ await throwIfRateLimited(loginPage);
46
+ throw error;
47
+ }
23
48
  await page
24
49
  .waitForLoadState('domcontentloaded', { timeout: 30000 })
25
50
  .catch(() => { });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.923",
3
+ "version": "0.0.925",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",