@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,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createKeycloakUser = exports.createUser = exports.setupKeycloakUser = exports.keycloakAdminCredentials = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ const sleep_1 = require("../../utils/sleep");
6
+ const keycloakAdminCredentials = () => {
7
+ return {
8
+ username: process.env.DISTRO_QA_E2E_TESTS_KEYCLOAK_USERNAME || 'admin',
9
+ password: process.env.DISTRO_QA_E2E_TESTS_KEYCLOAK_PASSWORD,
10
+ };
11
+ };
12
+ exports.keycloakAdminCredentials = keycloakAdminCredentials;
13
+ const setupKeycloakUser = async (navigationPage, identityPage, keycloakLoginPage, keycloakAdminPage, ocIdentityHomePage, ocIdentityRolesPage, assignToDefaultTenant = false, managementIdentityTenantPage) => {
14
+ const testUsername = `test-user-${new Date().getTime()}-${Math.random()
15
+ .toString(36)
16
+ .substring(7)}`;
17
+ const testPassword = 'test-password';
18
+ await createKeycloakUser(navigationPage, keycloakLoginPage, keycloakAdminPage, testUsername, testPassword);
19
+ await createIdentityUser(navigationPage, identityPage, testUsername);
20
+ if (assignToDefaultTenant && managementIdentityTenantPage) {
21
+ const userEmail = `qacamunda+${testUsername}@gmail.com`;
22
+ await navigationPage.goToManagementIdentity();
23
+ await (0, test_1.expect)(identityPage.usersLink).toBeVisible({ timeout: 10000 });
24
+ if (await identityPage.tenantTab.isVisible()) {
25
+ await managementIdentityTenantPage.assignUserToTenant('Default', testUsername, userEmail);
26
+ }
27
+ }
28
+ await createOCUser(navigationPage, ocIdentityHomePage, ocIdentityRolesPage, testUsername);
29
+ return { testUsername, testPassword };
30
+ };
31
+ exports.setupKeycloakUser = setupKeycloakUser;
32
+ async function createUser(navigationPage, identityPage, keycloakLoginPage, keycloakAdminPage, username, password) {
33
+ await createKeycloakUser(navigationPage, keycloakLoginPage, keycloakAdminPage, username, password);
34
+ await createIdentityUser(navigationPage, identityPage, username);
35
+ }
36
+ exports.createUser = createUser;
37
+ // Keycloak occasionally serves "We are sorry... Unexpected error when
38
+ // handling authentication request to identity provider" instead of
39
+ // completing the admin login (the same transient 5xx NavigationPage.goTo's
40
+ // progressive backoff already guards against for app logins). This flow logs
41
+ // into the Keycloak admin console directly rather than through goTo, so it
42
+ // needs the same retry of the whole login sequence instead of failing the
43
+ // test outright on the first hit.
44
+ async function loginToKeycloakAdmin(navigationPage, keycloakLoginPage, keycloakAdminPage, maxRetries = 5) {
45
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
46
+ try {
47
+ await navigationPage.goToKeycloak();
48
+ await keycloakLoginPage.toBeVisible();
49
+ await keycloakLoginPage.fillUsername((0, exports.keycloakAdminCredentials)().username);
50
+ await keycloakLoginPage.fillPassword((0, exports.keycloakAdminCredentials)().password);
51
+ await keycloakLoginPage.clickLogin();
52
+ await keycloakAdminPage.toBeVisible();
53
+ return;
54
+ }
55
+ catch (error) {
56
+ if (attempt >= maxRetries - 1) {
57
+ throw error;
58
+ }
59
+ console.warn(`[KeycloakUtils] Keycloak admin login attempt ${attempt + 1} failed, retrying: ${error instanceof Error ? error.message : error}`);
60
+ await (0, sleep_1.sleep)(2000 * (attempt + 1));
61
+ }
62
+ }
63
+ }
64
+ async function createKeycloakUser(navigationPage, keycloakLoginPage, keycloakAdminPage, username, password) {
65
+ await loginToKeycloakAdmin(navigationPage, keycloakLoginPage, keycloakAdminPage);
66
+ await keycloakAdminPage.switchToCamundaPlatform();
67
+ await keycloakAdminPage.clickUsersTab();
68
+ await keycloakAdminPage.clickAddUser();
69
+ await keycloakAdminPage.fillUser(username);
70
+ await keycloakAdminPage.saveUser();
71
+ await keycloakAdminPage.fillPassword(password);
72
+ await keycloakAdminPage.savePassword();
73
+ }
74
+ exports.createKeycloakUser = createKeycloakUser;
75
+ const createIdentityUser = async (navigationPage, managementIdentity, username) => {
76
+ await navigationPage.goToManagementIdentity();
77
+ await managementIdentity.clickUsersLink();
78
+ await managementIdentity.clickUser(username);
79
+ await managementIdentity.clickAssignedRolesTab();
80
+ await managementIdentity.clickAssignRolesButton();
81
+ if (process.env.IS_OPTIMIZE !== 'false') {
82
+ await managementIdentity.clickOptimizeCheckbox();
83
+ }
84
+ await managementIdentity.clickModelerCheckbox();
85
+ await managementIdentity.clickIdentityCheckbox();
86
+ await managementIdentity.clickOrchestrationCheckbox();
87
+ await managementIdentity.clickAddButton();
88
+ };
89
+ const createOCUser = async (navigationPage, ocIdentityHomePage, ocIdentityRolesPage, username) => {
90
+ await navigationPage.goToOCAdmin();
91
+ await ocIdentityHomePage.clickRolesTab();
92
+ await ocIdentityRolesPage.clickAdminRole();
93
+ await ocIdentityRolesPage.assignUserToRole(username);
94
+ };
@@ -0,0 +1,21 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class LoginPage {
3
+ private page;
4
+ readonly usernameInput: Locator;
5
+ readonly passwordInput: Locator;
6
+ readonly loginButton: Locator;
7
+ readonly coreUsernameInput: Locator;
8
+ readonly corePasswordInput: Locator;
9
+ readonly coreLoginButton: Locator;
10
+ readonly keycloakBanner: Locator;
11
+ private useCore;
12
+ private useKeycloak;
13
+ constructor(page: Page);
14
+ detectLoginForm(): Promise<void>;
15
+ fillUsername(username: string): Promise<void>;
16
+ clickUsername(): Promise<void>;
17
+ fillPassword(password: string): Promise<void>;
18
+ clickLoginButton(): Promise<void>;
19
+ login(username: string, password: string): Promise<boolean>;
20
+ }
21
+ export { LoginPage };
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoginPage = void 0;
4
+ class LoginPage {
5
+ page;
6
+ usernameInput;
7
+ passwordInput;
8
+ loginButton;
9
+ coreUsernameInput;
10
+ corePasswordInput;
11
+ coreLoginButton;
12
+ keycloakBanner;
13
+ useCore = false;
14
+ useKeycloak = false;
15
+ constructor(page) {
16
+ this.page = page;
17
+ this.usernameInput = page.getByLabel('Username or email');
18
+ this.passwordInput = page.getByLabel('Password');
19
+ this.loginButton = page.getByRole('button', { name: /log in|sign in/i });
20
+ this.coreUsernameInput = page.getByPlaceholder('Username');
21
+ this.corePasswordInput = page.getByPlaceholder('Password');
22
+ this.coreLoginButton = page.getByRole('button', { name: 'Login' });
23
+ this.keycloakBanner = page.locator('body#keycloak-bg[data-page-id="login-login"]');
24
+ }
25
+ async detectLoginForm() {
26
+ // If we're on an app page that's about to redirect to KC, wait for
27
+ // the navigation to complete before looking for login form elements.
28
+ const url = this.page.url();
29
+ if (!url.includes('/auth/') && !url.includes('/login-callback')) {
30
+ await this.page
31
+ .waitForURL((u) => u.pathname.includes('/auth/'), {
32
+ timeout: 30000,
33
+ waitUntil: 'domcontentloaded',
34
+ })
35
+ .catch(() => { });
36
+ }
37
+ const kcUsername = this.page.locator('#username');
38
+ const anyForm = kcUsername
39
+ .or(this.coreLoginButton)
40
+ .or(this.keycloakBanner)
41
+ .first();
42
+ await anyForm.waitFor({ state: 'visible', timeout: 30000 });
43
+ if (await this.coreLoginButton.isVisible()) {
44
+ this.useCore = true;
45
+ }
46
+ else if (await this.keycloakBanner.isVisible()) {
47
+ this.useKeycloak = true;
48
+ }
49
+ }
50
+ async fillUsername(username) {
51
+ if (await this.page.locator('#username').isVisible()) {
52
+ await this.page.fill('#username', username);
53
+ }
54
+ else {
55
+ await (this.useCore
56
+ ? this.coreUsernameInput.fill(username)
57
+ : this.usernameInput.fill(username));
58
+ }
59
+ }
60
+ async clickUsername() {
61
+ if (await this.page.locator('#username').isVisible()) {
62
+ await this.page.click('#username');
63
+ }
64
+ else {
65
+ await (this.useCore
66
+ ? this.coreUsernameInput.click({ timeout: 60000 })
67
+ : this.usernameInput.click({ timeout: 60000 }));
68
+ }
69
+ }
70
+ async fillPassword(password) {
71
+ if (await this.page.locator('#password').isVisible()) {
72
+ await this.page.fill('#password', password);
73
+ }
74
+ else {
75
+ await (this.useCore
76
+ ? this.corePasswordInput.fill(password)
77
+ : this.passwordInput.fill(password));
78
+ }
79
+ }
80
+ async clickLoginButton() {
81
+ if (await this.page.locator('button[type="submit"]').isVisible()) {
82
+ // The Keycloak submit path was the only click here without an explicit
83
+ // timeout, so it inherited the 10s actionTimeout while page.click waits
84
+ // out the OAuth redirect chain it triggers. Match the 60s budget the
85
+ // sibling branches already use.
86
+ await this.page.click('button[type="submit"]', { timeout: 60000 });
87
+ }
88
+ else {
89
+ await (this.useCore
90
+ ? this.coreLoginButton.click({ timeout: 60000 })
91
+ : this.loginButton.click({ timeout: 60000 }));
92
+ }
93
+ }
94
+ // Resolves to whether credentials were actually submitted. A missing form is
95
+ // not an error -- the caller may already hold a session, in which case there
96
+ // is nothing to fill -- but the caller has to be able to tell that apart from
97
+ // a submitted form, because only the latter leaves a page transition pending.
98
+ async login(username, password) {
99
+ try {
100
+ await this.detectLoginForm();
101
+ }
102
+ catch (error) {
103
+ return false;
104
+ }
105
+ await this.clickUsername();
106
+ await this.fillUsername(username);
107
+ await this.fillPassword(password);
108
+ await this.clickLoginButton();
109
+ return true;
110
+ }
111
+ }
112
+ exports.LoginPage = LoginPage;
@@ -0,0 +1,44 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class ManagementIdentityPage {
3
+ private page;
4
+ readonly identityBanner: Locator;
5
+ readonly usersLink: Locator;
6
+ readonly assignedRolesTab: Locator;
7
+ readonly demoUser: Locator;
8
+ readonly confirmDeleteButton: Locator;
9
+ readonly assignRolesButton: Locator;
10
+ readonly addButton: Locator;
11
+ readonly optimizeCheckbox: Locator;
12
+ readonly modelerCheckbox: Locator;
13
+ readonly deleteButton: Locator;
14
+ readonly deleteSubButton: Locator;
15
+ readonly tenantTab: Locator;
16
+ readonly licenseKeyTagNonProduction: Locator;
17
+ readonly licenseKeyTagNonCommercial: Locator;
18
+ readonly licenseKeyTagProduction: Locator;
19
+ readonly licenseKeyTagCommercial: Locator;
20
+ readonly modelerAdminCheckbox: Locator;
21
+ readonly identityCheckbox: Locator;
22
+ readonly openSidebarButton: Locator;
23
+ readonly logoutButton: Locator;
24
+ readonly orchestrationCheckbox: Locator;
25
+ constructor(page: Page);
26
+ clickUsersLink(): Promise<void>;
27
+ clickUser(username: string): Promise<void>;
28
+ clickAssignedRolesTab(): Promise<void>;
29
+ clickDemoUser(): Promise<void>;
30
+ clickDeleteAccessButton(accessToDelete: string | string[]): Promise<void>;
31
+ clickConfirmDeleteButton(): Promise<void>;
32
+ clickAssignRolesButton(): Promise<void>;
33
+ clickAddButton(): Promise<void>;
34
+ clickOptimizeCheckbox(): Promise<void>;
35
+ clickModelerCheckbox(): Promise<void>;
36
+ clickIdentityCheckbox(): Promise<void>;
37
+ clickModelerAdminCheckbox(): Promise<void>;
38
+ clickUserGroup(name: string): Promise<void>;
39
+ clickTenantTab(): Promise<void>;
40
+ clickOpenSidebarButton(): Promise<void>;
41
+ clickLogoutButton(): Promise<void>;
42
+ clickOrchestrationCheckbox(): Promise<void>;
43
+ }
44
+ export { ManagementIdentityPage };
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ManagementIdentityPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class ManagementIdentityPage {
6
+ page;
7
+ identityBanner;
8
+ usersLink;
9
+ assignedRolesTab;
10
+ demoUser;
11
+ confirmDeleteButton;
12
+ assignRolesButton;
13
+ addButton;
14
+ optimizeCheckbox;
15
+ modelerCheckbox;
16
+ deleteButton;
17
+ deleteSubButton;
18
+ tenantTab;
19
+ licenseKeyTagNonProduction;
20
+ licenseKeyTagNonCommercial;
21
+ licenseKeyTagProduction;
22
+ licenseKeyTagCommercial;
23
+ modelerAdminCheckbox;
24
+ identityCheckbox;
25
+ openSidebarButton;
26
+ logoutButton;
27
+ orchestrationCheckbox;
28
+ constructor(page) {
29
+ this.page = page;
30
+ this.identityBanner = page
31
+ .locator('a')
32
+ .filter({ hasText: /^Camunda logo\s*Management Identity$/ })
33
+ .first();
34
+ this.usersLink = page.locator('a').filter({ hasText: 'Users' });
35
+ this.tenantTab = page
36
+ .getByRole('link', { name: 'Tenants' })
37
+ .or(page.locator('a').filter({ hasText: 'Tenants' }))
38
+ .first();
39
+ this.assignedRolesTab = page.getByRole('tab', { name: 'Assigned roles' });
40
+ this.demoUser = page.getByRole('cell', { name: 'demo' }).first();
41
+ this.confirmDeleteButton = page.getByRole('button', {
42
+ name: 'danger Delete',
43
+ });
44
+ this.assignRolesButton = page.getByRole('button', { name: 'Assign roles' });
45
+ this.addButton = page.getByRole('button', { name: 'Add' });
46
+ this.optimizeCheckbox = page
47
+ .locator('label')
48
+ .filter({ hasText: 'Optimize (Grants full access to Optimize)' });
49
+ // The chart's Keycloak preset (camunda-platform-helm#6896) renamed the Hub
50
+ // application and added "Hub"/"Hub Admin" roles while keeping the identical
51
+ // legacy "Web Modeler"/"Web Modeler Admin" roles for 8.10-alpha upgrades,
52
+ // so the straddle alternation that matched either wording now resolves to
53
+ // two rows and trips strict mode. Both roles grant the same permissions on
54
+ // the same application; target the go-forward "Hub" name, which is also
55
+ // what the chart assigns its own QA users. The `for` attribute is the role
56
+ // name, so this survives further description rewording.
57
+ this.modelerCheckbox = page.locator('label[for="Hub"]');
58
+ this.identityCheckbox = page.locator('label').filter({
59
+ hasText: 'ManagementIdentity (Provides full access to Management Identity)',
60
+ });
61
+ this.deleteSubButton = page.getByRole('button', { name: 'danger delete' });
62
+ this.deleteButton = page.locator('button', { hasText: 'danger' });
63
+ this.licenseKeyTagNonProduction = page
64
+ .getByText('Non-production license')
65
+ .first();
66
+ this.licenseKeyTagNonCommercial = page.getByText('Non-commercial license');
67
+ this.licenseKeyTagProduction = page.getByText('Production license').first();
68
+ this.licenseKeyTagCommercial = page.getByText('Commercial license');
69
+ // Same two-role split as `modelerCheckbox` above.
70
+ this.modelerAdminCheckbox = page.locator('label[for="Hub Admin"]');
71
+ this.openSidebarButton = page.getByLabel('Open User Sidebar');
72
+ this.logoutButton = page.getByRole('button', { name: 'Log out' });
73
+ this.orchestrationCheckbox = page.locator('label').filter({
74
+ hasText: 'Orchestration (Grants full access to Orchestration)',
75
+ });
76
+ }
77
+ async clickUsersLink() {
78
+ try {
79
+ await this.usersLink.click({ timeout: 180000, force: true });
80
+ }
81
+ catch {
82
+ await this.page.reload();
83
+ await this.usersLink.click({ timeout: 180000, force: true });
84
+ }
85
+ }
86
+ async clickUser(username) {
87
+ const searchbox = this.page.getByRole('searchbox');
88
+ await searchbox.click({ timeout: 30000 });
89
+ await searchbox.fill(username);
90
+ const user = this.page.getByRole('cell', { name: username, exact: true });
91
+ await (0, test_1.expect)(user).toBeVisible({ timeout: 60000 });
92
+ await user.click();
93
+ }
94
+ async clickAssignedRolesTab() {
95
+ await (0, test_1.expect)(this.assignedRolesTab).toBeVisible({ timeout: 60000 });
96
+ await this.assignedRolesTab.click();
97
+ }
98
+ async clickDemoUser() {
99
+ await (0, test_1.expect)(this.demoUser).toBeVisible({ timeout: 60000 });
100
+ await this.demoUser.click({ timeout: 180000 });
101
+ }
102
+ // The assigned-roles table can come up with a stale row set shortly after the
103
+ // roles were assigned — run 32920068272 recorded `/api/users/<id>/roles`
104
+ // returning Optimize while the table repeated the neighbouring row's label —
105
+ // and it does not re-render on its own. Rebuild it from a fresh response
106
+ // between attempts before reporting the role as missing.
107
+ async clickDeleteAccessButton(accessToDelete) {
108
+ const candidates = typeof accessToDelete === 'string' ? [accessToDelete] : accessToDelete;
109
+ const rowSelector = candidates.map((c) => `:text("${c}")`).join(', ');
110
+ const roleRow = this.page.locator(rowSelector).first();
111
+ for (let attempt = 1; attempt <= 2; attempt++) {
112
+ const rowVisible = await roleRow
113
+ .waitFor({ state: 'visible', timeout: 30000 })
114
+ .then(() => true)
115
+ .catch(() => false);
116
+ if (rowVisible) {
117
+ break;
118
+ }
119
+ await this.page.reload({ waitUntil: 'domcontentloaded' });
120
+ await this.clickAssignedRolesTab();
121
+ }
122
+ await (0, test_1.expect)(roleRow, `No assigned role matching ${candidates
123
+ .map((c) => `"${c}"`)
124
+ .join(' or ')} was found. The role may already be removed, or its ` +
125
+ `label may have changed in this version.`).toBeVisible({ timeout: 60000 });
126
+ // Click the Delete control inside the matched role's own table row. A
127
+ // `td:right-of(:text(...))` spatial match resolves to a neighbouring row's
128
+ // button once the roles table carries rows before the target (Orchestration
129
+ // is ordered above Hub), so it removed the wrong role and left the intended
130
+ // one still assigned.
131
+ await this.page
132
+ .locator('tr')
133
+ .filter({ has: this.page.locator(rowSelector) })
134
+ .first()
135
+ .getByRole('button', { name: 'Delete' })
136
+ .click({ timeout: 60000 });
137
+ }
138
+ async clickConfirmDeleteButton() {
139
+ await (0, test_1.expect)(this.confirmDeleteButton, 'The delete-role confirmation dialog did not appear.').toBeVisible({ timeout: 60000 });
140
+ await this.confirmDeleteButton.click();
141
+ }
142
+ async clickAssignRolesButton() {
143
+ await this.assignRolesButton.click();
144
+ }
145
+ async clickAddButton() {
146
+ await this.addButton.click();
147
+ }
148
+ async clickOptimizeCheckbox() {
149
+ await this.optimizeCheckbox.click();
150
+ }
151
+ async clickModelerCheckbox() {
152
+ await this.modelerCheckbox.click();
153
+ }
154
+ async clickIdentityCheckbox() {
155
+ await this.identityCheckbox.click();
156
+ }
157
+ async clickModelerAdminCheckbox() {
158
+ await this.modelerAdminCheckbox.click();
159
+ }
160
+ async clickUserGroup(name) {
161
+ await this.page.getByRole('cell', { name: name }).click();
162
+ }
163
+ async clickTenantTab() {
164
+ await this.tenantTab.click();
165
+ }
166
+ async clickOpenSidebarButton() {
167
+ await this.openSidebarButton.click({ timeout: 60000 });
168
+ }
169
+ async clickLogoutButton() {
170
+ await this.logoutButton.click({ timeout: 60000 });
171
+ }
172
+ async clickOrchestrationCheckbox() {
173
+ await this.orchestrationCheckbox.click();
174
+ }
175
+ }
176
+ exports.ManagementIdentityPage = ManagementIdentityPage;