@camunda/e2e-test-suite 0.0.1104 → 0.0.1106

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.
@@ -22,6 +22,7 @@ declare class ClusterDetailsPage {
22
22
  readonly clientCredentialsDialog: Locator;
23
23
  readonly clustersLink: Locator;
24
24
  readonly alertsTab: Locator;
25
+ readonly activeTabPanel: Locator;
25
26
  readonly alertsList: Locator;
26
27
  readonly createFirstAlertButton: Locator;
27
28
  readonly createNewAlertButton: Locator;
@@ -28,6 +28,7 @@ class ClusterDetailsPage {
28
28
  clientCredentialsDialog;
29
29
  clustersLink;
30
30
  alertsTab;
31
+ activeTabPanel;
31
32
  alertsList;
32
33
  createFirstAlertButton;
33
34
  createNewAlertButton;
@@ -105,7 +106,14 @@ class ClusterDetailsPage {
105
106
  .getByRole('banner')
106
107
  .getByRole('link', { name: 'Clusters' });
107
108
  this.alertsTab = page.getByRole('tab', { name: 'Alerts' });
108
- this.alertsList = page
109
+ // Only the selected tab's panel is rendered without `hidden`, so this always
110
+ // resolves to the tab currently on screen. Scoping the alert rows to it is
111
+ // what stops `alertsList` from silently counting a different tab's table:
112
+ // unscoped, `getByRole('row')` matched the Overview tab's 15-row "Cluster
113
+ // Details" list whenever the Alerts tab was not the active one, so the
114
+ // "alerts are gone" assertion was reporting rows that were never alerts.
115
+ this.activeTabPanel = page.locator('[role="tabpanel"]:not([hidden])');
116
+ this.alertsList = this.activeTabPanel
109
117
  .getByRole('row')
110
118
  .filter({ hasNotText: 'Delivery method' }); //Filter out header row
111
119
  this.createFirstAlertButton = page.getByRole('button', {
@@ -362,7 +370,26 @@ class ClusterDetailsPage {
362
370
  }
363
371
  async clickAlertsTab() {
364
372
  await (0, test_1.expect)(this.alertsTab).toBeVisible({ timeout: 40000 });
365
- await this.alertsTab.click();
373
+ // The cluster details page re-mounts while its data finishes loading: the
374
+ // nightly trace shows the DOM emptied out at the exact moment of this click,
375
+ // and once the app re-rendered the tab strip was back on its default
376
+ // "Overview" tab with the click discarded. Nothing downstream noticed, so
377
+ // the alert steps ran against the Overview tab. Re-drive the click until the
378
+ // tab reports itself selected.
379
+ await (0, test_1.expect)(async () => {
380
+ const selected = await this.alertsTab.getAttribute('aria-selected');
381
+ if (selected !== 'true') {
382
+ await this.alertsTab.click({ timeout: 30000 });
383
+ }
384
+ await (0, test_1.expect)(this.alertsTab).toHaveAttribute('aria-selected', 'true', {
385
+ timeout: 10000,
386
+ });
387
+ }).toPass({ timeout: 90000 });
388
+ // Wait for the panel to finish loading before the caller reads the list.
389
+ // Exactly one of these renders: "Create an alert" is the empty state,
390
+ // "Create new alert" sits above a populated table. Without this the callers
391
+ // can observe an empty, still-loading panel and mistake it for "no alerts".
392
+ await (0, test_1.expect)(this.createFirstAlertButton.or(this.createNewAlertButton).first()).toBeVisible({ timeout: 60000 });
366
393
  }
367
394
  async clickExpandButton() {
368
395
  await this.expandButton.click({ timeout: 60000 });
@@ -1393,24 +1393,42 @@ class ModelerCreatePage {
1393
1393
  // 1. Connect cluster → "Configure environment" modal → select cluster → Save
1394
1394
  // 2. Deploy process → wait for success banner
1395
1395
  // 3. Configure test case
1396
+ // camunda-hub 8b4226983e (#28226, 2026-09-04) turned the three setup steps
1397
+ // into a Carbon Accordion, so the Deploy button now lives in the "Deploy
1398
+ // process" item's *content*, a sibling of the heading -- scoping by the
1399
+ // heading text's parent can no longer reach it. Anchor on the test id the
1400
+ // hub's own e2e suite uses (test-studio/e2e/pages/Definition.ts), keeping
1401
+ // the text-scoped locator as a fallback for pre-accordion builds.
1396
1402
  const setupDeployButton = this.page
1403
+ .getByTestId('test-configuration-deploy-button')
1404
+ .or(this.page
1397
1405
  .getByText('Deploy process')
1398
1406
  .locator('..')
1399
- .getByRole('button', { name: 'Deploy' });
1407
+ .getByRole('button', { name: 'Deploy' }))
1408
+ .first();
1400
1409
  // Both attributes on this button have been renamed by camunda-hub, in
1401
1410
  // separate commits: a90fd06 changed the label from "Configure scenario" to
1402
1411
  // "Configure test case", and b3958a1649 (#27259, 2026-08-07) then changed
1403
1412
  // the test id from `play-configuration-configure-scenario-button` to
1404
1413
  // `configure-test-case-button`. Match current test id, then pre-rename test
1405
- // id, then either label, so a further rename of any single attribute cannot
1406
- // break the step.
1414
+ // id. The label-based fallback that used to follow them had to go: the
1415
+ // accordion's third heading is itself a <button> labelled "Configure test
1416
+ // case", rendered `disabled={!isConfigureReady}` (camunda-hub
1417
+ // test-studio/src/test-mode/test-configuration-panel/TestConfigurationPanel.tsx).
1418
+ // The regex matched that heading, so the "already deployed?" probe below saw
1419
+ // it, skipped the deploy step outright, and then clicked a permanently
1420
+ // disabled button until the step timed out.
1407
1421
  const configureScenarioButton = this.page
1408
1422
  .getByTestId('configure-test-case-button')
1409
1423
  .or(this.page.getByTestId('play-configuration-configure-scenario-button'))
1410
- .or(this.page.getByRole('button', {
1411
- name: /^Configure (test case|scenario)$/,
1412
- }))
1413
1424
  .first();
1425
+ // Step 2 is an accordion item too, and its content (the Deploy button)
1426
+ // only renders visibly while that item is expanded. It expands by itself
1427
+ // once the cluster step completes, but a manual heading click is the
1428
+ // recovery path if it did not.
1429
+ const deployStepHeading = this.page.getByRole('button', {
1430
+ name: 'Deploy process',
1431
+ });
1414
1432
  // Play settles into exactly ONE of three states, and which one is not
1415
1433
  // knowable up front, so race them instead of timing out on each in turn:
1416
1434
  // the setup overlay, the legacy Continue button, or the configure-test
@@ -1496,25 +1514,91 @@ class ModelerCreatePage {
1496
1514
  // processApplicationId is defined, which it now is, so re-entering
1497
1515
  // Play on an already-deployed process application legitimately
1498
1516
  // has nothing to deploy and renders no Deploy button at all.
1517
+ //
1518
+ // Deploy is done when the step swaps its button for the success badge --
1519
+ // camunda-hub DeployStepContent.tsx renders
1520
+ // `data-testid="deploy-success-badge"` reading "Successfully deployed";
1521
+ // the old "Process has been successfully deployed" banner is gone, so keep
1522
+ // it only as a fallback for older builds. Probing for a Configure control
1523
+ // alone is not enough: current builds render none at all until the deploy
1524
+ // step completes.
1525
+ const deploySuccessBadge = this.page
1526
+ .getByTestId('deploy-success-badge')
1527
+ .or(this.page.getByText('Process has been successfully deployed'))
1528
+ .first();
1529
+ // `deploy-success-badge` on its own is NOT a usable "is the deploy done"
1530
+ // probe. DeployStepContent renders it inside the "Deploy process"
1531
+ // accordion item, and TestConfigurationPanel collapses that item the
1532
+ // instant the deploy finishes (`isDeployStepComplete` ->
1533
+ // `hideConfigurationOverlay()` -> `isDeployOpen` false). Carbon keeps a
1534
+ // collapsed accordion's content mounted, so the badge stays in the DOM
1535
+ // but never becomes visible again -- confirmed in a failing nightly
1536
+ // trace (PR #3339, 8.9), whose call log shows the badge resolving 89
1537
+ // times in a row and reading "hidden" every time. DeployStepIcon
1538
+ // carries the same state in the accordion *heading*, which stays on
1539
+ // screen while the item is collapsed, and the configure panel only
1540
+ // opens once the deploy step completes, so treat any of the three as
1541
+ // proof.
1542
+ const deployCompleteIcon = this.page.locator('[aria-label="Deployment complete"]');
1543
+ const isDeployComplete = async () => (await deployCompleteIcon.isVisible().catch(() => false)) ||
1544
+ (await deploySuccessBadge.isVisible().catch(() => false)) ||
1545
+ (await configureTestPanel.isVisible().catch(() => false));
1499
1546
  const alreadyDeployed = await configureScenarioButton
1500
- .isVisible({ timeout: 3000 })
1547
+ .isEnabled({ timeout: 3000 })
1501
1548
  .catch(() => false);
1502
- if (!alreadyDeployed) {
1503
- // Step 2: deploy wait for enabled; button stays disabled until the cluster
1549
+ if (!alreadyDeployed && !(await isDeployComplete())) {
1550
+ // The Deploy button lives inside the "Deploy process" accordion item,
1551
+ // which expands itself once the cluster step completes. Nudge the
1552
+ // heading if it is still collapsed, otherwise the button is present
1553
+ // but hidden and the click below would time out.
1554
+ const deployButtonShown = await setupDeployButton
1555
+ .isVisible({ timeout: 30000 })
1556
+ .catch(() => false);
1557
+ if (!deployButtonShown) {
1558
+ const canExpandDeployStep = await deployStepHeading
1559
+ .isEnabled({ timeout: 5000 })
1560
+ .catch(() => false);
1561
+ if (canExpandDeployStep) {
1562
+ await deployStepHeading.click({ timeout });
1563
+ }
1564
+ }
1565
+ // Wait for enabled; the button stays disabled until the cluster
1504
1566
  // connection is confirmed by the backend after the Save in step 1.
1505
- await (0, test_1.expect)(setupDeployButton).toBeEnabled({ timeout: 30000 });
1506
- await setupDeployButton.click({ timeout });
1507
- await (0, test_1.expect)(this.page.getByText('Process has been successfully deployed')).toBeVisible({ timeout: 90000 });
1567
+ await (0, test_1.expect)(setupDeployButton).toBeEnabled({ timeout: 60000 });
1568
+ // The click is retried against the completion probe rather than fired
1569
+ // once, because the same collapse re-renders the accordion around the
1570
+ // button: it can detach mid-click, which is the second nightly
1571
+ // symptom. A re-click can only happen while the deploy is provably
1572
+ // still incomplete AND the button is enabled -- a deploy in flight
1573
+ // disables it and a finished deploy replaces it with the badge, so
1574
+ // this cannot double-deploy. If the deploy never completes the loop
1575
+ // still fails.
1576
+ await (0, test_1.expect)(async () => {
1577
+ if (await isDeployComplete()) {
1578
+ return;
1579
+ }
1580
+ const canClick = (await setupDeployButton.isVisible().catch(() => false)) &&
1581
+ (await setupDeployButton.isEnabled().catch(() => false));
1582
+ if (canClick) {
1583
+ await setupDeployButton.click({ timeout });
1584
+ }
1585
+ (0, test_1.expect)(await isDeployComplete()).toBe(true);
1586
+ }).toPass({ timeout: 120000, intervals: [1000, 2000, 5000] });
1508
1587
  }
1509
- // Step 3: leave the overlay, and confirm we actually left it. The
1510
- // button only calls hideConfigurationOverlay(); the overlay's own
1511
- // cluster-change effect can then fire resetDeployment and bring it
1512
- // straight back, and ConfigureTestPanel stays null while it is up.
1513
- // Assert the panel really rendered, and re-drive the click if the
1514
- // overlay returned.
1588
+ // Step 3: the configure-test-case step opens on its own once the deploy
1589
+ // step completes (TestConfigurationPanel hides the setup overlay in an
1590
+ // effect keyed on isDeployStepComplete). Wait for the panel that step
1591
+ // renders; only if it stays closed -- e.g. the panel's own
1592
+ // cluster-change effect fired resetDeployment and reopened setup -- fall
1593
+ // back to clicking the step heading, which by then is enabled.
1515
1594
  await (0, test_1.expect)(async () => {
1516
- if (await configurationOverlay.isVisible()) {
1517
- await configureScenarioButton.click({ timeout });
1595
+ if (!(await configureTestPanel.isVisible())) {
1596
+ const canOpenConfigureStep = await configureScenarioButton
1597
+ .isEnabled({ timeout: 5000 })
1598
+ .catch(() => false);
1599
+ if (canOpenConfigureStep) {
1600
+ await configureScenarioButton.click({ timeout: 15000 });
1601
+ }
1518
1602
  }
1519
1603
  await (0, test_1.expect)(configureTestPanel).toBeVisible({ timeout: 15000 });
1520
1604
  }).toPass({ timeout: 90000 });
@@ -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.1106",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",