@camunda/e2e-test-suite 0.0.938 → 0.0.940

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.
@@ -121,11 +121,20 @@ class TaskDetailsPage {
121
121
  async clickUnassignButton() {
122
122
  await this.unassignButton.click();
123
123
  }
124
+ // The "Task completed" toast is a transient confirmation: the v2 webapp's
125
+ // notification store auto-removes it after 5s, and it is never rendered at
126
+ // all when the refreshed task list deselects the completed task before the
127
+ // completion state machine reaches CompletionSucceeded (which is what the
128
+ // nightly trace showed - the task was completed, but no toast ever entered
129
+ // the DOM). Accept the task's own completed state as well: the details panel
130
+ // only renders "Completion date" once the task has one, so this confirms the
131
+ // completion rather than weakening the check.
124
132
  async clickCompleteTaskButton() {
125
133
  await this.completeTaskButton.click({ timeout: 60000 });
126
- await (0, test_1.expect)(this.page.getByText('Task completed')).toBeVisible({
127
- timeout: 60000,
128
- });
134
+ await (0, test_1.expect)(this.page
135
+ .getByText('Task completed')
136
+ .or(this.detailsPanel.getByText('Completion date'))
137
+ .first()).toBeVisible({ timeout: 60000 });
129
138
  await this.page.reload();
130
139
  }
131
140
  async clickAddVariableButton() {
@@ -249,7 +249,11 @@ async function assertPageTextWithRetry(page, text, notVisible = false, timeout =
249
249
  }
250
250
  exports.assertPageTextWithRetry = assertPageTextWithRetry;
251
251
  async function completeTaskWithRetry(taskPanelPage, taskDetailsPage, taskName, taskPriority, maxRetries = 3) {
252
+ const openTask = taskPanelPage.availableTasks
253
+ .getByText(taskName, { exact: true })
254
+ .first();
252
255
  for (let attempt = 0; attempt < maxRetries; attempt++) {
256
+ let completionRequested = false;
253
257
  try {
254
258
  await taskPanelPage.openTask(taskName);
255
259
  await (0, test_1.expect)(taskDetailsPage.detailsInfo.getByText(taskName, { exact: true })).toBeVisible();
@@ -257,11 +261,27 @@ async function completeTaskWithRetry(taskPanelPage, taskDetailsPage, taskName, t
257
261
  await taskDetailsPage.clickAssignToMeButton();
258
262
  }
259
263
  await (0, test_1.expect)(taskDetailsPage.detailsPanel.getByText(taskPriority)).toBeVisible();
264
+ completionRequested = true;
260
265
  await taskDetailsPage.clickCompleteTaskButton();
261
- await (0, test_1.expect)(taskPanelPage.availableTasks.getByText(taskName, { exact: true }).first()).not.toBeVisible({ timeout: 30000 });
266
+ await (0, test_1.expect)(openTask).not.toBeVisible({ timeout: 30000 });
262
267
  return;
263
268
  }
264
269
  catch (error) {
270
+ // Once the Complete Task click has gone out, the task may well have been
271
+ // completed even though its confirmation was missed. Retrying blindly
272
+ // re-enters openTask, which waits 120s per attempt for a task that no
273
+ // longer exists and exhausts the 12 min test timeout, so first check the
274
+ // durable signal: the task leaving the open task list.
275
+ if (completionRequested) {
276
+ const taskGone = await openTask
277
+ .waitFor({ state: 'hidden', timeout: 30000 })
278
+ .then(() => true)
279
+ .catch(() => false);
280
+ if (taskGone) {
281
+ console.warn(`Confirmation for completing task ${taskName} was missed, but the task left the open task list - treating it as completed.`);
282
+ return;
283
+ }
284
+ }
265
285
  if (attempt < maxRetries - 1) {
266
286
  console.warn(`Attempt ${attempt + 1} failed for completing task ${taskName}. Retrying...`);
267
287
  await (0, sleep_1.sleep)(2000);
@@ -74,6 +74,8 @@ declare class ClusterDetailsPage {
74
74
  selectEmailRadioButton(): Promise<void>;
75
75
  clickCreateAlertButton(): Promise<void>;
76
76
  deleteAlerts(): Promise<void>;
77
+ private confirmDelete;
78
+ private dismissDeleteDialog;
77
79
  private doDelete;
78
80
  assertComponentsHealth(components?: string[]): Promise<void>;
79
81
  createAPIClientAndReturnVariables(name: string, setEnvVariables?: boolean): Promise<{
@@ -404,6 +404,45 @@ class ClusterDetailsPage {
404
404
  async deleteAlerts() {
405
405
  await this.doDelete(this.dialog, 'Alerts');
406
406
  }
407
+ // The confirmation modal only closes once the DELETE request resolves. When
408
+ // that call fails the modal stays open on an inline "We're having trouble
409
+ // deleting the alert / fetch error" banner, and Carbon's modal overlay then
410
+ // intercepts pointer events for the whole page — so the next row's Delete
411
+ // click can never land (the nightly trace shows
412
+ // `DELETE /api/orgs/<org>/clusters/<id>/alerts/<uuid>` ending in
413
+ // net::ERR_FAILED, followed by a 60s click timeout on the row button). Retry
414
+ // the confirmation while the modal is up, and guarantee it is gone before the
415
+ // caller touches the list again.
416
+ async confirmDelete(dialog) {
417
+ const maxAttempts = 3;
418
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
419
+ await this.deleteSubButton.click({ timeout: 60000 });
420
+ await (0, test_1.expect)(this.page.getByText('Deleting...')).not.toBeVisible({
421
+ timeout: 60000,
422
+ });
423
+ const closed = await dialog
424
+ .waitFor({ state: 'hidden', timeout: 30000 })
425
+ .then(() => true)
426
+ .catch(() => false);
427
+ if (closed) {
428
+ return true;
429
+ }
430
+ console.warn(`Confirmation dialog still open after delete attempt ${attempt} of ${maxAttempts}`);
431
+ }
432
+ await this.dismissDeleteDialog(dialog);
433
+ return false;
434
+ }
435
+ async dismissDeleteDialog(dialog) {
436
+ const cancelButton = dialog.getByRole('button', { name: 'Cancel' });
437
+ const hasCancel = await cancelButton.isVisible().catch(() => false);
438
+ if (hasCancel) {
439
+ await cancelButton.click({ timeout: 30000 });
440
+ }
441
+ else {
442
+ await this.page.keyboard.press('Escape');
443
+ }
444
+ await dialog.waitFor({ state: 'hidden', timeout: 30000 });
445
+ }
407
446
  async doDelete(dialog, text) {
408
447
  try {
409
448
  await (0, test_1.expect)(this.deleteButton.first()).toBeVisible({
@@ -414,9 +453,12 @@ class ClusterDetailsPage {
414
453
  return; //No items found in the list
415
454
  }
416
455
  try {
417
- let deletes = await this.deleteButton.all();
418
- while (deletes.length > 0) {
419
- const deleteButton = deletes[0];
456
+ let remaining = await this.deleteButton.count();
457
+ // A failed DELETE leaves the row in place; retry it from a clean state
458
+ // instead of giving up on the first stalled round.
459
+ let stalledRounds = 0;
460
+ while (remaining > 0 && stalledRounds < 3) {
461
+ const deleteButton = this.deleteButton.first();
420
462
  if (await deleteButton.isVisible()) {
421
463
  await deleteButton.click({ timeout: 60000 });
422
464
  // Handle confirmation dialog if it appears; some UI states delete without one
@@ -424,17 +466,18 @@ class ClusterDetailsPage {
424
466
  .isVisible({ timeout: 5000 })
425
467
  .catch(() => false);
426
468
  if (dialogVisible) {
427
- await this.deleteSubButton.click();
428
- await (0, test_1.expect)(this.page.getByText('Deleting...')).not.toBeVisible({
429
- timeout: 60000,
430
- });
469
+ if (!(await this.confirmDelete(dialog))) {
470
+ console.warn(`Retrying ${text} deletion after a failed request`);
471
+ }
431
472
  }
432
473
  else {
433
474
  await (0, sleep_1.sleep)(2000);
434
475
  }
435
476
  }
436
477
  await (0, sleep_1.sleep)(3000);
437
- deletes = await this.deleteButton.all();
478
+ const left = await this.deleteButton.count();
479
+ stalledRounds = left < remaining ? 0 : stalledRounds + 1;
480
+ remaining = left;
438
481
  }
439
482
  await (0, test_1.expect)(this.deleteButton).not.toBeVisible({
440
483
  timeout: 30000,
@@ -152,17 +152,23 @@ _8_8_1.test.describe('Console User Flow Tests @tasklistV2', () => {
152
152
  await homePage.clickClusters();
153
153
  await clusterPage.clickClusterLink(alertFlowClusterName);
154
154
  });
155
+ // Console's alerts panel renders its "Alerts keep you informed" empty state
156
+ // whenever the cluster-detail fetch fails (the nightly trace shows
157
+ // `/api/orgs/<org>/clusters/<id>*` calls ending in net::ERR_FAILED), so the
158
+ // alert rows can be missing for a while even though the alert exists and has
159
+ // already triggered. A reload re-issues those fetches, so give the recovery
160
+ // enough reload cycles instead of only three.
155
161
  await _8_8_1.test.step('Verify Alert Count Increases to 1 After Trigger', async () => {
156
162
  await clusterDetailsPage.clickAlertsTab();
157
163
  await (0, test_1.expect)(async () => {
158
164
  await page.reload();
159
165
  await (0, test_1.expect)(clusterDetailsPage.alertsList.first()).toBeVisible({
160
- timeout: 30000,
166
+ timeout: 20000,
161
167
  });
162
168
  (0, test_1.expect)(await clusterDetailsPage.alertsList.count()).toBeGreaterThan(1);
163
169
  await (0, test_1.expect)(clusterDetailsPage.alertsList.nth(0)).toContainText(`Email`);
164
170
  await clusterDetailsPage.assertAlertText('Amount triggered1');
165
- }).toPass({ timeout: 90000 });
171
+ }).toPass({ timeout: 240000 });
166
172
  });
167
173
  await _8_8_1.test.step('Verify Alerts Received via Email for Incident', async () => {
168
174
  await (0, sleep_1.sleep)(60000);
@@ -191,16 +197,17 @@ _8_8_1.test.describe('Console User Flow Tests @tasklistV2', () => {
191
197
  await homePage.clickClusters();
192
198
  await clusterPage.clickClusterLink(alertFlowClusterName);
193
199
  });
200
+ // Same empty-state recovery as the first count assertion above.
194
201
  await _8_8_1.test.step('Verify Alert Count Increases to 3 After Trigger', async () => {
195
202
  await clusterDetailsPage.clickAlertsTab();
196
203
  await (0, test_1.expect)(async () => {
197
204
  await page.reload();
198
205
  await (0, test_1.expect)(clusterDetailsPage.alertsList.first()).toBeVisible({
199
- timeout: 30000,
206
+ timeout: 20000,
200
207
  });
201
208
  (0, test_1.expect)(await clusterDetailsPage.alertsList.count()).toBeGreaterThan(1);
202
209
  await clusterDetailsPage.assertAlertText('Amount triggered3');
203
- }).toPass({ timeout: 90000 });
210
+ }).toPass({ timeout: 240000 });
204
211
  });
205
212
  await _8_8_1.test.step('Verify Alerts Received via Email for Incident', async () => {
206
213
  await (0, sleep_1.sleep)(60000);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.938",
3
+ "version": "0.0.940",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",