@camunda/e2e-test-suite 0.0.959 → 0.0.961

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.
@@ -806,7 +806,10 @@ class ModelerCreatePage {
806
806
  await (0, test_1.expect)(this.changeElementSearchInput).toBeVisible({ timeout: 30000 });
807
807
  await this.changeElementSearchInput.click();
808
808
  await this.changeElementSearchInput.fill('');
809
- await this.changeElementSearchInput.pressSequentially('REST Outbound', {
809
+ // 'Send REST Request' is the template's current name -- connectors #7917
810
+ // renamed it from 'REST Outbound Connector' on 2026-07-15, and "Outbound"
811
+ // now appears in no searchable field, so the old filter matched nothing.
812
+ await this.changeElementSearchInput.pressSequentially('Send REST Request', {
810
813
  delay: 50,
811
814
  });
812
815
  await (0, test_1.expect)(this.restConnectorOption).toBeVisible({ timeout: 90000 });
@@ -215,10 +215,13 @@ class ModelerHomePage {
215
215
  }
216
216
  async clickHomeBreadcrumb() {
217
217
  try {
218
- await this.homeBreadcrumb.click();
218
+ await this.homeBreadcrumb.click({ timeout: 60000 });
219
219
  }
220
220
  catch (error) {
221
- await this.page.getByText('Home', { exact: true }).first().click();
221
+ await this.page
222
+ .getByText('Home', { exact: true })
223
+ .first()
224
+ .click({ timeout: 60000 });
222
225
  }
223
226
  }
224
227
  async clickChooseBpmnTemplateButton() {
@@ -100,9 +100,21 @@ class OperateHomePage {
100
100
  await this.page
101
101
  .getByLabel('Edit Variable "testVariable"')
102
102
  .getByText('"testValue"')
103
- .dblclick();
104
- await this.page.keyboard.press('Backspace');
105
- await this.page.keyboard.type(newValue);
103
+ .click();
104
+ // Replace the whole JSON document in one shot. Typing it per-character
105
+ // raced the editor's re-render: after a couple of keystrokes the caret
106
+ // jumped outside the closing quote, leaving invalid JSON such as
107
+ // `"up"datedValue`. Apply then rejects it silently, the modal stays open
108
+ // and the old value is still on screen, so the caller's
109
+ // `not.toBeVisible('"testValue"')` assertion times out. insertText emits a
110
+ // single input event, so there is no intermediate state to race.
111
+ //
112
+ // Pass only the OPENING quote: Monaco auto-closes it. Supplying both ends
113
+ // yields `"updatedValue""` -- invalid JSON, and Apply rejects it exactly
114
+ // like the per-character version did. Same recipe as
115
+ // pages/c8Run-8.10/OperateHomePage.ts.
116
+ await this.page.keyboard.press('ControlOrMeta+A');
117
+ await this.page.keyboard.insertText(`"${newValue}`);
106
118
  }
107
119
  async clickSaveVariableButton() {
108
120
  await this.applyButton.click();
@@ -223,6 +223,17 @@ class PlayPage {
223
223
  await this.scenarioDetailNameInput.press('Tab');
224
224
  }
225
225
  async clickViewAllScenariosButton() {
226
+ // This method's job is to reach the scenario LIST. Saving can already leave
227
+ // Play there (see assertSavedScenarioNameInPanel), and the "Back to test
228
+ // cases" control exists only inside a scenario's detail view -- so on the
229
+ // list it never renders and waiting for it just burns the retry budget.
230
+ // "Run all test cases" lives on the list and is what the caller needs next,
231
+ // so treat it as proof the destination is already reached.
232
+ if (await this.runAllScenariosButton
233
+ .isVisible({ timeout: 3000 })
234
+ .catch(() => false)) {
235
+ return;
236
+ }
226
237
  await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.viewAllScenariosButton);
227
238
  await this.viewAllScenariosButton.click();
228
239
  }
@@ -252,6 +263,20 @@ class PlayPage {
252
263
  if (await heading.isVisible({ timeout: 3000 }).catch(() => false)) {
253
264
  return;
254
265
  }
266
+ // Updating an existing test case does NOT always leave the detail view
267
+ // open: Play can close it and fall back to the "Test cases" list, which is
268
+ // what it did in run 32105225796 -- the screenshot shows the list with the
269
+ // updated name present while neither the heading nor the Name field
270
+ // existed, so the old two-surface check failed on a save that had actually
271
+ // succeeded (the "Scenario saved" toast had already been asserted). The row
272
+ // carrying the exact name is the same proof, on the surface Play chose.
273
+ const listRow = this.page
274
+ .locator('tr')
275
+ .filter({ has: this.page.getByText(scenarioName, { exact: true }) })
276
+ .first();
277
+ if (await listRow.isVisible({ timeout: 3000 }).catch(() => false)) {
278
+ return;
279
+ }
255
280
  await (0, test_1.expect)(this.scenarioDetailNameInput).toHaveValue(scenarioName, {
256
281
  timeout: 30000,
257
282
  });
@@ -198,8 +198,8 @@ async function modelRestConnector(modelerCreatePage, connectorSettingsPage, conn
198
198
  try {
199
199
  // The change-element popup virtualizes its list: connector templates render
200
200
  // below the built-in BPMN tasks and are not in the queryable DOM slice until
201
- // the list is filtered. Type "REST Outbound" into the popup search box so the
202
- // bundled REST Outbound Connector (compatible with the 8.10 engine set above)
201
+ // the list is filtered. Type the template name into the popup search box so
202
+ // the bundled REST template (compatible with the 8.10 engine set above)
203
203
  // renders and is selected directly. Without this filter the off-screen entry
204
204
  // is missed and the flow falls back to the marketplace unnecessarily,
205
205
  // exposing it to transient marketplace-API errors even though the connector
@@ -209,7 +209,7 @@ async function modelRestConnector(modelerCreatePage, connectorSettingsPage, conn
209
209
  });
210
210
  await modelerCreatePage.changeElementSearchInput.click();
211
211
  await modelerCreatePage.changeElementSearchInput.fill('');
212
- await modelerCreatePage.changeElementSearchInput.pressSequentially('REST Outbound', { delay: 50 });
212
+ await modelerCreatePage.changeElementSearchInput.pressSequentially('Send REST Request', { delay: 50 });
213
213
  await (0, test_1.expect)(modelerCreatePage.restConnectorOption).toBeVisible({
214
214
  timeout: 15000,
215
215
  });
@@ -13,6 +13,7 @@ declare class ConnectorMarketplacePage {
13
13
  clickCancelButton(): Promise<void>;
14
14
  clickReplaceResourceButton(): Promise<void>;
15
15
  downloadConnectorToProject(): Promise<void>;
16
+ private waitForImportToSettle;
16
17
  searchAndDownloadConnector(connectorName: string, maxRetries?: number): Promise<void>;
17
18
  }
18
19
  export { ConnectorMarketplacePage };
@@ -54,6 +54,7 @@ class ConnectorMarketplacePage {
54
54
  .then(() => true)
55
55
  .catch(() => false);
56
56
  if (!modalOpened) {
57
+ await this.waitForImportToSettle();
57
58
  return;
58
59
  }
59
60
  if (await this.addToProjectButton.isVisible()) {
@@ -62,6 +63,20 @@ class ConnectorMarketplacePage {
62
63
  else {
63
64
  await this.replaceResourceButton.click({ timeout: 20000 });
64
65
  }
66
+ await this.waitForImportToSettle(primaryButton.first());
67
+ }
68
+ // Hub writes the template into the project asynchronously after the primary
69
+ // button is clicked, and keeps the ImportModal mounted until that request
70
+ // resolves. Returning as soon as the click resolved let the caller's
71
+ // `page.reload()` tear the page down ~90ms later and abort the write, leaving
72
+ // the project's connector-template list empty.
73
+ async waitForImportToSettle(modalButton) {
74
+ if (modalButton) {
75
+ await modalButton
76
+ .waitFor({ state: 'hidden', timeout: 60000 })
77
+ .catch(() => { });
78
+ }
79
+ await this.page.waitForLoadState('networkidle').catch(() => { });
65
80
  }
66
81
  // The marketplace search backend can transiently return HTTP 504
67
82
  // ("upstream request timeout"), which leaves the modal in an error or
@@ -191,6 +191,7 @@ declare class ModelerCreatePage {
191
191
  fillZeebeRestValue(zeebeUrl: string): Promise<void>;
192
192
  embedForm(formName: string): Promise<void>;
193
193
  clickFirstPlaceRESTConnector(): Promise<void>;
194
+ isConnectorTemplateApplied(timeout?: number): Promise<boolean>;
194
195
  setOAuthTokenEndpoint(elementToClick: Locator, endpoint: string, options?: {
195
196
  retries?: number;
196
197
  settleMs?: number;
@@ -1064,6 +1064,17 @@ class ModelerCreatePage {
1064
1064
  async clickFirstPlaceRESTConnector() {
1065
1065
  await this.firstPlaceRESTConnector.click({ timeout: 60000 });
1066
1066
  }
1067
+ // The Authentication group is contributed by the REST connector element
1068
+ // template, so it exists only while that template resolves for the selected
1069
+ // element. When the marketplace import never reached the project the panel
1070
+ // renders `Template: Not found` instead and no amount of waiting produces
1071
+ // the group.
1072
+ async isConnectorTemplateApplied(timeout = 30000) {
1073
+ return this.authenticationPanel
1074
+ .waitFor({ state: 'visible', timeout })
1075
+ .then(() => true)
1076
+ .catch(() => false);
1077
+ }
1067
1078
  async setOAuthTokenEndpoint(elementToClick, endpoint, options) {
1068
1079
  const retries = options?.retries ?? 2;
1069
1080
  const settleMs = options?.settleMs ?? 250;
@@ -206,11 +206,18 @@ class ModelerHomePage {
206
206
  // restarts. Wait for the app shell before checking for the dropdown, and
207
207
  // reload-then-wait on each retry so a 503 is ridden out rather than
208
208
  // reasserted against the error page.
209
+ // `expectLocatorWithRetry` re-checks its elapsed budget before every
210
+ // attempt, so the 60s default `totalTimeout` was spent inside a single
211
+ // `waitForModelerReady` recovery and the helper gave up "after 1 attempts"
212
+ // -- the reload-and-wait retry never actually ran. Bound the recovery wait
213
+ // and widen the budget so all three attempts fit.
209
214
  await this.waitForModelerReady();
210
215
  await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.diagramTypeDropdown, {
216
+ visibilityTimeout: 15000,
217
+ totalTimeout: 180000,
211
218
  postAction: async () => {
212
219
  await this.page.reload();
213
- await this.waitForModelerReady();
220
+ await this.waitForModelerReady(45000);
214
221
  },
215
222
  });
216
223
  await this.diagramTypeDropdown.click();
@@ -428,6 +428,32 @@ async function expectTextWithPagination(page, text, shouldExist = true, timeout
428
428
  }
429
429
  }
430
430
  exports.expectTextWithPagination = expectTextWithPagination;
431
+ // SM Web Modeler ships no bundled marketplace connectors, so the REST connector
432
+ // template has to be imported from the marketplace into the project before any
433
+ // of the OAuth steps below can find the template-provided Authentication group.
434
+ // The import is confirmed against the diagram itself and re-driven when it did
435
+ // not land, so a dropped import fails here with its own cause instead of five
436
+ // 60s waits on a panel that can never render.
437
+ async function importRestConnectorTemplate(modelerCreatePage, connectorMarketplacePage, page) {
438
+ const maxAttempts = 2;
439
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
440
+ await modelerCreatePage.clickFirstPlaceRESTConnector();
441
+ await modelerCreatePage.clickChangeTypeButton();
442
+ await modelerCreatePage.clickMarketPlaceButton();
443
+ await connectorMarketplacePage.searchAndDownloadConnector('REST Connector');
444
+ await page.reload();
445
+ await page.waitForLoadState('networkidle');
446
+ await modelerCreatePage.clickFirstPlaceRESTConnector();
447
+ if (await modelerCreatePage.isConnectorTemplateApplied()) {
448
+ return;
449
+ }
450
+ console.warn(`REST connector template did not resolve on the diagram after import ` +
451
+ `attempt ${attempt}/${maxAttempts}; re-importing from the marketplace.`);
452
+ }
453
+ throw new Error(`REST connector template was not imported into the project after ` +
454
+ `${maxAttempts} marketplace attempts: the element still renders ` +
455
+ `"Template: Not found", so its Authentication group never exists.`);
456
+ }
431
457
  async function modelAndRunConnectorsDocHandlingDiagram(modelerCreatePage, modelerHomePage, processName, page, connectorMarketplacePage, zeebeUrl, zeebeClientId, zeebeClientSecret, endpoint, tenant = '') {
432
458
  await modelerHomePage.clickCrossComponentProjectFolder();
433
459
  await modelerHomePage.clickDiagramTypeDropdown();
@@ -443,12 +469,7 @@ async function modelAndRunConnectorsDocHandlingDiagram(modelerCreatePage, modele
443
469
  await modelerCreatePage.clickIdInput();
444
470
  await modelerCreatePage.fillIdInput(processName);
445
471
  await (0, sleep_1.sleep)(10000);
446
- await modelerCreatePage.clickFirstPlaceRESTConnector();
447
- await modelerCreatePage.clickChangeTypeButton();
448
- await modelerCreatePage.clickMarketPlaceButton();
449
- await connectorMarketplacePage.searchAndDownloadConnector('REST Connector');
450
- await page.reload();
451
- await page.waitForLoadState('networkidle');
472
+ await importRestConnectorTemplate(modelerCreatePage, connectorMarketplacePage, page);
452
473
  await modelerCreatePage.fillStartEventVariablesForDocHandling(zeebeUrl, zeebeClientId, zeebeClientSecret);
453
474
  await modelerCreatePage.setOAuthTokenEndpoint(page.locator('.djs-hit').first(), endpoint);
454
475
  await (0, sleep_1.sleep)(2000);
@@ -44,8 +44,7 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
44
44
  });
45
45
  });
46
46
  });
47
- // Skipped due to bug #8162: https://github.com/camunda/connectors/issues/8162
48
- SM_8_10_1.test.skip('REST Connector Bearer Token Auth User Flow', async ({ page, operateHomePage, modelerHomePage, modelerCreatePage, connectorSettingsPage, navigationPage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, }) => {
47
+ (0, SM_8_10_1.test)('REST Connector Bearer Token Auth User Flow', async ({ page, operateHomePage, modelerHomePage, modelerCreatePage, connectorSettingsPage, navigationPage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, }) => {
49
48
  SM_8_10_1.test.slow();
50
49
  const processName = 'REST_Connector_Bearer_Auth_Process' +
51
50
  (await (0, _setup_1.generateRandomStringAsync)(3));
@@ -116,8 +116,7 @@ if (process.env.IS_DS === 'true') {
116
116
  await operateProcessInstancePage.assertProcessVariableContainsText('Upload_Files', 'aws');
117
117
  });
118
118
  });
119
- // Skipped due to bug #8162: https://github.com/camunda/connectors/issues/8162
120
- SM_8_10_1.test.skip('Document Handling Connectors User Flow - AWS @tasklistV2', async ({ page, navigationPage, modelerHomePage, modelerCreatePage, operateHomePage, operateProcessesPage, connectorMarketplacePage, operateProcessInstancePage, ocIdentityHomePage, ocIdentityRolesPage, }) => {
119
+ (0, SM_8_10_1.test)('Document Handling Connectors User Flow - AWS @tasklistV2', async ({ page, navigationPage, modelerHomePage, modelerCreatePage, operateHomePage, operateProcessesPage, connectorMarketplacePage, operateProcessInstancePage, ocIdentityHomePage, ocIdentityRolesPage, }) => {
121
120
  const processName = 'Document_Handling_Connectors_User_Flow_AWS_Process' +
122
121
  (await (0, _setup_1.generateRandomStringAsync)(3));
123
122
  const baseURL = process.env.PLAYWRIGHT_BASE_URL ||
@@ -127,8 +127,7 @@ if (process.env.IS_MT === 'true') {
127
127
  }
128
128
  });
129
129
  });
130
- // Skipped due to bug #8162: https://github.com/camunda/connectors/issues/8162
131
- SM_8_10_1.test.skip('Main User Can Create & Access Tenant - Connectors Flow @tasklistV2', async ({ page, modelerHomePage, modelerCreatePage, operateProcessInstancePage, operateProcessesPage, operateHomePage, navigationPage, managementIdentityTenantPage, connectorSettingsPage, connectorMarketplacePage, optimizeHomePage, optimizeDashboardPage, ocIdentityHomePage, ocTenantPage, }) => {
130
+ (0, SM_8_10_1.test)('Main User Can Create & Access Tenant - Connectors Flow @tasklistV2', async ({ page, modelerHomePage, modelerCreatePage, operateProcessInstancePage, operateProcessesPage, operateHomePage, navigationPage, managementIdentityTenantPage, connectorSettingsPage, connectorMarketplacePage, optimizeHomePage, optimizeDashboardPage, ocIdentityHomePage, ocTenantPage, }) => {
132
131
  SM_8_10_1.test.slow();
133
132
  const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
134
133
  const processName = 'Main_User_Connectors_Flow_' + randomString;
@@ -260,8 +259,7 @@ if (process.env.IS_MT === 'true') {
260
259
  });
261
260
  }
262
261
  });
263
- // Skipped due to bug #8162: https://github.com/camunda/connectors/issues/8162
264
- SM_8_10_1.test.skip('Second User Can Access Tenant Created By Main User - Connectors Flow @tasklistV2', async ({ page, modelerHomePage, modelerCreatePage, operateProcessInstancePage, operateProcessesPage, operateHomePage, navigationPage, managementIdentityTenantPage, connectorSettingsPage, connectorMarketplacePage, optimizeHomePage, optimizeDashboardPage, ocIdentityHomePage, ocTenantPage, managementIdentityPage, keycloakAdminPage, keycloakLoginPage, ocIdentityRolesPage, ocIdentityMappingRulesPage, browser, }) => {
262
+ (0, SM_8_10_1.test)('Second User Can Access Tenant Created By Main User - Connectors Flow @tasklistV2', async ({ page, modelerHomePage, modelerCreatePage, operateProcessInstancePage, operateProcessesPage, operateHomePage, navigationPage, managementIdentityTenantPage, connectorSettingsPage, connectorMarketplacePage, optimizeHomePage, optimizeDashboardPage, ocIdentityHomePage, ocTenantPage, managementIdentityPage, keycloakAdminPage, keycloakLoginPage, ocIdentityRolesPage, ocIdentityMappingRulesPage, browser, }) => {
265
263
  SM_8_10_1.test.slow();
266
264
  const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
267
265
  const processName = 'Second_User_Connectors_Flow_' + randomString;
@@ -390,8 +388,7 @@ if (process.env.IS_MT === 'true') {
390
388
  });
391
389
  }
392
390
  });
393
- // Skipped due to bug #8162: https://github.com/camunda/connectors/issues/8162
394
- SM_8_10_1.test.skip('User Can Be Assigned To Multiple Tenants @tasklistV2', async ({ page, modelerHomePage, modelerCreatePage, operateProcessInstancePage, operateProcessesPage, operateHomePage, navigationPage, managementIdentityTenantPage, connectorSettingsPage, connectorMarketplacePage, ocIdentityHomePage, ocTenantPage, managementIdentityPage, }) => {
391
+ (0, SM_8_10_1.test)('User Can Be Assigned To Multiple Tenants @tasklistV2', async ({ page, modelerHomePage, modelerCreatePage, operateProcessInstancePage, operateProcessesPage, operateHomePage, navigationPage, managementIdentityTenantPage, connectorSettingsPage, connectorMarketplacePage, ocIdentityHomePage, ocTenantPage, managementIdentityPage, }) => {
395
392
  SM_8_10_1.test.slow();
396
393
  const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
397
394
  const processName1 = 'Multiple_Tenant_Flow_1' + randomString;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.959",
3
+ "version": "0.0.961",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",