@camunda/e2e-test-suite 0.0.1104 → 0.0.1105

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.
@@ -29,7 +29,15 @@ class AppsPage {
29
29
  this.appSwitcherButton = page.getByLabel('App Switcher');
30
30
  this.tasklistLink = page.getByRole('link', { name: 'Tasklist', exact: true });
31
31
  this.adminLink = page.getByRole('link', { name: /^(Admin|Identity)$/ });
32
- this.operateLink = page.getByRole('link', { name: 'Operate', exact: true });
32
+ // Console renders its OWN "Operate" nav link pointing at
33
+ // /org/<id>/appTeaser/operate — the "Create a cluster to use Operate"
34
+ // teaser page, not a cluster's Operate. It carries the same role and
35
+ // accessible name as the app switcher's cluster-scoped Operate link, so an
36
+ // unfiltered locator silently navigates to the teaser and every downstream
37
+ // Operate assertion then fails on a Console page. Match only the real link.
38
+ this.operateLink = page
39
+ .getByRole('link', { name: 'Operate', exact: true })
40
+ .and(page.locator('a:not([href*="appTeaser"])'));
33
41
  this.optimizeLink = page.getByRole('link', { name: 'Optimize', exact: true });
34
42
  this.consoleLink = page.getByRole('link', { name: 'Console', exact: true });
35
43
  this.camundaComponentsButton = page.getByLabel('Camunda components');
@@ -84,7 +92,15 @@ class AppsPage {
84
92
  }
85
93
  catch (error) {
86
94
  console.warn(`Click attempt ${retries + 1} failed: ${error}`);
87
- await new Promise((resolve) => setTimeout(resolve, 10000));
95
+ // The app-switcher panel can open with no entries at all when the
96
+ // request that populates it fails (the nightly trace shows the panel
97
+ // open and empty, with its backing requests erroring out). Re-clicking
98
+ // the switcher only toggles that same empty panel shut, so the retries
99
+ // could never recover. Reload first so the panel is rebuilt from a
100
+ // fresh fetch — the same recovery clickOperate/clickTasklist/clickAdmin
101
+ // already use.
102
+ await this.page.waitForLoadState('domcontentloaded');
103
+ await this.page.reload();
88
104
  }
89
105
  }
90
106
  throw new Error(`Failed to click the modeler link after ${maxRetries} attempts.`);
@@ -192,8 +192,17 @@ class ClusterPage {
192
192
  }
193
193
  async clickClusterNameInput() {
194
194
  await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.clusterNameInput, {
195
+ visibilityTimeout: 30000,
196
+ totalTimeout: 120000,
195
197
  postAction: async () => {
198
+ // Going back to the Clusters list is not a recovery on its own: the
199
+ // create-cluster form is a separate route, so the name input can never
200
+ // reappear until "Create new cluster" is pressed again. The nightly
201
+ // trace shows the form's `clusters/parameters` request failing, which
202
+ // left the form empty, and every retry then waited on an input that was
203
+ // no longer reachable. Re-open the form so the request is retried.
196
204
  await this.clickClusterBanner();
205
+ await this.clickCreateNewClusterButton();
197
206
  },
198
207
  });
199
208
  }
@@ -1334,10 +1334,36 @@ class ModelerCreatePage {
1334
1334
  // 1. Connect cluster → "Configure environment" modal → select cluster → Save
1335
1335
  // 2. Deploy process → wait for success banner
1336
1336
  // 3. Configure test case
1337
+ // The Deploy button lives in the accordion item's *content* panel, a
1338
+ // sibling of the "Deploy process" heading -- not inside it -- so the
1339
+ // label-scoped locator below resolves to nothing on current builds. The
1340
+ // "Test Studio" rebrand gave the button the stable test id
1341
+ // `test-configuration-deploy-button` (camunda-hub
1342
+ // `frontend/packages/modeler/test-studio/src/test-mode/configuration-overlay/DeployStepContent.tsx`).
1343
+ // Prefer it, and keep the label-scoped locator as a fallback for older
1344
+ // modeler builds that render the button without a test id.
1337
1345
  const setupDeployButton = this.page
1346
+ .getByTestId('test-configuration-deploy-button')
1347
+ .or(this.page
1338
1348
  .getByText('Deploy process')
1339
1349
  .locator('..')
1340
- .getByRole('button', { name: 'Deploy' });
1350
+ .getByRole('button', { name: 'Deploy' }))
1351
+ .first();
1352
+ // Deploy completion signal. camunda-hub 8b4226983e (#28226, 2026-09-04)
1353
+ // replaced the overlay's "Process has been successfully deployed." status
1354
+ // text with a badge carrying `deploy-success-badge`; keep the old sentence
1355
+ // as a fallback for modeler builds from before that commit.
1356
+ const deploySuccessBadge = this.page
1357
+ .getByTestId('deploy-success-badge')
1358
+ .or(this.page.getByText('Process has been successfully deployed'))
1359
+ .first();
1360
+ // Step 2 is an accordion item too, and its content (the Deploy button)
1361
+ // only renders visibly while that item is expanded. It expands by itself
1362
+ // once the cluster step completes, but a manual heading click is the
1363
+ // recovery path if it did not.
1364
+ const deployStepHeading = this.page.getByRole('button', {
1365
+ name: 'Deploy process',
1366
+ });
1341
1367
  // Both attributes on this button have been renamed by camunda-hub, in
1342
1368
  // separate commits: a90fd06 changed the label from "Configure scenario" to
1343
1369
  // "Configure test case", and b3958a1649 (#27259, 2026-08-07) then changed
@@ -1437,25 +1463,85 @@ class ModelerCreatePage {
1437
1463
  // processApplicationId is defined, which it now is, so re-entering
1438
1464
  // Play on an already-deployed process application legitimately
1439
1465
  // has nothing to deploy and renders no Deploy button at all.
1466
+ // The "Configure test case" accordion header is always rendered once the
1467
+ // overlay is up -- TestConfigurationPanel renders it whenever
1468
+ // canShowConfigureSection and only sets `disabled={!isConfigureReady}` --
1469
+ // so isVisible() alone is always true here. Gating on it skipped Step 2
1470
+ // even while deploy was still pending, and Step 3 then burned its whole
1471
+ // budget clicking a permanently disabled button. Gate on isEnabled().
1440
1472
  const alreadyDeployed = await configureScenarioButton
1441
- .isVisible({ timeout: 3000 })
1473
+ .isEnabled({ timeout: 3000 })
1442
1474
  .catch(() => false);
1443
- if (!alreadyDeployed) {
1444
- // Step 2: deploy wait for enabled; button stays disabled until the cluster
1475
+ // `deploy-success-badge` on its own is NOT a usable "is the deploy done"
1476
+ // probe. DeployStepContent renders it inside the "Deploy process"
1477
+ // accordion item, and TestConfigurationPanel collapses that item the
1478
+ // instant the deploy finishes (`isDeployStepComplete` ->
1479
+ // `hideConfigurationOverlay()` -> `isDeployOpen` false). Carbon keeps a
1480
+ // collapsed accordion's content mounted, so the badge stays in the DOM
1481
+ // but never becomes visible again -- confirmed in a failing nightly
1482
+ // trace, whose call log shows the badge resolving 89 times in a row and
1483
+ // reading "hidden" every time. DeployStepIcon carries the same state in
1484
+ // the accordion *heading*, which stays on screen while the item is
1485
+ // collapsed, and the configure panel only opens once the deploy step
1486
+ // completes, so treat any of the three as proof.
1487
+ const deployCompleteIcon = this.page.locator('[aria-label="Deployment complete"]');
1488
+ const isDeployComplete = async () => (await deployCompleteIcon.isVisible().catch(() => false)) ||
1489
+ (await deploySuccessBadge.isVisible().catch(() => false)) ||
1490
+ (await configureTestPanel.isVisible().catch(() => false));
1491
+ if (!alreadyDeployed && !(await isDeployComplete())) {
1492
+ // The Deploy button lives inside the "Deploy process" accordion item,
1493
+ // which expands itself once the cluster step completes. Nudge the
1494
+ // heading if it is still collapsed, otherwise the button is present
1495
+ // but hidden and the click below would time out.
1496
+ const deployButtonShown = await setupDeployButton
1497
+ .isVisible({ timeout: 30000 })
1498
+ .catch(() => false);
1499
+ if (!deployButtonShown) {
1500
+ const canExpandDeployStep = await deployStepHeading
1501
+ .isEnabled({ timeout: 5000 })
1502
+ .catch(() => false);
1503
+ if (canExpandDeployStep) {
1504
+ await deployStepHeading.click({ timeout });
1505
+ }
1506
+ }
1507
+ // Wait for enabled; the button stays disabled until the cluster
1445
1508
  // connection is confirmed by the backend after the Save in step 1.
1446
- await (0, test_1.expect)(setupDeployButton).toBeEnabled({ timeout: 30000 });
1447
- await setupDeployButton.click({ timeout });
1448
- await (0, test_1.expect)(this.page.getByText('Process has been successfully deployed')).toBeVisible({ timeout: 90000 });
1509
+ await (0, test_1.expect)(setupDeployButton).toBeEnabled({ timeout: 60000 });
1510
+ // The click is retried against the completion probe rather than fired
1511
+ // once, because the same collapse re-renders the accordion around the
1512
+ // button: it can detach mid-click, which is the second nightly
1513
+ // symptom (a stuck-hidden badge, or the later Start button never
1514
+ // rendering because deploy silently never landed). A re-click can
1515
+ // only happen while the deploy is provably still incomplete AND the
1516
+ // button is enabled -- a deploy in flight disables it and a finished
1517
+ // deploy replaces it with the badge, so this cannot double-deploy. If
1518
+ // the deploy never completes the loop still fails.
1519
+ await (0, test_1.expect)(async () => {
1520
+ if (await isDeployComplete()) {
1521
+ return;
1522
+ }
1523
+ const canClick = (await setupDeployButton.isVisible().catch(() => false)) &&
1524
+ (await setupDeployButton.isEnabled().catch(() => false));
1525
+ if (canClick) {
1526
+ await setupDeployButton.click({ timeout });
1527
+ }
1528
+ (0, test_1.expect)(await isDeployComplete()).toBe(true);
1529
+ }).toPass({ timeout: 120000, intervals: [1000, 2000, 5000] });
1449
1530
  }
1450
- // Step 3: leave the overlay, and confirm we actually left it. The
1451
- // button only calls hideConfigurationOverlay(); the overlay's own
1452
- // cluster-change effect can then fire resetDeployment and bring it
1453
- // straight back, and ConfigureTestPanel stays null while it is up.
1454
- // Assert the panel really rendered, and re-drive the click if the
1455
- // overlay returned.
1531
+ // Step 3: the configure-test-case step opens on its own once the deploy
1532
+ // step completes (TestConfigurationPanel hides the setup overlay in an
1533
+ // effect keyed on isDeployStepComplete). Wait for the panel that step
1534
+ // renders; only if it stays closed -- e.g. the panel's own
1535
+ // cluster-change effect fired resetDeployment and reopened setup -- fall
1536
+ // back to clicking the step heading, which by then is enabled.
1456
1537
  await (0, test_1.expect)(async () => {
1457
- if (await configurationOverlay.isVisible()) {
1458
- await configureScenarioButton.click({ timeout });
1538
+ if (!(await configureTestPanel.isVisible())) {
1539
+ const canOpenConfigureStep = await configureScenarioButton
1540
+ .isEnabled({ timeout: 5000 })
1541
+ .catch(() => false);
1542
+ if (canOpenConfigureStep) {
1543
+ await configureScenarioButton.click({ timeout: 15000 });
1544
+ }
1459
1545
  }
1460
1546
  await (0, test_1.expect)(configureTestPanel).toBeVisible({ timeout: 15000 });
1461
1547
  }).toPass({ timeout: 90000 });
@@ -55,6 +55,11 @@ _8_9_1.test.describe('Orchestration Cluster MCP Server - Cluster Tools @tasklist
55
55
  _8_9_1.test.slow();
56
56
  await _8_9_1.test.step('Navigate to completed process in Operate', async () => {
57
57
  await homePage.clickClusters();
58
+ // clickOperate expects the app switcher to already be open: its
59
+ // first attempt looks for the switcher's Operate entry, which does
60
+ // not exist on the Clusters page, so it always burned an attempt
61
+ // before recovering. Open it first, as every other spec does.
62
+ await appsPage.clickCamundaApps();
58
63
  await appsPage.clickOperate(clusterName);
59
64
  await (0, test_1.expect)(operateHomePage.operateBanner).toBeVisible({
60
65
  timeout: 60000,
@@ -108,6 +108,11 @@ _8_9_1.test.describe('Orchestration Cluster MCP Server - User Task Tools @taskli
108
108
  await _8_9_1.test.step('Navigate to completed process in Operate', async () => {
109
109
  await page.goto('/');
110
110
  await homePage.clickClusters();
111
+ // clickOperate expects the app switcher to already be open: its
112
+ // first attempt looks for the switcher's Operate entry, which does
113
+ // not exist on the Clusters page, so it always burned an attempt
114
+ // before recovering. Open it first, as every other spec does.
115
+ await appsPage.clickCamundaApps();
111
116
  await appsPage.clickOperate(clusterName);
112
117
  await (0, test_1.expect)(operateHomePage.operateBanner).toBeVisible({
113
118
  timeout: 60000,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1104",
3
+ "version": "0.0.1105",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",