@camunda/e2e-test-suite 0.0.1144 → 0.0.1146

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.
@@ -35,6 +35,7 @@ declare class ModelerCreatePage {
35
35
  readonly cancelButton: Locator;
36
36
  readonly restConnectorOption: Locator;
37
37
  readonly changeElementSearchInput: Locator;
38
+ readonly changeElementResults: Locator;
38
39
  readonly changeElementTabStrip: Locator;
39
40
  readonly reusableAssetsTab: Locator;
40
41
  readonly marketPlaceButton: Locator;
@@ -176,6 +177,8 @@ declare class ModelerCreatePage {
176
177
  expandAssignmentSection(): Promise<void>;
177
178
  clickAppendElementButton(): Promise<void>;
178
179
  clickParallelGatewayOption(): Promise<void>;
180
+ private openReplacePopup;
181
+ private revealReplaceEntry;
179
182
  clickConnectToOtherElementButton(): Promise<void>;
180
183
  clickPriorityInput(): Promise<void>;
181
184
  fillPriorityInput(priority: string): Promise<void>;
@@ -42,6 +42,7 @@ class ModelerCreatePage {
42
42
  cancelButton;
43
43
  restConnectorOption;
44
44
  changeElementSearchInput;
45
+ changeElementResults;
45
46
  changeElementTabStrip;
46
47
  reusableAssetsTab;
47
48
  marketPlaceButton;
@@ -207,6 +208,7 @@ class ModelerCreatePage {
207
208
  .locator('.djs-popup-results')
208
209
  .locator('[data-id="replace.template-io.camunda.connectors.HttpJson.v2"]');
209
210
  this.changeElementSearchInput = page.locator('.djs-popup-search input');
211
+ this.changeElementResults = page.locator('.djs-popup-results');
210
212
  this.changeElementTabStrip = page.locator('.djs-popup-tabs-container');
211
213
  // The tab renders its label as text content, and the product source
212
214
  // spells it both "Reusable Assets" and "Reusable assets".
@@ -1191,14 +1193,17 @@ class ModelerCreatePage {
1191
1193
  (0, test_1.expect)(deployComplete).toBe(true);
1192
1194
  }).toPass({ timeout: 90000 });
1193
1195
  }
1194
- // Step 3: leave the overlay, and confirm we actually left it. The
1195
- // button only calls hideConfigurationOverlay(); the overlay's own
1196
- // cluster-change effect can then fire resetDeployment and bring it
1197
- // straight back, and ConfigureTestPanel stays null while it is up.
1198
- // Assert the panel really rendered, and re-drive the click if the
1199
- // overlay returned.
1196
+ // Step 3: reveal the "Configure test case" section. In the current Test
1197
+ // Studio the "Setup environment" panel is an inline accordion, not a
1198
+ // blocking overlay -- its heading is always present and step 3 auto-opens
1199
+ // once deploy completes, rendering ConfigureTestPanel with the Start
1200
+ // button. Clicking the "Configure test case" accordion heading while it
1201
+ // is already open calls showConfigurationOverlay() and collapses the
1202
+ // panel again, so only click it to OPEN the section when the panel is not
1203
+ // yet visible; keying on the always-present overlay heading here would
1204
+ // re-collapse the panel on every pass.
1200
1205
  await (0, test_1.expect)(async () => {
1201
- if (await configurationOverlay.isVisible()) {
1206
+ if (!(await configureTestPanel.isVisible())) {
1202
1207
  await configureScenarioButton.click({ timeout });
1203
1208
  }
1204
1209
  await (0, test_1.expect)(configureTestPanel).toBeVisible({ timeout: 15000 });
@@ -1387,8 +1392,77 @@ class ModelerCreatePage {
1387
1392
  // multiplied the worst-case wait.
1388
1393
  await this.hoverOnLocator(this.appendPreButton);
1389
1394
  }
1395
+ // Owns the whole replace step, popup included: the append leaves the new
1396
+ // (exclusive) gateway selected while the canvas is still panning it into
1397
+ // view, and a forced "Change element" click issued mid-pan lands on empty
1398
+ // canvas -- that clears the selection, closes the context pad, and the
1399
+ // replace popup never opens, so a bare wait on the entry burns its full
1400
+ // timeout with nothing on screen. Pin the shape by id up front so the popup
1401
+ // can be reopened against the same element instead of a positional one.
1390
1402
  async clickParallelGatewayOption() {
1391
- await this.parallelGatewayOption.click({ timeout: 90000 });
1403
+ const selectedId = await this.page
1404
+ .locator('.djs-element.selected')
1405
+ .first()
1406
+ .getAttribute('data-element-id', { timeout: 10000 })
1407
+ .catch(() => null);
1408
+ const element = selectedId
1409
+ ? this.page
1410
+ .locator(`.djs-element[data-element-id="${selectedId}"]`)
1411
+ .first()
1412
+ : this.page.locator('.djs-element.selected').first();
1413
+ const maxRetries = 3;
1414
+ let lastError;
1415
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
1416
+ try {
1417
+ if (attempt > 1) {
1418
+ // Drop a popup left open on a stale search filter (or on the wrong
1419
+ // element) so the retry reopens a fresh one for `element`.
1420
+ await this.page.keyboard.press('Escape');
1421
+ }
1422
+ await this.openReplacePopup(element, attempt > 1);
1423
+ await this.revealReplaceEntry(this.parallelGatewayOption, 'Parallel gateway');
1424
+ await this.parallelGatewayOption.click({ timeout: 30000 });
1425
+ // bpmn-js closes the popup once an entry is applied, so a popup still
1426
+ // on screen means the click was swallowed and the element was not
1427
+ // replaced.
1428
+ await (0, test_1.expect)(this.changeElementResults).toBeHidden({ timeout: 30000 });
1429
+ return;
1430
+ }
1431
+ catch (error) {
1432
+ lastError = error;
1433
+ console.error(`Parallel gateway attempt ${attempt} failed: ${error}`);
1434
+ await (0, sleep_1.sleep)(5000);
1435
+ }
1436
+ }
1437
+ throw new Error(`Failed to replace the element with a parallel gateway after ${maxRetries} attempts: ${lastError}`);
1438
+ }
1439
+ async openReplacePopup(element, force) {
1440
+ if (await this.isVisibleWithin(this.changeElementResults, 2000)) {
1441
+ return;
1442
+ }
1443
+ // The context pad only renders for a selected element, so "Change element"
1444
+ // would otherwise never appear.
1445
+ if (!(await this.isVisibleWithin(this.changeTypeButton, 5000))) {
1446
+ await element.click({ force: true, timeout: 30000 });
1447
+ }
1448
+ await this.changeTypeButton.click({ timeout: 60000, force });
1449
+ await (0, test_1.expect)(this.changeElementResults).toBeVisible({ timeout: 30000 });
1450
+ }
1451
+ async revealReplaceEntry(option, searchTerm) {
1452
+ if (await this.isVisibleWithin(option, 5000)) {
1453
+ return;
1454
+ }
1455
+ // The popup lists the project's deployed resources alongside the built-in
1456
+ // replace entries, so the built-in entry can sit below the fold of the
1457
+ // scrolling results list; the popup's own search filters it back into view.
1458
+ if (await this.isVisibleWithin(this.changeElementSearchInput, 5000)) {
1459
+ await this.changeElementSearchInput.click();
1460
+ await this.changeElementSearchInput.fill('');
1461
+ await this.changeElementSearchInput.pressSequentially(searchTerm, {
1462
+ delay: 50,
1463
+ });
1464
+ }
1465
+ await (0, test_1.expect)(option).toBeVisible({ timeout: 30000 });
1392
1466
  }
1393
1467
  async clickConnectToOtherElementButton() {
1394
1468
  await (0, test_1.expect)(this.connectToOtherElementButton).toBeVisible({
@@ -1427,7 +1501,6 @@ class ModelerCreatePage {
1427
1501
  await this.hoverOnLocator(this.appendElementButton);
1428
1502
  }
1429
1503
  await this.clickAppendGatewayButton();
1430
- await this.clickChangeTypeButton();
1431
1504
  await this.clickParallelGatewayOption();
1432
1505
  await this.clickAppendElementButton();
1433
1506
  await this.clickAppendTaskButton();
@@ -1441,7 +1514,6 @@ class ModelerCreatePage {
1441
1514
  await this.assertImplementationOption('zeebeUserTask');
1442
1515
  await this.clickAppendElementButton();
1443
1516
  await this.clickAppendGatewayButton();
1444
- await this.clickChangeTypeButton();
1445
1517
  await this.clickParallelGatewayOption();
1446
1518
  for (let i = 2; i <= numberOfTasks; i++) {
1447
1519
  await this.clickFirstPlacedGateway();
@@ -156,19 +156,15 @@ class PlayPage {
156
156
  .or(this.startInstanceButton)
157
157
  .or(this.startInstanceWithCachedButton)
158
158
  .first();
159
- // Test Studio's "Setup environment" overlay can bounce back AFTER
160
- // completePlayConfiguration() has already returned: leaving it only calls
161
- // hideConfigurationOverlay(), and the overlay's cluster-change effect can
162
- // then fire resetDeployment and re-open it at the "Configure test case"
163
- // step. ConfigureTestPanel (and its Start button) render null for as long
164
- // as the overlay is up, so the Start trigger never appears. Re-drive the
165
- // "Configure test case" click before each attempt -- the same recovery
166
- // completePlayConfiguration() uses -- so the panel is present when we click.
167
- const configurationOverlay = this.page
168
- .locator('[data-test="test-studio-configuration-overlay"]')
169
- .or(this.page.locator('[data-test="play-configuration-overlay"]'))
170
- .or(this.page.getByText('Setup environment'))
171
- .first();
159
+ // Test Studio's "Setup environment" is an inline accordion whose step 3
160
+ // ("Configure test case") holds ConfigureTestPanel and its Start button.
161
+ // The section can collapse again after completePlayConfiguration() returns
162
+ // (a cluster-change effect re-shows the overlay), in which case the Start
163
+ // trigger disappears. Re-open the "Configure test case" accordion heading
164
+ // before an attempt, but only when the panel is not already visible --
165
+ // clicking the heading while it is open re-shows the overlay and collapses
166
+ // the panel, so gating on the always-present "Setup environment" heading
167
+ // would defeat every retry.
172
168
  const configureTestCaseButton = this.page
173
169
  .getByTestId('configure-test-case-button')
174
170
  .or(this.page.getByTestId('play-configuration-configure-scenario-button'))
@@ -181,7 +177,10 @@ class PlayPage {
181
177
  visibilityTimeout: 30000,
182
178
  maxRetries: 5,
183
179
  preAction: async () => {
184
- if (await configurationOverlay.isVisible().catch(() => false)) {
180
+ const panelVisible = await this.configureTestPanel
181
+ .isVisible()
182
+ .catch(() => false);
183
+ if (!panelVisible) {
185
184
  await configureTestCaseButton.click({ timeout: 30000 });
186
185
  }
187
186
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1144",
3
+ "version": "0.0.1146",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",