@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,340 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProcessApplicationPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ const submitModalWithRetry_1 = require("../../utils/assertionHelpers/submitModalWithRetry");
6
+ // ModelerHomePage creates the container, while ModelerCreatePage later binds
7
+ // its stage. Both page objects share the same Playwright Page.
8
+ const resourceContainers = new WeakMap();
9
+ // Workspace ids whose Environment an org admin assigned from a separate session
10
+ // (see assignEnvironmentToWorkspace), keyed by the non-admin user's Page. That
11
+ // user cannot open the workspace Environments tab, so ensureStageCluster skips it.
12
+ const adminAssignedWorkspaces = new WeakMap();
13
+ // Flag-on Self-Managed 8.10 (camunda-hub#27903: workspaces-enabled=true) renamed
14
+ // the entity hierarchy: the legacy "project folder" is now a Workspace and the
15
+ // legacy "process application" is now a Project (camunda-hub#28005). A Project is
16
+ // the resource container -- files, folders and uploads live directly inside it,
17
+ // there is no separate process-application level to descend into. It is created
18
+ // from the workspace's projects listing via the "Create project" split button +
19
+ // dialog, and the app lands on `/workspace/{wsId}/projects/{projectId}`.
20
+ //
21
+ // camunda-hub#29210 ("Environments phase1") then moved cluster assignment up a
22
+ // level again: a Project no longer has its own "Define stages" dialog or
23
+ // "Connected clusters" card at all. Assignment is now an Environment (backed by
24
+ // a registered cluster) assigned to the whole Workspace via its Environments
25
+ // settings tab (`/workspaces/{wsId}/settings?tab=environments`), shared by every
26
+ // Project inside that Workspace.
27
+ //
28
+ // This page object owns that container's surface (creating a Project) plus the
29
+ // Workspace-level Environment assignment Deploy/Play need. Entering and leaving
30
+ // it is driven from ModelerHomePage so the ~150 existing spec call sites keep
31
+ // working unchanged. Method names are kept from the flag-off era
32
+ // ("...ProcessApplication...", "...StageCluster...") so the callers do not have
33
+ // to change.
34
+ class ProcessApplicationPage {
35
+ page;
36
+ // The workspace projects listing's "Create project" split button. exact:true
37
+ // because the split button has a sibling "Create project options" chevron whose
38
+ // accessible name substring-matches otherwise (mirrors the hub team's own
39
+ // WorkspaceProjectsPage.newProjectButton). Falls back to the legacy flag-off
40
+ // "Create process application" button so a deployment with the flag still off
41
+ // keeps working.
42
+ createProcessApplicationButton;
43
+ // Legacy flag-off fallback only: the "Create new" menu item. Not rendered under
44
+ // workspaces-enabled, where the split button above is the entry point.
45
+ createProcessApplicationOption;
46
+ creationDialog;
47
+ nameInput;
48
+ submitButton;
49
+ cancelButton;
50
+ breadcrumb;
51
+ folderExplorer;
52
+ titleBar;
53
+ createNewDropdown;
54
+ inlineNameInput;
55
+ // Workspace management -> Environments tab (camunda-hub#29210). Page-scoped,
56
+ // not container-scoped: this tab lives on a different page
57
+ // (`/workspaces/{wsId}/settings`) than the Project detail these other
58
+ // locators target.
59
+ manageEnvironmentsHeading;
60
+ assignedEnvironmentCards;
61
+ editEnvironmentsButton;
62
+ environmentEditorRegion;
63
+ saveEnvironmentsButton;
64
+ constructor(page) {
65
+ this.page = page;
66
+ this.createProcessApplicationButton = page
67
+ .getByRole('button', { name: 'Create project', exact: true })
68
+ .or(page.getByRole('button', { name: 'Create process application' }))
69
+ .first();
70
+ this.createProcessApplicationOption = page.locator('[data-test="create-process-application"]');
71
+ // The workspace-mode create-project dialog carries a "Project name" field and
72
+ // has no accessible dialog name; scope to it via that field. Keeps the legacy
73
+ // flag-off "Create a process application" dialog as a fallback.
74
+ this.creationDialog = page
75
+ .getByRole('dialog')
76
+ .filter({ has: page.getByLabel('Project name') })
77
+ .or(page.getByRole('dialog', { name: 'Create a process application' }))
78
+ .first();
79
+ // Deliberately scoped to the dialog: ModelerCreatePage owns an unscoped
80
+ // getByLabel('Name', {exact: true}) for the properties panel, which would
81
+ // resolve to two elements while the creation modal is open.
82
+ this.nameInput = this.creationDialog
83
+ .getByLabel('Project name')
84
+ .or(this.creationDialog.getByLabel('Name', { exact: true }))
85
+ .first();
86
+ this.submitButton = this.creationDialog
87
+ .getByRole('button', { name: 'Create project', exact: true })
88
+ .or(this.creationDialog.getByRole('button', { name: 'Create', exact: true }))
89
+ .first();
90
+ this.cancelButton = this.creationDialog.getByRole('button', {
91
+ name: 'Cancel',
92
+ exact: true,
93
+ });
94
+ // Some shells expose a labelled resources region ("Resources" on the DS
95
+ // twin, "Folder explorer" on Carbon); the 8.10 flag-on Project detail does
96
+ // not, so this is only a soft readiness signal, never a required scope.
97
+ this.folderExplorer = page
98
+ .getByRole('region', { name: 'Folder explorer' })
99
+ .or(page.getByRole('region', { name: 'Resources' }))
100
+ .first();
101
+ // Proof we are on a Project (resource container) page: the flag-on Project
102
+ // detail renders this title-bar hook.
103
+ this.titleBar = page.locator('[data-test="process-application-title-bar"]');
104
+ // Any Project-detail marker also serves as an "inside the container" probe.
105
+ this.breadcrumb = this.titleBar.or(this.folderExplorer).first();
106
+ // The Project detail's "Create new" menu. Flag-on 8.10 renders it as
107
+ // [data-test="create-action-dropdown"] (aria-label "Create new"); older
108
+ // shells used [data-test="diagram-dropdown"]. Match either, page-wide,
109
+ // because the flag-on Project detail exposes no resources region to scope to.
110
+ this.createNewDropdown = page
111
+ .locator('[data-test="create-action-dropdown"]')
112
+ .or(page.locator('[data-test="diagram-dropdown"]'))
113
+ .or(page.getByRole('button', { name: 'Create new' }))
114
+ .first();
115
+ this.inlineNameInput = page.locator('[data-test="editable-input"]');
116
+ // "Assigned environments" heading: WorkspaceEnvironmentsTab's ready signal
117
+ // (it only renders once the workspace-scoped read has resolved).
118
+ this.manageEnvironmentsHeading = page.locator('[data-test="manage-environments-heading"]');
119
+ this.assignedEnvironmentCards = page.locator('[data-test="environment-card"]');
120
+ // Reads "Add environments" with none assigned yet, "Edit environments"
121
+ // otherwise -- same data-test either way.
122
+ this.editEnvironmentsButton = page.locator('[data-test="edit-environments-button"]');
123
+ this.environmentEditorRegion = page.getByRole('group', {
124
+ name: 'Edit assigned environments',
125
+ });
126
+ // Page-scoped, not environmentEditorRegion-scoped: Save/Cancel are
127
+ // rendered in the tab's header row, a SIBLING of the "Edit assigned
128
+ // environments" group, not a descendant of it.
129
+ this.saveEnvironmentsButton = page.getByRole('button', {
130
+ name: 'Save',
131
+ exact: true,
132
+ });
133
+ }
134
+ // Any one of the title bar, the resource region or the create-new dropdown
135
+ // proves we are on the Project (resource container) page.
136
+ pageReady() {
137
+ return this.titleBar
138
+ .or(this.createNewDropdown)
139
+ .or(this.folderExplorer)
140
+ .first();
141
+ }
142
+ async waitForProcessApplication(timeout = 90000) {
143
+ await (0, test_1.expect)(this.pageReady()).toBeVisible({ timeout });
144
+ }
145
+ async clickCreateProcessApplicationButton() {
146
+ await (0, test_1.expect)(this.createProcessApplicationButton).toBeVisible({
147
+ timeout: 60000,
148
+ });
149
+ await this.createProcessApplicationButton.click({ timeout: 60000 });
150
+ }
151
+ async clickCreateProcessApplicationOption() {
152
+ await (0, test_1.expect)(this.createProcessApplicationOption).toBeVisible({
153
+ timeout: 60000,
154
+ });
155
+ await this.createProcessApplicationOption.click({ timeout: 60000 });
156
+ }
157
+ // A Project is named up front in the create-project dialog. The inline path is
158
+ // kept as a fallback for the legacy flag-off "process application" surface.
159
+ async nameNewProcessApplication(name) {
160
+ const isModal = await this.creationDialog
161
+ .waitFor({ state: 'visible', timeout: 15000 })
162
+ .then(() => true)
163
+ .catch(() => false);
164
+ if (isModal) {
165
+ await this.nameInput.click({ timeout: 30000 });
166
+ await this.nameInput.fill(name);
167
+ await (0, test_1.expect)(this.nameInput).toHaveValue(name, { timeout: 10000 });
168
+ await (0, submitModalWithRetry_1.submitModalWithRetry)(this.submitButton, this.creationDialog);
169
+ // The app navigates to the new Project's own detail page on submit.
170
+ await this.page
171
+ .waitForURL(/\/projects\/[^/?#]+/, { timeout: 60000 })
172
+ .catch(() => { });
173
+ await this.waitForProcessApplication();
174
+ return;
175
+ }
176
+ await (0, test_1.expect)(this.inlineNameInput).toBeVisible({ timeout: 30000 });
177
+ await this.inlineNameInput.click({ timeout: 60000 });
178
+ await this.inlineNameInput.fill(name);
179
+ await this.inlineNameInput.press('Enter');
180
+ await this.waitForProcessApplication();
181
+ }
182
+ rememberResourceContainer(url) {
183
+ resourceContainers.set(this.page, { url });
184
+ }
185
+ // Derives the shared Workspace's Environments settings URL from a Project
186
+ // detail URL (".../workspaces/<wsId>/projects/<projectId>[?...]"): the
187
+ // origin/app-root plus "/workspaces/<wsId>/settings?tab=environments" -- the
188
+ // same deep link camunda-hub's own useManageEnvironmentsLink builds for the
189
+ // deploy dialog's "Manage environments" link. Always emits the plural
190
+ // "workspaces" regardless of which spelling the container URL used
191
+ // (ModelerHomePage.openWorkspaceTile still tolerates a singular
192
+ // "/workspace/<id>/projects" from camunda-hub#28928 not yet being merged
193
+ // everywhere) -- the settings route itself (App.tsx) is plural-only, with no
194
+ // singular alias, so reusing a singular prefix verbatim would 404.
195
+ workspaceEnvironmentsUrl(containerUrl) {
196
+ const match = containerUrl.match(/^(.*)\/workspaces?\/([^/?#]+)\//);
197
+ if (!match) {
198
+ throw new Error(`Could not derive the workspace Environments URL from "${containerUrl}": ` +
199
+ 'expected a "/workspaces/<id>/..." segment.');
200
+ }
201
+ const [, origin, workspaceId] = match;
202
+ return `${origin}/workspaces/${workspaceId}/settings?tab=environments`;
203
+ }
204
+ // Assigns an Environment to the shared Workspace via its Environments
205
+ // settings tab, so Deploy/Play (and Play's "Configure environment") find a
206
+ // usable target instead of rendering "No environments assigned" and staying
207
+ // disabled -- camunda-hub#29210 moved this out of the Project detail's own
208
+ // "Define stages" dialog and up to the Workspace, shared by every Project
209
+ // inside it.
210
+ //
211
+ // Checks the read-only "Assigned environments" list before entering edit
212
+ // mode, so a Workspace another (parallel) test already assigned is left
213
+ // alone regardless of this Page's own memo flag below -- required because
214
+ // every test's Project lives in the one shared Workspace. This is a
215
+ // best-effort check, not a lock: two tests racing to assign at once each
216
+ // still write their own snapshot of the selected set (Save persists the
217
+ // whole set, it does not merge), so a genuine concurrent race could still
218
+ // trigger two writes. It converges correctly here only because every test
219
+ // targets the one MODELER_CLUSTER_NAME (or, when unset, is happy with
220
+ // whichever single Environment ends up assigned).
221
+ async ensureStageCluster(clusterName) {
222
+ const container = resourceContainers.get(this.page);
223
+ if (!container ||
224
+ (container.stageBound && container.developmentCluster === clusterName)) {
225
+ return;
226
+ }
227
+ if (adminAssignedWorkspaces
228
+ .get(this.page)
229
+ ?.has(this.workspaceId(container.url))) {
230
+ container.stageBound = true;
231
+ container.developmentCluster = clusterName;
232
+ return;
233
+ }
234
+ const returnTo = this.page.url();
235
+ await this.assignEnvironmentToWorkspace(container.url, clusterName);
236
+ container.stageBound = true;
237
+ container.developmentCluster = clusterName;
238
+ await this.page.goto(returnTo, { waitUntil: 'domcontentloaded' });
239
+ }
240
+ // Assigns an Environment to the workspace that `workspaceUrl` (any
241
+ // "/workspaces/<id>/..." URL) belongs to, driving this Page's own session.
242
+ async assignEnvironmentToWorkspace(workspaceUrl, clusterName) {
243
+ const environmentsUrl = this.workspaceEnvironmentsUrl(workspaceUrl);
244
+ await (0, test_1.expect)(async () => {
245
+ await this.page.goto(environmentsUrl, { waitUntil: 'domcontentloaded' });
246
+ await this.assignWorkspaceEnvironment(clusterName);
247
+ }).toPass({ timeout: 240000, intervals: [1000, 2000, 5000] });
248
+ }
249
+ markWorkspaceEnvironmentAssignedByAdmin(workspaceUrl) {
250
+ const assigned = adminAssignedWorkspaces.get(this.page) ?? new Set();
251
+ assigned.add(this.workspaceId(workspaceUrl));
252
+ adminAssignedWorkspaces.set(this.page, assigned);
253
+ }
254
+ workspaceId(workspaceUrl) {
255
+ const match = workspaceUrl.match(/\/workspaces?\/([^/?#]+)\//);
256
+ if (!match) {
257
+ throw new Error(`Could not derive the workspace id from "${workspaceUrl}": ` +
258
+ 'expected a "/workspaces/<id>/..." segment.');
259
+ }
260
+ return match[1];
261
+ }
262
+ async assignWorkspaceEnvironment(clusterName) {
263
+ const tabReady = await this.manageEnvironmentsHeading
264
+ .or(this.editEnvironmentsButton)
265
+ .first()
266
+ .waitFor({ state: 'visible', timeout: 90000 })
267
+ .then(() => true)
268
+ .catch(() => false);
269
+ if (!tabReady) {
270
+ // WorkspaceManageBody silently normalises an unrecognised/unusable
271
+ // "?tab=environments" back to Members -- e.g. isEnvironmentsEnabled()
272
+ // off, or the current user failing canManageWorkspaceEnvironments
273
+ // (assigning is stricter than viewing: a plain Editor with no
274
+ // elevated/DevOps org role cannot assign at all). Name the likely
275
+ // cause rather than timing out with an opaque "not visible".
276
+ const onMembersTab = await this.page
277
+ .locator('[data-test="tab-members"][data-state="active"]')
278
+ .isVisible()
279
+ .catch(() => false);
280
+ throw new Error('The workspace Environments settings tab never rendered' +
281
+ (onMembersTab ? ' -- landed on the Members tab instead' : '') +
282
+ '. Either the Environments feature is off for this deployment, or the ' +
283
+ "current user lacks permission to manage this workspace's environments.");
284
+ }
285
+ const alreadyAssigned = clusterName
286
+ ? this.assignedEnvironmentCards.filter({ hasText: clusterName })
287
+ : this.assignedEnvironmentCards;
288
+ if (await alreadyAssigned
289
+ .first()
290
+ .isVisible()
291
+ .catch(() => false)) {
292
+ return;
293
+ }
294
+ await this.editEnvironmentsButton.click({ timeout: 30000 });
295
+ await (0, test_1.expect)(this.environmentEditorRegion).toBeVisible({ timeout: 30000 });
296
+ const escapedClusterName = clusterName?.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
297
+ // A picker card's toggle button is "Select <name> (<clusterName or
298
+ // clusterId>)" (see camunda-hub EnvironmentPickerCard) -- match the
299
+ // cluster name in that parenthetical rather than the environment's own
300
+ // display name, which is a separate, admin-chosen field that need not
301
+ // match the cluster at all.
302
+ const targetOption = clusterName
303
+ ? this.environmentEditorRegion
304
+ .getByRole('button', {
305
+ name: new RegExp(`^Select .*\\(${escapedClusterName}\\)`),
306
+ })
307
+ .first()
308
+ : this.environmentEditorRegion
309
+ .getByRole('button', { name: /^Select / })
310
+ .first();
311
+ const optionAppeared = await targetOption
312
+ .waitFor({ state: 'visible', timeout: 30000 })
313
+ .then(() => true)
314
+ .catch(() => false);
315
+ if (!optionAppeared) {
316
+ throw new Error(clusterName
317
+ ? `No Environment backed by cluster "${clusterName}" is available to assign to this ` +
318
+ 'workspace. Register the cluster (or its Environment) first.'
319
+ : 'No Environment is available to assign to this workspace: the picker shows "No ' +
320
+ 'environments available".');
321
+ }
322
+ await targetOption.click({ timeout: 30000 });
323
+ await (0, test_1.expect)(this.saveEnvironmentsButton).toBeEnabled({ timeout: 30000 });
324
+ await this.saveEnvironmentsButton.click({ timeout: 30000 });
325
+ await (0, test_1.expect)(this.environmentEditorRegion).toBeHidden({ timeout: 60000 });
326
+ }
327
+ async openByName(name) {
328
+ // Workspace-mode projects table: the whole row is the click target (see the
329
+ // hub team's WorkspaceProjectsPage). Fall back to the legacy title cell.
330
+ const projectRow = this.page
331
+ .getByRole('row', { name })
332
+ .first()
333
+ .or(this.page.getByRole('row').filter({ hasText: name }).getByTitle(name))
334
+ .first();
335
+ await (0, test_1.expect)(projectRow).toBeVisible({ timeout: 90000 });
336
+ await projectRow.click({ timeout: 60000 });
337
+ await this.waitForProcessApplication();
338
+ }
339
+ }
340
+ exports.ProcessApplicationPage = ProcessApplicationPage;
@@ -0,0 +1,12 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class SettingsPage {
3
+ private page;
4
+ readonly openSettingsButton: Locator;
5
+ readonly logoutButton: Locator;
6
+ readonly openUserSidebarButton: Locator;
7
+ constructor(page: Page);
8
+ clickOpenSettingsButton(): Promise<void>;
9
+ clickOpenUserSideBarButton(): Promise<void>;
10
+ clickLogoutButton(): Promise<void>;
11
+ }
12
+ export { SettingsPage };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SettingsPage = void 0;
4
+ class SettingsPage {
5
+ page;
6
+ openSettingsButton;
7
+ logoutButton;
8
+ openUserSidebarButton;
9
+ constructor(page) {
10
+ this.page = page;
11
+ this.openSettingsButton = page
12
+ .getByRole('button', { name: /^User menu/ })
13
+ .or(page.getByLabel('Open Settings'))
14
+ .first();
15
+ this.openUserSidebarButton = page
16
+ .getByRole('button', { name: /^User menu/ })
17
+ .or(page.getByLabel('Open User Sidebar'))
18
+ .first();
19
+ this.logoutButton = page
20
+ .getByRole('menuitem', { name: /log out/i })
21
+ .or(page.getByRole('button', { name: 'Log out' }))
22
+ .first();
23
+ }
24
+ async clickOpenSettingsButton() {
25
+ await this.openSettingsButton.click({ timeout: 120000 });
26
+ }
27
+ async clickOpenUserSideBarButton() {
28
+ await this.openUserSidebarButton.click({ timeout: 120000 });
29
+ }
30
+ async clickLogoutButton() {
31
+ await this.logoutButton.click({ timeout: 30000 });
32
+ }
33
+ }
34
+ exports.SettingsPage = SettingsPage;
@@ -0,0 +1,70 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class TaskDetailsPage {
3
+ private page;
4
+ readonly assignToMeButton: Locator;
5
+ readonly completeButton: Locator;
6
+ readonly unassignButton: Locator;
7
+ readonly assignee: Locator;
8
+ readonly completeTaskButton: Locator;
9
+ readonly addVariableButton: Locator;
10
+ readonly detailsPanel: Locator;
11
+ readonly detailsHeader: Locator;
12
+ readonly pendingTaskDescription: Locator;
13
+ readonly pickATaskHeader: Locator;
14
+ readonly emptyTaskMessage: Locator;
15
+ readonly nameInput: Locator;
16
+ readonly addressInput: Locator;
17
+ readonly ageInput: Locator;
18
+ readonly variablesTable: Locator;
19
+ readonly nameColumnHeader: Locator;
20
+ readonly valueColumnHeader: Locator;
21
+ readonly form: Locator;
22
+ readonly numberInput: Locator;
23
+ readonly incrementButton: Locator;
24
+ readonly decrementButton: Locator;
25
+ readonly dateInput: Locator;
26
+ readonly timeInput: Locator;
27
+ readonly checkbox: Locator;
28
+ readonly selectDropdown: Locator;
29
+ readonly tagList: Locator;
30
+ readonly detailsInfo: Locator;
31
+ readonly textInput: Locator;
32
+ readonly taskCompletedBanner: Locator;
33
+ readonly assignedToMeText: Locator;
34
+ readonly noPreviewContainer: Locator;
35
+ readonly previewContainer: Locator;
36
+ constructor(page: Page);
37
+ clickAssignToMeButton(): Promise<void>;
38
+ clickUnassignButton(): Promise<void>;
39
+ clickCompleteTaskButton(): Promise<void>;
40
+ clickAddVariableButton(): Promise<void>;
41
+ replaceExistingVariableValue(values: {
42
+ name: string;
43
+ value: string;
44
+ }): Promise<void>;
45
+ getNthVariableNameInput(nth: number): Locator;
46
+ getNthVariableValueInput(nth: number): Locator;
47
+ addVariable(payload: {
48
+ name: string;
49
+ value: string;
50
+ }): Promise<void>;
51
+ fillNumber(number: string): Promise<void>;
52
+ clickIncrementButton(): Promise<void>;
53
+ clickDecrementButton(): Promise<void>;
54
+ fillDate(date: string): Promise<void>;
55
+ enterTime(time: string): Promise<void>;
56
+ checkCheckbox(): Promise<void>;
57
+ selectDropdownValue(value: string): Promise<void>;
58
+ clickRadioButton(radioBtnLabel: string): Promise<void>;
59
+ checkChecklistBox(label: string): Promise<void>;
60
+ enterTwoValuesInTagList(value1: string, value2: string): Promise<void>;
61
+ clickTextInput(): Promise<void>;
62
+ fillTextInput(value: string): Promise<void>;
63
+ priorityAssertion(priority: string): Promise<void>;
64
+ taskAssertion(name: string): Promise<void>;
65
+ assertLoadedImage(documentName: string): Promise<void>;
66
+ assertDocumentDownloadButton(documentName: string): Promise<void>;
67
+ assertPdfPreviewViewerExists(): Promise<void>;
68
+ assertTextIsPresent(expectedText: string): Promise<void>;
69
+ }
70
+ export { TaskDetailsPage };