@camunda/e2e-test-suite 0.0.1122 → 0.0.1123

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.
@@ -1364,6 +1364,37 @@ class ModelerCreatePage {
1364
1364
  const isDeployComplete = async () => (await deployCompleteIcon.isVisible().catch(() => false)) ||
1365
1365
  (await deploySuccessBadge.isVisible().catch(() => false)) ||
1366
1366
  (await configureTestPanel.isVisible().catch(() => false));
1367
+ // A deploy that FAILED looks, to the probe above, exactly like a deploy
1368
+ // that has not been triggered yet. DeployStepContent renders a
1369
+ // "Deployment failed" badge (or "Missing permissions to deploy" for a
1370
+ // 403) and relabels the very same `test-configuration-deploy-button` to
1371
+ // "Retry" -- still visible, still enabled -- so the loop below happily
1372
+ // re-clicks an action the backend is rejecting and finally reports
1373
+ // `Expected: true Received: false`, which names neither the failure nor
1374
+ // its cause. Read the panel's own verdict instead and put it in the
1375
+ // assertion message, and expand the "Show details" disclosure so the
1376
+ // server message lands in the afterEach screenshot and the trace.
1377
+ const deployErrorBadge = this.page
1378
+ .getByText('Deployment failed', { exact: true })
1379
+ .or(this.page.getByText('Missing permissions to deploy'))
1380
+ .first();
1381
+ const deployErrorDetailsToggle = this.page.locator('[data-test="test-studio-configuration-toggle-details"]');
1382
+ const readDeployError = async () => {
1383
+ const failed = await deployErrorBadge.isVisible().catch(() => false);
1384
+ if (!failed) {
1385
+ return undefined;
1386
+ }
1387
+ const hasDetails = await deployErrorDetailsToggle
1388
+ .isVisible()
1389
+ .catch(() => false);
1390
+ const isExpanded = hasDetails &&
1391
+ (await deployErrorDetailsToggle.getAttribute('aria-expanded')) ===
1392
+ 'true';
1393
+ if (hasDetails && !isExpanded) {
1394
+ await deployErrorDetailsToggle.click({ timeout: 5000 });
1395
+ }
1396
+ return deployErrorBadge.innerText();
1397
+ };
1367
1398
  if (!(await isDeployComplete())) {
1368
1399
  // The Deploy button lives inside the "Deploy process" accordion item,
1369
1400
  // which expands itself once the cluster step completes. Nudge the
@@ -1389,19 +1420,50 @@ class ModelerCreatePage {
1389
1420
  // ("element is not visible", 58 retries, in the click call log). A
1390
1421
  // re-click can only happen while the deploy is provably still
1391
1422
  // incomplete AND the button is enabled -- a deploy in flight disables
1392
- // it and a finished deploy replaces it with the badge, so this cannot
1393
- // double-deploy. If the deploy never completes the loop still fails.
1423
+ // it (or replaces it with the "Deploying..." loader), so this cannot
1424
+ // pile up requests. If the deploy never completes the loop still
1425
+ // fails, now naming the panel's own error when there is one.
1426
+ //
1427
+ // The budget is 4 minutes, not the 2 it used to be: a process
1428
+ // application deploy on SaaS serialises deployProcessApplication(),
1429
+ // fetchLinkedStartForm() and the connector-secret fetch before
1430
+ // TestConfigurationPanel reports the step complete, and the previous
1431
+ // budget expired while that chain was still in flight. The test is
1432
+ // test.slow() (36 min), so the extra headroom is affordable.
1433
+ //
1434
+ // One stall shape is invisible to the re-click above: while the deploy
1435
+ // request is in flight the panel keeps `status === 'deploying-files'`,
1436
+ // which renders the button `disabled` (camunda-hub test-studio
1437
+ // DeployStepContent), so a request that never settles leaves the loop
1438
+ // with nothing clickable and no error badge to report -- it just polls
1439
+ // until the budget expires and reports the bare "never reported
1440
+ // completion". Remount the panel once when that happens: on a fresh
1441
+ // Play mount useSetupEnvironmentStep re-runs
1442
+ // testEnvironmentStore.checkExistingDeployment(), which marks the step
1443
+ // complete when the deployment actually landed, and otherwise leaves an
1444
+ // enabled Deploy button for this loop to click -- i.e. a real retry
1445
+ // either way, not a masked failure.
1446
+ let hasRemountedAfterStall = false;
1447
+ const stallDeadline = Date.now() + 120000;
1394
1448
  await (0, test_1.expect)(async () => {
1395
1449
  if (await isDeployComplete()) {
1396
1450
  return;
1397
1451
  }
1452
+ const deployError = await readDeployError();
1398
1453
  const canClick = (await setupDeployButton.isVisible().catch(() => false)) &&
1399
1454
  (await setupDeployButton.isEnabled().catch(() => false));
1400
1455
  if (canClick) {
1401
1456
  await setupDeployButton.click({ timeout });
1402
1457
  }
1403
- (0, test_1.expect)(await isDeployComplete()).toBe(true);
1404
- }).toPass({ timeout: 120000, intervals: [1000, 2000, 5000] });
1458
+ else if (!hasRemountedAfterStall && Date.now() > stallDeadline) {
1459
+ hasRemountedAfterStall = true;
1460
+ await this.page.reload();
1461
+ await this.switchToPlay();
1462
+ }
1463
+ (0, test_1.expect)(await isDeployComplete(), deployError === undefined
1464
+ ? 'Play "Deploy process" step never reported completion'
1465
+ : `Play "Deploy process" step reported: ${deployError}`).toBe(true);
1466
+ }).toPass({ timeout: 300000, intervals: [1000, 2000, 5000] });
1405
1467
  }
1406
1468
  // Step 3: the configure-test-case step opens on its own once the deploy
1407
1469
  // step completes (TestConfigurationPanel hides the setup overlay in an
@@ -59,6 +59,7 @@ declare class ModelerHomePage {
59
59
  returnToResourceContainer(): Promise<void>;
60
60
  startBlankBpmnDiagram(): Promise<void>;
61
61
  private becameVisible;
62
+ isModelerPageBannerVisible(timeout: number): Promise<boolean>;
62
63
  clickHomeBreadcrumb(): Promise<void>;
63
64
  clickOpenOrganizationsButton(): Promise<void>;
64
65
  clickCrossComponentProjectFolder(): Promise<void>;
@@ -426,6 +426,11 @@ class ModelerHomePage {
426
426
  .then(() => true)
427
427
  .catch(() => false);
428
428
  }
429
+ // Boolean form of the modeler-banner assertion, so a caller can re-open
430
+ // Modeler instead of failing outright when the app shell never mounts.
431
+ async isModelerPageBannerVisible(timeout) {
432
+ return this.becameVisible(this.modelerPageBanner, timeout);
433
+ }
429
434
  async clickHomeBreadcrumb() {
430
435
  try {
431
436
  await this.homeBreadcrumb.click();
@@ -48,7 +48,20 @@ class PlayPage {
48
48
  });
49
49
  }
50
50
  async clickCompleteJobButton() {
51
- await this.completeJobButton.click();
51
+ // The complete-job action is a bpmn-js canvas overlay pinned to the active
52
+ // element, so it is re-laid-out (and briefly detached) whenever the diagram
53
+ // re-renders -- which it does on every job/instance update arriving from
54
+ // the cluster. A bare click that lands in that window silently resolves
55
+ // against a stale node, the job is never completed, and the failure only
56
+ // surfaces two calls later as "waitForNextElementToBeActive" timing out on
57
+ // the next element that consequently never became active. Retry the click
58
+ // against a fresh visibility + clickability check instead.
59
+ await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.completeJobButton, {
60
+ totalTimeout: 120000,
61
+ visibilityTimeout: 30000,
62
+ maxRetries: 3,
63
+ retryDelayMs: 3000,
64
+ });
52
65
  }
53
66
  async clickStartInstanceButton() {
54
67
  // The Modeler Play UI has two surfaces that can hold the start trigger:
@@ -133,8 +146,36 @@ class PlayPage {
133
146
  });
134
147
  }
135
148
  async waitForProcessToBeCompleted() {
136
- await (0, test_1.expect)(this.page.getByText('Completed')).toBeVisible({
149
+ // "Completed" is the bpmn-js overlay Modeler pins to the end event once the
150
+ // instance reaches COMPLETED (camunda-hub test-studio DiagramOverlay ->
151
+ // CompletedOverlay), so it can only render after the LAST job has actually
152
+ // been completed. That makes this the only place where a silently
153
+ // ineffective final complete-job click can surface: the two earlier tasks
154
+ // are each followed by waitForNextElementToBeActive, which catches a lost
155
+ // click, but nothing follows the third one -- so a click that resolved
156
+ // against a re-laid-out (briefly detached) overlay leaves the service-task
157
+ // job pending and the sole symptom is this locator timing out with
158
+ // "element(s) not found", exactly the nightly failure.
159
+ //
160
+ // While the overlay is absent AND a complete-job overlay button is still on
161
+ // the canvas, the job demonstrably was not completed, so re-issue it rather
162
+ // than waiting out the whole budget on a job nothing will complete. The
163
+ // assertion itself is unchanged: the step still only passes on a visible
164
+ // "Completed" overlay.
165
+ const completedOverlay = this.page.getByText('Completed').first();
166
+ await (0, test_1.expect)(async () => {
167
+ const isCompleted = await completedOverlay.isVisible().catch(() => false);
168
+ if (!isCompleted) {
169
+ const isJobStillPending = (await this.completeJobButton.isVisible().catch(() => false)) &&
170
+ (await this.completeJobButton.isEnabled().catch(() => false));
171
+ if (isJobStillPending) {
172
+ await this.completeJobButton.click({ timeout: 30000 });
173
+ }
174
+ }
175
+ await (0, test_1.expect)(completedOverlay).toBeVisible({ timeout: 15000 });
176
+ }).toPass({
137
177
  timeout: maxWaitTimeSeconds,
178
+ intervals: [2000, 5000, 10000],
138
179
  });
139
180
  }
140
181
  }
@@ -27,9 +27,18 @@ _8_7_1.test.describe('Deploy and run a process in Play', () => {
27
27
  });
28
28
  await appsPage.clickCamundaApps();
29
29
  await appsPage.clickModeler();
30
- await (0, test_1.expect)(modelerHomePage.modelerPageBanner).toBeVisible({
31
- timeout: 120000,
32
- });
30
+ // Following the Modeler link occasionally leaves the browser on the
31
+ // Console shell with the Modeler app never mounting, so the banner never
32
+ // renders and the whole flow dies before it has done anything. The link
33
+ // click itself succeeded, so AppsPage's own retry loop does not fire --
34
+ // re-open Modeler from the apps menu here instead.
35
+ if (!(await modelerHomePage.isModelerPageBannerVisible(120000))) {
36
+ await appsPage.clickCamundaApps();
37
+ await appsPage.clickModeler();
38
+ await (0, test_1.expect)(modelerHomePage.modelerPageBanner).toBeVisible({
39
+ timeout: 120000,
40
+ });
41
+ }
33
42
  });
34
43
  await _8_7_1.test.step('Open Cross Component Test Project', async () => {
35
44
  await modelerHomePage.clickCrossComponentProjectFolder();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1122",
3
+ "version": "0.0.1123",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",