@camunda/e2e-test-suite 0.0.1443 → 0.0.1444

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.
Files changed (122) hide show
  1. package/.github/c8_versions.json +1 -0
  2. package/README.md +2 -0
  3. package/dist/fixtures/SM-8.11.d.ts +77 -0
  4. package/dist/fixtures/SM-8.11.js +176 -0
  5. package/dist/pages/SM-8.11/Authorization.d.ts +39 -0
  6. package/dist/pages/SM-8.11/Authorization.js +349 -0
  7. package/dist/pages/SM-8.11/ClusterDetailsPage.d.ts +8 -0
  8. package/dist/pages/SM-8.11/ClusterDetailsPage.js +65 -0
  9. package/dist/pages/SM-8.11/ClusterPage.d.ts +11 -0
  10. package/dist/pages/SM-8.11/ClusterPage.js +37 -0
  11. package/dist/pages/SM-8.11/ConnectorMarketplacePage.d.ts +27 -0
  12. package/dist/pages/SM-8.11/ConnectorMarketplacePage.js +187 -0
  13. package/dist/pages/SM-8.11/ConnectorSettingsPage.d.ts +41 -0
  14. package/dist/pages/SM-8.11/ConnectorSettingsPage.js +153 -0
  15. package/dist/pages/SM-8.11/ConnectorTemplatePage.d.ts +11 -0
  16. package/dist/pages/SM-8.11/ConnectorTemplatePage.js +34 -0
  17. package/dist/pages/SM-8.11/FormJsPage.d.ts +33 -0
  18. package/dist/pages/SM-8.11/FormJsPage.js +109 -0
  19. package/dist/pages/SM-8.11/HomePage.d.ts +20 -0
  20. package/dist/pages/SM-8.11/HomePage.js +49 -0
  21. package/dist/pages/SM-8.11/IdentityTenantPage.d.ts +53 -0
  22. package/dist/pages/SM-8.11/IdentityTenantPage.js +264 -0
  23. package/dist/pages/SM-8.11/IdentityUsersPage.d.ts +92 -0
  24. package/dist/pages/SM-8.11/IdentityUsersPage.js +485 -0
  25. package/dist/pages/SM-8.11/KeycloakAdminPage.d.ts +17 -0
  26. package/dist/pages/SM-8.11/KeycloakAdminPage.js +78 -0
  27. package/dist/pages/SM-8.11/KeycloakLoginPage.d.ts +12 -0
  28. package/dist/pages/SM-8.11/KeycloakLoginPage.js +32 -0
  29. package/dist/pages/SM-8.11/KeycloakUtils.d.ts +17 -0
  30. package/dist/pages/SM-8.11/KeycloakUtils.js +94 -0
  31. package/dist/pages/SM-8.11/LoginPage.d.ts +21 -0
  32. package/dist/pages/SM-8.11/LoginPage.js +112 -0
  33. package/dist/pages/SM-8.11/ManagementIdentityPage.d.ts +44 -0
  34. package/dist/pages/SM-8.11/ManagementIdentityPage.js +176 -0
  35. package/dist/pages/SM-8.11/ModelerCreatePage.d.ts +238 -0
  36. package/dist/pages/SM-8.11/ModelerCreatePage.js +1950 -0
  37. package/dist/pages/SM-8.11/ModelerHomePage.d.ts +97 -0
  38. package/dist/pages/SM-8.11/ModelerHomePage.js +956 -0
  39. package/dist/pages/SM-8.11/NavigationPage.d.ts +58 -0
  40. package/dist/pages/SM-8.11/NavigationPage.js +389 -0
  41. package/dist/pages/SM-8.11/OCIdentityAuthorizationsPage.d.ts +10 -0
  42. package/dist/pages/SM-8.11/OCIdentityAuthorizationsPage.js +22 -0
  43. package/dist/pages/SM-8.11/OCIdentityClusterVariablesPage.d.ts +22 -0
  44. package/dist/pages/SM-8.11/OCIdentityClusterVariablesPage.js +120 -0
  45. package/dist/pages/SM-8.11/OCIdentityGroupsPage.d.ts +39 -0
  46. package/dist/pages/SM-8.11/OCIdentityGroupsPage.js +154 -0
  47. package/dist/pages/SM-8.11/OCIdentityHomePage.d.ts +23 -0
  48. package/dist/pages/SM-8.11/OCIdentityHomePage.js +115 -0
  49. package/dist/pages/SM-8.11/OCIdentityMappingRulesPage.d.ts +23 -0
  50. package/dist/pages/SM-8.11/OCIdentityMappingRulesPage.js +116 -0
  51. package/dist/pages/SM-8.11/OCIdentityRolesPage.d.ts +61 -0
  52. package/dist/pages/SM-8.11/OCIdentityRolesPage.js +433 -0
  53. package/dist/pages/SM-8.11/OCTenantPage.d.ts +73 -0
  54. package/dist/pages/SM-8.11/OCTenantPage.js +399 -0
  55. package/dist/pages/SM-8.11/OperateHomePage.d.ts +26 -0
  56. package/dist/pages/SM-8.11/OperateHomePage.js +139 -0
  57. package/dist/pages/SM-8.11/OperateProcessInstancePage.d.ts +30 -0
  58. package/dist/pages/SM-8.11/OperateProcessInstancePage.js +276 -0
  59. package/dist/pages/SM-8.11/OperateProcessesPage.d.ts +38 -0
  60. package/dist/pages/SM-8.11/OperateProcessesPage.js +383 -0
  61. package/dist/pages/SM-8.11/OptimizeCollectionsPage.d.ts +17 -0
  62. package/dist/pages/SM-8.11/OptimizeCollectionsPage.js +62 -0
  63. package/dist/pages/SM-8.11/OptimizeDashboardPage.d.ts +14 -0
  64. package/dist/pages/SM-8.11/OptimizeDashboardPage.js +63 -0
  65. package/dist/pages/SM-8.11/OptimizeHomePage.d.ts +19 -0
  66. package/dist/pages/SM-8.11/OptimizeHomePage.js +76 -0
  67. package/dist/pages/SM-8.11/OptimizeReportPage.d.ts +50 -0
  68. package/dist/pages/SM-8.11/OptimizeReportPage.js +209 -0
  69. package/dist/pages/SM-8.11/PlayPage.d.ts +47 -0
  70. package/dist/pages/SM-8.11/PlayPage.js +389 -0
  71. package/dist/pages/SM-8.11/ProcessApplicationPage.d.ts +35 -0
  72. package/dist/pages/SM-8.11/ProcessApplicationPage.js +340 -0
  73. package/dist/pages/SM-8.11/SettingsPage.d.ts +12 -0
  74. package/dist/pages/SM-8.11/SettingsPage.js +34 -0
  75. package/dist/pages/SM-8.11/TaskDetailsPage.d.ts +70 -0
  76. package/dist/pages/SM-8.11/TaskDetailsPage.js +273 -0
  77. package/dist/pages/SM-8.11/TaskPanelPage.d.ts +29 -0
  78. package/dist/pages/SM-8.11/TaskPanelPage.js +320 -0
  79. package/dist/pages/SM-8.11/TaskProcessesPage.d.ts +15 -0
  80. package/dist/pages/SM-8.11/TaskProcessesPage.js +77 -0
  81. package/dist/pages/SM-8.11/UtilitiesPage.d.ts +38 -0
  82. package/dist/pages/SM-8.11/UtilitiesPage.js +573 -0
  83. package/dist/pages/SM-8.11/optimizeReportUtils.d.ts +6 -0
  84. package/dist/pages/SM-8.11/optimizeReportUtils.js +77 -0
  85. package/dist/tests/SM-8.11/cluster-management-user-flows.spec.d.ts +1 -0
  86. package/dist/tests/SM-8.11/cluster-management-user-flows.spec.js +48 -0
  87. package/dist/tests/SM-8.11/cluster-variables.spec.d.ts +1 -0
  88. package/dist/tests/SM-8.11/cluster-variables.spec.js +226 -0
  89. package/dist/tests/SM-8.11/connectors-user-flows.spec.d.ts +1 -0
  90. package/dist/tests/SM-8.11/connectors-user-flows.spec.js +307 -0
  91. package/dist/tests/SM-8.11/document-handling-user-flows.spec.d.ts +1 -0
  92. package/dist/tests/SM-8.11/document-handling-user-flows.spec.js +174 -0
  93. package/dist/tests/SM-8.11/hto-user-flows.spec.d.ts +1 -0
  94. package/dist/tests/SM-8.11/hto-user-flows.spec.js +410 -0
  95. package/dist/tests/SM-8.11/hub-web-modeler-smoke.spec.d.ts +1 -0
  96. package/dist/tests/SM-8.11/hub-web-modeler-smoke.spec.js +24 -0
  97. package/dist/tests/SM-8.11/identity-user-flows.spec.d.ts +1 -0
  98. package/dist/tests/SM-8.11/identity-user-flows.spec.js +220 -0
  99. package/dist/tests/SM-8.11/license-key-user-flows.spec.d.ts +1 -0
  100. package/dist/tests/SM-8.11/license-key-user-flows.spec.js +461 -0
  101. package/dist/tests/SM-8.11/login.spec.d.ts +1 -0
  102. package/dist/tests/SM-8.11/login.spec.js +24 -0
  103. package/dist/tests/SM-8.11/migration-path-user-flows.spec.d.ts +1 -0
  104. package/dist/tests/SM-8.11/migration-path-user-flows.spec.js +263 -0
  105. package/dist/tests/SM-8.11/mt-enabled-user-flows.spec.d.ts +1 -0
  106. package/dist/tests/SM-8.11/mt-enabled-user-flows.spec.js +607 -0
  107. package/dist/tests/SM-8.11/optimize-user-flows.spec.d.ts +1 -0
  108. package/dist/tests/SM-8.11/optimize-user-flows.spec.js +505 -0
  109. package/dist/tests/SM-8.11/play.spec.d.ts +1 -0
  110. package/dist/tests/SM-8.11/play.spec.js +144 -0
  111. package/dist/tests/SM-8.11/rba-enabled-user-flows.spec.d.ts +1 -0
  112. package/dist/tests/SM-8.11/rba-enabled-user-flows.spec.js +712 -0
  113. package/dist/tests/SM-8.11/smoke-tests.spec.d.ts +1 -0
  114. package/dist/tests/SM-8.11/smoke-tests.spec.js +167 -0
  115. package/dist/tests/SM-8.11/test-setup.spec.d.ts +1 -0
  116. package/dist/tests/SM-8.11/test-setup.spec.js +24 -0
  117. package/dist/tests/SM-8.11/topology-orchestration-smoke.spec.d.ts +1 -0
  118. package/dist/tests/SM-8.11/topology-orchestration-smoke.spec.js +58 -0
  119. package/dist/tests/SM-8.11/web-modeler-user-flows.spec.d.ts +1 -0
  120. package/dist/tests/SM-8.11/web-modeler-user-flows.spec.js +223 -0
  121. package/package.json +1 -1
  122. package/playwright.config.ts +21 -0
@@ -0,0 +1,573 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.modelAndRunConnectorsDocHandlingDiagram = exports.expectTextWithPagination = exports.modelDiagramFromFile = exports.findTextWithPagination = exports.modelAndRunConnectorsTimerEventDiagram = exports.assertPageTextWithRetry = exports.assertLocatorVisibleWithRetry = exports.assertLocatorVisibleWithPaginated = exports.modelRestConnector = exports.completeTaskWithRetry = exports.createAndRunProcess = exports.assignMappingToRole = exports.createUserAndAssignToRole = exports.runMultipleProcesses = exports.deleteAllUserGroups = void 0;
4
+ const sleep_1 = require("../../utils/sleep");
5
+ const test_1 = require("@playwright/test");
6
+ const fileUpload_1 = require("../../utils/fileUpload");
7
+ const findLocatorInPaginatedList_1 = require("../../utils/findLocatorInPaginatedList");
8
+ const KeycloakUtils_1 = require("../SM-8.11/KeycloakUtils");
9
+ const expectLocatorWithPagination_1 = require("../../utils/assertionHelpers/expectLocatorWithPagination");
10
+ // This step will be skipped until new Identity expected flow is confirmed
11
+ async function deleteAllUserGroups() {
12
+ // await navigationPage.goToOCAdmin();
13
+ // await identityPage.clickGroupsTab();
14
+ // await identityPage.deleteAllGroups();
15
+ }
16
+ exports.deleteAllUserGroups = deleteAllUserGroups;
17
+ async function runMultipleProcesses(page, modelerHomePage, modelerCreatePage, numberOfProcesses, processName, processId = '', tenant = '') {
18
+ for (let i = 1; i <= numberOfProcesses; i++) {
19
+ await createAndRunProcess(page, modelerHomePage, modelerCreatePage, processName + i, processId.length > 0 ? processId + i : processId, tenant);
20
+ }
21
+ }
22
+ exports.runMultipleProcesses = runMultipleProcesses;
23
+ async function createUserAndAssignToRole(page, navigationPage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, ocIdentityHomePage, identityMappingRulesPage, identityRolesPage, username, password, role = 'admin', testMappings) {
24
+ const mappingRuleId = `${username}-user-mapping`;
25
+ const claimName = 'preferred_username';
26
+ await (0, KeycloakUtils_1.createUser)(navigationPage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, username, password);
27
+ await navigationPage.goToOCAdmin();
28
+ await ocIdentityHomePage.clickMappingRulesTab();
29
+ await identityMappingRulesPage.createMappingRule(mappingRuleId, mappingRuleId, claimName, username);
30
+ await (0, expectLocatorWithPagination_1.expectLocatorWithPagination)(page, identityMappingRulesPage.mappingRuleRow(mappingRuleId).first());
31
+ if (testMappings && mappingRuleId.toLowerCase() != 'demo-user-mapping') {
32
+ testMappings.mappingIds.push(mappingRuleId);
33
+ }
34
+ await assignMappingToRole(page, ocIdentityHomePage, identityRolesPage, role, mappingRuleId, testMappings);
35
+ await (0, expectLocatorWithPagination_1.expectLocatorWithPagination)(page, identityMappingRulesPage
36
+ .mappingRuleRow(mappingRuleId)
37
+ .filter({
38
+ hasText: `${mappingRuleId}${mappingRuleId}${claimName}${username}`,
39
+ })
40
+ .first());
41
+ }
42
+ exports.createUserAndAssignToRole = createUserAndAssignToRole;
43
+ async function assignMappingToRole(page, ocIdentityHomePage, ocIdentityRolesPage, role, mappingRuleId, testMappings) {
44
+ await ocIdentityHomePage.clickRolesTab();
45
+ try {
46
+ await (0, test_1.expect)(ocIdentityRolesPage.roleCell(role).first()).toBeVisible({
47
+ timeout: 20000,
48
+ });
49
+ }
50
+ catch (error) {
51
+ await ocIdentityRolesPage.createRole({ id: role, name: role });
52
+ if (testMappings && role.toLowerCase() != 'admin') {
53
+ testMappings.roleIds.push(role);
54
+ }
55
+ }
56
+ await ocIdentityRolesPage.assignMappingRuleToRole(role, mappingRuleId);
57
+ await assertLocatorVisibleWithPaginated(page, ocIdentityRolesPage.mappingRuleRow(mappingRuleId).first(), `${mappingRuleId} Mapping Rule`);
58
+ }
59
+ exports.assignMappingToRole = assignMappingToRole;
60
+ async function createAndRunProcess(page, modelerHomePage, modelerCreatePage, processName, processId = '', tenant = '') {
61
+ await modelerHomePage.clickDiagramTypeDropdown();
62
+ await modelerHomePage.clickBpmnTemplateOption();
63
+ await modelerCreatePage.modelCamundaUserTaskDiagram(processName, processId);
64
+ await modelerCreatePage.runProcessInstance('', tenant);
65
+ await modelerHomePage.clickProjectBreadcrumb();
66
+ }
67
+ exports.createAndRunProcess = createAndRunProcess;
68
+ async function completeTaskWithRetry(page, taskPanelPage, taskDetailsPage, taskName, taskPriority, maxRetries = 7) {
69
+ // Dismiss any lingering "Task completed" toast from a previous completion
70
+ // to avoid strict mode violations and stale UI state
71
+ try {
72
+ const toastCloseButton = page
73
+ .locator('.cds--toast-notification')
74
+ .getByRole('button', { name: /close/i })
75
+ .first();
76
+ if (await toastCloseButton.isVisible({ timeout: 2000 })) {
77
+ await toastCloseButton.click();
78
+ }
79
+ }
80
+ catch {
81
+ // No toast to dismiss, continue
82
+ }
83
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
84
+ try {
85
+ // Tasklist keeps polling for task updates, so 'networkidle' never
86
+ // settles here. This wait carried no timeout, so it consumed whatever
87
+ // was left of the 12-minute test budget and the run died inside
88
+ // waitForLoadState. The task panel rendering is the precondition this
89
+ // step actually needs, so wait for that instead.
90
+ await (0, test_1.expect)(taskPanelPage.availableTasks).toBeVisible({ timeout: 60000 });
91
+ const taskLocator = taskPanelPage.availableTasks
92
+ .getByText(taskName, { exact: true })
93
+ .first();
94
+ try {
95
+ await taskLocator.waitFor({ state: 'visible', timeout: 10000 });
96
+ }
97
+ catch {
98
+ throw new Error(`Task ${taskName} not found in available tasks`);
99
+ }
100
+ // Click the task directly instead of using openTask's 30-retry loop
101
+ // (this outer loop already provides retry logic)
102
+ await taskLocator.click({ timeout: 10000 });
103
+ await (0, test_1.expect)(taskDetailsPage.detailsPanel).toBeVisible({ timeout: 30000 });
104
+ // Verify the correct task is loaded by checking the task name appears
105
+ // in the details-info section (the task name heading is outside the
106
+ // complementary panel, so we use detailsInfo instead of detailsPanel)
107
+ await (0, test_1.expect)(taskDetailsPage.detailsInfo.getByText(taskName)).toBeVisible({ timeout: 30000 });
108
+ if (!(await taskDetailsPage.assignedToMeText.isVisible({ timeout: 5000 }))) {
109
+ await taskDetailsPage.clickAssignToMeButton();
110
+ }
111
+ await (0, test_1.expect)(taskDetailsPage.detailsPanel.getByText(taskPriority)).toBeVisible({ timeout: 30000 });
112
+ await taskDetailsPage.completeTaskButton.click({ timeout: 30000 });
113
+ await (0, test_1.expect)(taskDetailsPage.taskCompletedBanner).toBeVisible({
114
+ timeout: 30000,
115
+ });
116
+ await (0, test_1.expect)(taskPanelPage.availableTasks.getByText(taskName, { exact: true }).first()).not.toBeVisible({ timeout: 15000 });
117
+ console.log(`Successfully completed task: ${taskName}`);
118
+ return;
119
+ }
120
+ catch (error) {
121
+ console.warn(`Attempt ${attempt + 1} failed for completing task ${taskName}:`, error instanceof Error ? error.message : error);
122
+ if (attempt < maxRetries - 1) {
123
+ // Dismiss any toast before reloading
124
+ try {
125
+ const toastCloseButton = page
126
+ .locator('.cds--toast-notification')
127
+ .getByRole('button', { name: /close/i })
128
+ .first();
129
+ if (await toastCloseButton.isVisible({ timeout: 1000 })) {
130
+ await toastCloseButton.click();
131
+ }
132
+ }
133
+ catch {
134
+ // No toast to dismiss
135
+ }
136
+ // A transient backend 500 while opening the task can leave the page on
137
+ // the raw Tasklist API URL (the JSON error renders as the top-level
138
+ // document). A bare reload then re-requests that broken URL and never
139
+ // restores the SPA, so every remaining attempt is wasted. Re-navigate
140
+ // to the Tasklist list — which uses a different endpoint than the
141
+ // single-task fetch that 500s — so the app re-mounts and the task can
142
+ // be re-opened once the blip clears. Progressive backoff gives the
143
+ // backend time to recover between attempts.
144
+ await (0, sleep_1.sleep)(2000 * (attempt + 1));
145
+ const orchestrationContextPath = process.env.ORCHESTRATION_CONTEXT_PATH || '/orchestration';
146
+ const normalizedOrchestrationPath = orchestrationContextPath.startsWith('/')
147
+ ? orchestrationContextPath
148
+ : `/${orchestrationContextPath}`;
149
+ try {
150
+ await page.goto(`${normalizedOrchestrationPath}/tasklist`, {
151
+ timeout: 60000,
152
+ waitUntil: 'domcontentloaded',
153
+ });
154
+ }
155
+ catch {
156
+ await page.reload();
157
+ }
158
+ // No settle wait here either — the goto already waited for
159
+ // domcontentloaded and the next attempt waits for the task panel.
160
+ }
161
+ else {
162
+ console.error(`All ${maxRetries} attempts failed for task ${taskName}`);
163
+ throw new Error(`Completion of task ${taskName} failed after ${maxRetries} attempts`);
164
+ }
165
+ }
166
+ }
167
+ }
168
+ exports.completeTaskWithRetry = completeTaskWithRetry;
169
+ async function modelRestConnector(modelerCreatePage, connectorSettingsPage, connectorMarketplacePage, processName, url, auth, resultExpression, { resultVariable = '', basicAuthCredentials = { username: '', password: '' }, recoverSession, } = {}) {
170
+ await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({
171
+ timeout: 120000,
172
+ });
173
+ await modelerCreatePage.enterDiagramName(processName);
174
+ await (0, sleep_1.sleep)(1000);
175
+ await modelerCreatePage.clickCanvas();
176
+ await modelerCreatePage.clickGeneralPropertiesPanel();
177
+ await modelerCreatePage.clickIdInput();
178
+ await modelerCreatePage.fillIdInput(processName);
179
+ await modelerCreatePage.assertNameInput(processName);
180
+ await (0, sleep_1.sleep)(1000);
181
+ await modelerCreatePage.clickStartEventElement();
182
+ try {
183
+ await (0, test_1.expect)(modelerCreatePage.appendElementButton).toBeVisible({
184
+ timeout: 1000,
185
+ });
186
+ }
187
+ catch {
188
+ await modelerCreatePage.clickStartEventElement();
189
+ }
190
+ await modelerCreatePage.clickAppendElementButton();
191
+ await modelerCreatePage.clickAppendTaskButton();
192
+ // The REST connector template requires engines.camunda ^8.10 (since connector v15).
193
+ // New diagrams default to "Check problems against: Camunda 8.9", which moves the
194
+ // connector into the "Requires newer Camunda version" section where clicking it
195
+ // has no effect. Set the diagram version to 8.10 before opening the picker.
196
+ await modelerCreatePage.setEngineVersion('8.10');
197
+ await modelerCreatePage.clickChangeTypeButton();
198
+ try {
199
+ // The change-element popup virtualizes its list: connector templates render
200
+ // below the built-in BPMN tasks and are not in the queryable DOM slice until
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
+ // renders and is selected directly. Without this filter the off-screen entry
204
+ // is missed and the flow falls back to the marketplace unnecessarily,
205
+ // exposing it to transient marketplace-API errors even though the connector
206
+ // is already bundled in the modeler.
207
+ await (0, test_1.expect)(modelerCreatePage.changeElementSearchInput).toBeVisible({
208
+ timeout: 30000,
209
+ });
210
+ // Connector templates are listed under the popup's "Reusable assets" tab;
211
+ // revealChangeElementTemplate selects it before falling back to search.
212
+ const revealed = await modelerCreatePage.revealChangeElementTemplate(modelerCreatePage.restConnectorOption, 'Send REST Request');
213
+ if (!revealed) {
214
+ throw new Error('Bundled REST connector template not listed');
215
+ }
216
+ }
217
+ catch (error) {
218
+ await modelerCreatePage.clickMarketPlaceButton();
219
+ await connectorMarketplacePage.clickSearchForConnectorTextbox();
220
+ await connectorMarketplacePage.fillSearchForConnectorTextbox('REST Connector');
221
+ await connectorMarketplacePage.waitForConnectorSearchResults();
222
+ await connectorMarketplacePage.downloadConnectorToProject();
223
+ // Marketplace modal closes the change-type dropdown. The task may remain in
224
+ // a selected state (class includes "djs-selected") which breaks the exact
225
+ // class-attribute match used by secondElement. Click the canvas background
226
+ // first to deselect, then re-select the task and reopen the dropdown.
227
+ await modelerCreatePage.clickCanvas();
228
+ await modelerCreatePage.secondElement.click({ timeout: 30000 });
229
+ await modelerCreatePage.clickChangeTypeButton();
230
+ }
231
+ await modelerCreatePage.clickRestConnectorOption(recoverSession);
232
+ // Guard: wait for the connector settings panel to render before proceeding.
233
+ // On slow clusters the properties panel can take several seconds to update
234
+ // after the change-type click; if it doesn't appear, re-select the element
235
+ // and try once more before letting the tab click time out.
236
+ try {
237
+ await (0, test_1.expect)(connectorSettingsPage.authenticationTab).toBeVisible({
238
+ timeout: 30000,
239
+ });
240
+ }
241
+ catch {
242
+ await modelerCreatePage.secondElement
243
+ .click({ timeout: 30000 })
244
+ .catch(() => { });
245
+ await modelerCreatePage.clickChangeTypeButton();
246
+ await modelerCreatePage.clickRestConnectorOption(recoverSession);
247
+ }
248
+ await connectorSettingsPage.clickAuthenticationTab();
249
+ await connectorSettingsPage.clickHTTPEndpointTab();
250
+ if (auth == 'bearer') {
251
+ await connectorSettingsPage.selectAuthenticationType('bearer');
252
+ await (0, test_1.expect)(connectorSettingsPage.bearerTokenInput).toBeVisible({
253
+ timeout: 60000,
254
+ });
255
+ await connectorSettingsPage.clickBearerTokenInput();
256
+ await connectorSettingsPage.fillBearerTokenInput('thisisabearertoken');
257
+ await (0, test_1.expect)(connectorSettingsPage.methodTypeDropdown).toBeVisible({
258
+ timeout: 30000,
259
+ });
260
+ await connectorSettingsPage.selectMethodType('POST');
261
+ }
262
+ else if (auth == 'basic') {
263
+ await connectorSettingsPage.selectAuthenticationType('basic');
264
+ await (0, test_1.expect)(connectorSettingsPage.usernameInput).toBeVisible({
265
+ timeout: 60000,
266
+ });
267
+ await connectorSettingsPage.clickUsernameInput();
268
+ (0, test_1.expect)(basicAuthCredentials['username'].length).toBeGreaterThan(0);
269
+ (0, test_1.expect)(basicAuthCredentials['password'].length).toBeGreaterThan(0);
270
+ await connectorSettingsPage.fillUsernameInput(basicAuthCredentials['username']);
271
+ await (0, test_1.expect)(connectorSettingsPage.passwordInput).toBeVisible({
272
+ timeout: 30000,
273
+ });
274
+ await connectorSettingsPage.clickPasswordInput();
275
+ await connectorSettingsPage.fillPasswordInput(basicAuthCredentials['password']);
276
+ await (0, test_1.expect)(connectorSettingsPage.methodTypeDropdown).toBeVisible({
277
+ timeout: 30000,
278
+ });
279
+ await connectorSettingsPage.selectMethodType('POST');
280
+ }
281
+ await connectorSettingsPage.clickUrlInput();
282
+ await connectorSettingsPage.fillUrlInput(url);
283
+ await (0, sleep_1.sleep)(3000);
284
+ await connectorSettingsPage.clickOutputMappingTab();
285
+ if (resultVariable.length > 0) {
286
+ await (0, test_1.expect)(connectorSettingsPage.resultVariableInput).toBeVisible({
287
+ timeout: 60000,
288
+ });
289
+ await connectorSettingsPage.clickResultVariableInput();
290
+ await connectorSettingsPage.fillResultVariableInput('result');
291
+ await (0, sleep_1.sleep)(5000);
292
+ }
293
+ await connectorSettingsPage.clickResultExpressionInput();
294
+ await connectorSettingsPage.fillResultExpressionInput(resultExpression);
295
+ await (0, sleep_1.sleep)(5000);
296
+ await modelerCreatePage.clickAppendElementButton();
297
+ await modelerCreatePage.clickAppendEndEventButton();
298
+ await (0, sleep_1.sleep)(10000);
299
+ }
300
+ exports.modelRestConnector = modelRestConnector;
301
+ async function assertLocatorVisibleWithPaginated(page, locator, text) {
302
+ const maxRetries = 6;
303
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
304
+ try {
305
+ await page.reload();
306
+ await (0, sleep_1.sleep)(5000);
307
+ if (attempt > 2) {
308
+ await (0, findLocatorInPaginatedList_1.findLocatorInPaginatedList)(page, locator);
309
+ }
310
+ await (0, test_1.expect)(locator).toBeVisible();
311
+ return;
312
+ }
313
+ catch (error) {
314
+ if (attempt < maxRetries - 1) {
315
+ console.warn(`Attempt ${attempt + 1} failed for asserting ${text}. Retrying...`);
316
+ }
317
+ else {
318
+ throw new Error(`Assertion ${text} failed after ${maxRetries} attempts`);
319
+ }
320
+ }
321
+ }
322
+ }
323
+ exports.assertLocatorVisibleWithPaginated = assertLocatorVisibleWithPaginated;
324
+ async function assertLocatorVisibleWithRetry(page, locator, text, timeout = 30000, notVisible, maxRetries = 3, clickLocator) {
325
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
326
+ try {
327
+ await page.reload();
328
+ await page.waitForLoadState('domcontentloaded');
329
+ if (clickLocator) {
330
+ await (0, test_1.expect)(clickLocator).toBeVisible({
331
+ timeout: 30000,
332
+ });
333
+ await clickLocator.click();
334
+ }
335
+ if (notVisible == true) {
336
+ await (0, test_1.expect)(locator.first()).not.toBeVisible({
337
+ timeout: timeout,
338
+ });
339
+ }
340
+ else {
341
+ await (0, test_1.expect)(locator).toBeVisible({
342
+ timeout: timeout,
343
+ });
344
+ }
345
+ return;
346
+ }
347
+ catch (error) {
348
+ if (attempt < maxRetries - 1) {
349
+ console.warn(`Attempt ${attempt + 1} failed for asserting ${text}. Retrying...`);
350
+ }
351
+ else {
352
+ // Keep the cause. Callers branch on the original error to tell a real
353
+ // failure apart from the test timeout aborting an in-flight wait (see
354
+ // assertReportWithRefreshes), and a bare attempt count told them
355
+ // nothing — so they retried into an already-dead test budget and
356
+ // reported their own generic "after N attempts" instead.
357
+ throw new Error(`Assertion failed after ${maxRetries} attempts: ${String(error)}`);
358
+ }
359
+ }
360
+ }
361
+ }
362
+ exports.assertLocatorVisibleWithRetry = assertLocatorVisibleWithRetry;
363
+ async function assertPageTextWithRetry(page, text, notVisible, timeout = 30000, maxRetries = 3) {
364
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
365
+ try {
366
+ await page.reload();
367
+ await page.waitForLoadState('domcontentloaded');
368
+ if (notVisible == true) {
369
+ await (0, test_1.expect)(page.getByText(text, { exact: true }).first()).not.toBeVisible({
370
+ timeout: timeout,
371
+ });
372
+ }
373
+ else {
374
+ await (0, test_1.expect)(page.getByText(text, { exact: true }).first()).toBeVisible({
375
+ timeout: timeout,
376
+ });
377
+ }
378
+ return;
379
+ }
380
+ catch (error) {
381
+ if (attempt < maxRetries - 1) {
382
+ console.warn(`Attempt ${attempt + 1} failed for asserting ${text}. Retrying...`);
383
+ }
384
+ else {
385
+ throw new Error(`Assertion failed after ${maxRetries} attempts: ${String(error)}`);
386
+ }
387
+ }
388
+ }
389
+ }
390
+ exports.assertPageTextWithRetry = assertPageTextWithRetry;
391
+ async function modelAndRunConnectorsTimerEventDiagram(modelerCreatePage, modelerHomePage, processName, page, connectorMarketplacePage, connectorTemplatePage, tenant = '') {
392
+ await modelerHomePage.clickCrossComponentProjectFolder();
393
+ await modelerHomePage.clickDiagramTypeDropdown();
394
+ await modelerHomePage.clickUploadFilesButton();
395
+ await (0, fileUpload_1.uploadFile)(page, 'Rest Connector Timer Event.bpmn');
396
+ await modelerHomePage.clickProcessDiagram('Rest Connector Timer Event');
397
+ await modelerCreatePage.clickDiagramBreadcrumb();
398
+ await modelerCreatePage.clickEditDiagramNameButton();
399
+ await modelerCreatePage.enterDiagramName(processName);
400
+ await modelerCreatePage.clickStartEventElement();
401
+ await modelerCreatePage.clickGeneralPropertiesPanel();
402
+ await modelerCreatePage.clickIdInput();
403
+ await modelerCreatePage.fillIdInput(processName);
404
+ await (0, sleep_1.sleep)(2000);
405
+ await page.reload();
406
+ await modelerCreatePage.clickEighthPlacedElement();
407
+ await modelerCreatePage.clickChangeTypeButton();
408
+ await (0, test_1.expect)(modelerCreatePage.marketPlaceButton).toBeVisible({
409
+ timeout: 120000,
410
+ });
411
+ await modelerCreatePage.clickMarketPlaceButton();
412
+ await connectorMarketplacePage.clickSearchForConnectorTextbox();
413
+ await connectorMarketplacePage.fillSearchForConnectorTextbox('REST Connector');
414
+ await connectorMarketplacePage.waitForConnectorSearchResults();
415
+ await connectorMarketplacePage.downloadConnectorToProject();
416
+ // Both lookups are container-relative: clickProjectBreadcrumb() returns to
417
+ // this test's process application, which is where the uploaded diagram
418
+ // lives. The downloaded element template is the open question -- hub
419
+ // publishes element templates to the workspace, but the marketplace
420
+ // download is initiated from inside the container, so it should land there.
421
+ // If a trace shows the template at workspace root instead, the first of
422
+ // these two calls becomes clickWorkspaceBreadcrumb() followed by
423
+ // returnToResourceContainer() before the diagram is reopened.
424
+ await modelerHomePage.clickProjectBreadcrumb();
425
+ await modelerHomePage.clickProcessDiagram('REST Outbound Connector');
426
+ await connectorTemplatePage.publishConnector();
427
+ await modelerHomePage.clickProjectBreadcrumb();
428
+ await modelerHomePage.clickProcessDiagram(processName);
429
+ await (0, sleep_1.sleep)(5000);
430
+ await page.reload();
431
+ await (0, sleep_1.sleep)(5000);
432
+ await modelerCreatePage.runProcessInstance('', tenant);
433
+ }
434
+ exports.modelAndRunConnectorsTimerEventDiagram = modelAndRunConnectorsTimerEventDiagram;
435
+ async function findTextWithPagination(page, text, timeout = 30000, action) {
436
+ const maxPages = 10;
437
+ const startTime = Date.now();
438
+ for (let pageNum = 0; pageNum < maxPages; pageNum++) {
439
+ if (Date.now() - startTime > timeout) {
440
+ console.log(`Overall timeout of ${timeout}ms exceeded`);
441
+ break;
442
+ }
443
+ const locator = page.getByText(text).last();
444
+ const textExists = await locator
445
+ .isVisible({ timeout: 2000 })
446
+ .catch(() => false);
447
+ if (textExists) {
448
+ console.log(`Found text "${text}" on page ${pageNum + 1}`);
449
+ if (action) {
450
+ await action(locator);
451
+ }
452
+ return true;
453
+ }
454
+ const loadMoreButton = page
455
+ .getByRole('button', { name: 'Load more', exact: true })
456
+ .last();
457
+ const isVisible = await loadMoreButton
458
+ .isVisible({ timeout: 1000 })
459
+ .catch(() => false);
460
+ const isEnabled = isVisible
461
+ ? await loadMoreButton.isEnabled().catch(() => false)
462
+ : false;
463
+ if (!isVisible || !isEnabled) {
464
+ console.log(`No more pages available after page ${pageNum + 1} (visible: ${isVisible}, enabled: ${isEnabled})`);
465
+ break;
466
+ }
467
+ console.log(`Text "${text}" not found on page ${pageNum + 1}, going to next page...`);
468
+ await loadMoreButton.click();
469
+ await page.waitForTimeout(1000);
470
+ }
471
+ return false;
472
+ }
473
+ exports.findTextWithPagination = findTextWithPagination;
474
+ async function modelDiagramFromFile(page, modelerHomePage, modelerCreatePage, processName, fileName = '', nrOfRenamedUserTasks = 0, taskName = '') {
475
+ await modelerHomePage.clickDiagramTypeDropdown();
476
+ await modelerHomePage.clickUploadFilesButton();
477
+ await (0, fileUpload_1.uploadFile)(page, fileName + '.bpmn');
478
+ await modelerHomePage.clickProcessDiagram(fileName);
479
+ await modelerCreatePage.clickDiagramBreadcrumb();
480
+ await modelerCreatePage.clickEditDiagramNameButton();
481
+ await modelerCreatePage.enterDiagramName(processName);
482
+ await (0, sleep_1.sleep)(1000);
483
+ await modelerCreatePage.clickGeneralPropertiesPanel();
484
+ await modelerCreatePage.clickNameInput();
485
+ await modelerCreatePage.fillNameInput(processName);
486
+ await modelerCreatePage.clickIdInput();
487
+ await modelerCreatePage.fillIdInput(processName);
488
+ if (nrOfRenamedUserTasks > 0) {
489
+ for (let i = 1; i <= nrOfRenamedUserTasks; i++) {
490
+ await modelerCreatePage.clickUserTask('process' + i);
491
+ await modelerCreatePage.clickNameInput();
492
+ await modelerCreatePage.fillNameInput(taskName + i);
493
+ await modelerCreatePage.clickIdInput();
494
+ await modelerCreatePage.fillIdInput(taskName + i);
495
+ await modelerCreatePage.clickCanvas();
496
+ }
497
+ }
498
+ await (0, sleep_1.sleep)(10000);
499
+ }
500
+ exports.modelDiagramFromFile = modelDiagramFromFile;
501
+ async function expectTextWithPagination(page, text, shouldExist = true, timeout = 30000) {
502
+ const found = await findTextWithPagination(page, text, timeout);
503
+ if (shouldExist && !found) {
504
+ throw new Error(`Text "${text}" not found on any page within ${timeout}ms`);
505
+ }
506
+ if (!shouldExist && found) {
507
+ throw new Error(`Text "${text}" should not exist but was found`);
508
+ }
509
+ if (shouldExist && found) {
510
+ await (0, test_1.expect)(page.getByText(text).last()).toBeVisible({ timeout: 5000 });
511
+ }
512
+ }
513
+ exports.expectTextWithPagination = expectTextWithPagination;
514
+ async function modelAndRunConnectorsDocHandlingDiagram(modelerCreatePage, modelerHomePage, processName, page, connectorMarketplacePage, zeebeUrl, zeebeClientId, zeebeClientSecret, endpoint, tenant = '') {
515
+ await modelerHomePage.clickCrossComponentProjectFolder();
516
+ await modelerHomePage.clickDiagramTypeDropdown();
517
+ await modelerHomePage.clickUploadFilesButton();
518
+ // 8.10-scoped copy of the fixture: it pins the REST connector element
519
+ // template version Web Modeler offers an 8.10 project (v18, engines ^8.10)
520
+ // and declares Camunda 8.10 as the execution platform. SM-8.8/SM-8.9 keep the
521
+ // fixture at the resources root, whose v15 pin still matches the template
522
+ // line their clusters accept. The version lives in the directory, not the
523
+ // basename: Web Modeler renders the basename in the diagram breadcrumb and
524
+ // a longer one widens the overflow tooltip until it covers the Rename item.
525
+ await (0, fileUpload_1.uploadFile)(page, 'SM-8.10/SM_Document_Handling_Connectors_User_Flow.bpmn');
526
+ await modelerHomePage.clickProcessDiagram('SM_Document_Handling_Connectors_User_Flow');
527
+ await modelerCreatePage.clickDiagramBreadcrumb();
528
+ await modelerCreatePage.clickEditDiagramNameButton();
529
+ await modelerCreatePage.enterDiagramName(processName);
530
+ await modelerCreatePage.clickGeneralPropertiesPanel();
531
+ await modelerCreatePage.clickNameInput();
532
+ await modelerCreatePage.fillNameInput(processName);
533
+ await modelerCreatePage.clickIdInput();
534
+ await modelerCreatePage.fillIdInput(processName);
535
+ await (0, sleep_1.sleep)(10000);
536
+ await modelerCreatePage.clickFirstPlaceRESTConnector();
537
+ await modelerCreatePage.clickChangeTypeButton();
538
+ await modelerCreatePage.clickMarketPlaceButton();
539
+ await connectorMarketplacePage.clickSearchForConnectorTextbox();
540
+ await connectorMarketplacePage.fillSearchForConnectorTextbox('REST Connector');
541
+ await connectorMarketplacePage.waitForConnectorSearchResults();
542
+ await connectorMarketplacePage.downloadConnectorToProject();
543
+ await page.reload();
544
+ await page.waitForLoadState('networkidle');
545
+ await modelerCreatePage.fillStartEventVariablesForDocHandling(zeebeUrl, zeebeClientId, zeebeClientSecret);
546
+ // bpmn-js reorders the canvas `<g>` groups as elements render and get
547
+ // selected, so `g:nth-child(N)` does not keep pointing at the task it was
548
+ // written for. Pin each shape by its BPMN id from the fixture instead: these
549
+ // are exactly the five REST tasks the fixture configures with
550
+ // `authentication.type = oauth-client-credentials-flow`, i.e. the ones that
551
+ // render an "OAuth 2.0 token endpoint" field. The sixth task
552
+ // (Activity_0jxgggi, "Download & store Image as 'doc' storage") is `noAuth`
553
+ // and has no such field.
554
+ const restTaskHit = (elementId) => page
555
+ .locator(`.djs-element[data-element-id="${elementId}"] .djs-hit`)
556
+ .first();
557
+ await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_0k0vloc'), endpoint);
558
+ await (0, sleep_1.sleep)(2000);
559
+ await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_02hwevk'), endpoint);
560
+ await (0, sleep_1.sleep)(2000);
561
+ await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_1oi90zl'), endpoint);
562
+ // The two parallel-branch tasks sit under the Details panel, so it has to be
563
+ // closed before their shape can be clicked and reopened afterwards.
564
+ await (0, sleep_1.sleep)(2000);
565
+ await modelerCreatePage.clickCloseDetailsPanel();
566
+ await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_0iyt4gv'), endpoint, { openPanel: true, elementId: 'Activity_0iyt4gv' });
567
+ await (0, sleep_1.sleep)(2000);
568
+ await modelerCreatePage.clickCloseDetailsPanel();
569
+ await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_1oiegam'), endpoint, { openPanel: true, elementId: 'Activity_1oiegam' });
570
+ await (0, sleep_1.sleep)(2000);
571
+ await modelerCreatePage.runProcessInstance('', tenant);
572
+ }
573
+ exports.modelAndRunConnectorsDocHandlingDiagram = modelAndRunConnectorsDocHandlingDiagram;
@@ -0,0 +1,6 @@
1
+ import { Locator, Page } from '@playwright/test';
2
+ import { OptimizeCollectionsPage } from '../SM-8.11/OptimizeCollectionsPage';
3
+ import { OptimizeReportPage } from '../SM-8.11/OptimizeReportPage';
4
+ import { OptimizeHomePage } from '../SM-8.11/OptimizeHomePage';
5
+ export declare const createReportForProcess: (optimizeCollectionsPage: OptimizeCollectionsPage, optimizeReportPage: OptimizeReportPage, processName: string) => Promise<void>;
6
+ export declare const assertReportWithRefreshes: (page: Page, optimizeHomePage: OptimizeHomePage, optimizeCollectionsPage: OptimizeCollectionsPage, optimizeReportPage: OptimizeReportPage, reportName: string, locator: Locator, text: string) => Promise<void>;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.assertReportWithRefreshes = exports.createReportForProcess = void 0;
4
+ const UtilitiesPage_1 = require("../SM-8.11/UtilitiesPage");
5
+ const UtilitiesPage_2 = require("../SM-8.11/UtilitiesPage");
6
+ const constants_1 = require("../../utils/constants");
7
+ const createReportForProcess = async (optimizeCollectionsPage, optimizeReportPage, processName) => {
8
+ const maxRetries = 30;
9
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
10
+ try {
11
+ await optimizeCollectionsPage.clickCreateNewButton();
12
+ await optimizeCollectionsPage.clickReportOption();
13
+ await optimizeReportPage.clickProcessSelectionButton();
14
+ await optimizeReportPage.waitUntilUserTaskProcessIsVisible(processName);
15
+ return;
16
+ }
17
+ catch (error) {
18
+ try {
19
+ await optimizeReportPage.clickCancelButton();
20
+ }
21
+ catch (cancelError) {
22
+ // Page may have been closed due to test timeout, ignore
23
+ }
24
+ await new Promise((resolve) => setTimeout(resolve, 2000));
25
+ }
26
+ }
27
+ throw new Error(`Failed to create report for process ${processName} after ${maxRetries} attempts`);
28
+ };
29
+ exports.createReportForProcess = createReportForProcess;
30
+ const assertReportWithRefreshes = async (page, optimizeHomePage, optimizeCollectionsPage, optimizeReportPage, reportName, locator, text) => {
31
+ // Was 30. Each attempt does 4 nested retries (each ~30s), so 30
32
+ // worst-case = 15 min on the longest-pole shard. Test that's
33
+ // genuinely failing at 30 attempts will also fail at 10 — same
34
+ // outcome but 3× faster fail. Test that needs more than 10
35
+ // refresh cycles for Optimize to catch up has a bigger underlying
36
+ // problem worth surfacing.
37
+ const maxRetries = 10;
38
+ // Playwright treats a 0 timeout as "no timeout", so passing 0 here made the
39
+ // visibility wait poll one already-rendered report view until the 720s test
40
+ // timeout killed the test. Optimize report views do not live-refresh, so that
41
+ // single wait could never observe the batch import landing, and it consumed
42
+ // every cycle this loop exists to spread out — the reason the failure surfaces
43
+ // as a bare "Test timeout of 720000ms exceeded". Bound each cycle instead, so
44
+ // the reload between cycles actually refetches. 60s (rather than the 90s the
45
+ // identical assertion gets in optimize-user-flows.spec.ts) keeps several
46
+ // cycles inside the smoke test's shared budget.
47
+ const attemptTimeout = constants_1._1_SECOND_IN_MS * 60;
48
+ // Stop starting cycles in time to throw the error below, instead of being
49
+ // killed mid-cycle by the test timeout, which reports no cause at all.
50
+ const deadline = Date.now() + constants_1._1_MINUTE_IN_MS * 6;
51
+ let attempts = 0;
52
+ let lastError;
53
+ while (attempts < maxRetries && Date.now() < deadline) {
54
+ attempts++;
55
+ try {
56
+ await optimizeHomePage.clickCollectionsLink();
57
+ await (0, UtilitiesPage_1.assertPageTextWithRetry)(page, reportName, false);
58
+ await optimizeCollectionsPage.clickMostRecentProcessReport(reportName);
59
+ await (0, UtilitiesPage_2.assertLocatorVisibleWithRetry)(page, locator, text, attemptTimeout);
60
+ return;
61
+ }
62
+ catch (error) {
63
+ lastError = error;
64
+ // Once the test budget is gone (or the page is closed) every remaining
65
+ // attempt rejects instantly, so this loop used to spin out and report
66
+ // "after 10 attempts" for a failure that happened somewhere else
67
+ // entirely. Surface the real error instead of retrying into it.
68
+ if (page.isClosed() || String(error).includes('Test timeout')) {
69
+ throw error;
70
+ }
71
+ // otherwise nothing to do. Just loop back to the collections
72
+ }
73
+ }
74
+ throw new Error(`Failed to assert report ${reportName} after ${attempts} attempts: ` +
75
+ String(lastError));
76
+ };
77
+ exports.assertReportWithRefreshes = assertReportWithRefreshes;