@camunda/e2e-test-suite 0.0.1443 → 0.0.1445

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,8 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class ClusterDetailsPage {
3
+ private page;
4
+ readonly clusterDetailsHeading: Locator;
5
+ constructor(page: Page);
6
+ assertCustomPropertyIsNavigated(linkTitle: string, linkName: string, link: string | RegExp): Promise<void>;
7
+ }
8
+ export { ClusterDetailsPage };
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClusterDetailsPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class ClusterDetailsPage {
6
+ page;
7
+ // Custom properties no longer have a heading/section of their own — the
8
+ // Environments/Clusters redesign folds them into the "Cluster details"
9
+ // card as rows (camunda-hub's ClusterDetailFields.sm.tsx), so this is the
10
+ // heading that confirms that card — and the properties inside it — rendered.
11
+ clusterDetailsHeading;
12
+ constructor(page) {
13
+ this.page = page;
14
+ this.clusterDetailsHeading = this.page.getByRole('heading', {
15
+ name: 'Cluster details',
16
+ });
17
+ }
18
+ async assertCustomPropertyIsNavigated(linkTitle, linkName, link) {
19
+ const context = this.page.context();
20
+ const matchesLink = (url) => typeof link === 'string'
21
+ ? url.href.startsWith(link)
22
+ : link.test(url.href);
23
+ // Serve a stub document only when the external site itself is
24
+ // unreachable, so the popup still commits the URL Console navigated to.
25
+ const handler = async (route) => {
26
+ if (route.request().resourceType() !== 'document') {
27
+ await route.continue();
28
+ return;
29
+ }
30
+ try {
31
+ const response = await route.fetch({ timeout: 30000 });
32
+ await route.fulfill({ response });
33
+ }
34
+ catch (error) {
35
+ const url = route.request().url();
36
+ console.warn(`External link ${url} unreachable, stubbing: ${error}`);
37
+ await route.fulfill({
38
+ status: 200,
39
+ contentType: 'text/html',
40
+ body: '<html><body></body></html>',
41
+ });
42
+ }
43
+ };
44
+ await context.route(matchesLink, handler);
45
+ try {
46
+ const pageTabPromise = this.page.waitForEvent('popup', {
47
+ timeout: 60000,
48
+ });
49
+ // Each custom property is a <dt>/<dd> row (direct child of the details
50
+ // card's <dl>), keyed by the property's own description — not by a
51
+ // generic "Link 1"/"Link 2" row title, which this DOM never had.
52
+ await this.page
53
+ .locator('dl > div')
54
+ .filter({ has: this.page.locator('dt', { hasText: linkTitle }) })
55
+ .getByRole('link', { name: linkName, exact: true })
56
+ .click({ timeout: 60000 });
57
+ const camundaPage = await pageTabPromise;
58
+ await (0, test_1.expect)(camundaPage).toHaveURL(link, { timeout: 60000 });
59
+ }
60
+ finally {
61
+ await context.unroute(matchesLink, handler);
62
+ }
63
+ }
64
+ }
65
+ exports.ClusterDetailsPage = ClusterDetailsPage;
@@ -0,0 +1,11 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class ClusterPage {
3
+ private page;
4
+ readonly clustersList: Locator;
5
+ readonly defaultClusterName: string;
6
+ readonly cluster: Locator;
7
+ constructor(page: Page);
8
+ clickClusterLink(): Promise<void>;
9
+ assertCustomTagsAreVisible(tags: string[]): Promise<void>;
10
+ }
11
+ export { ClusterPage };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClusterPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class ClusterPage {
6
+ page;
7
+ clustersList;
8
+ defaultClusterName = process.env.CLUSTER_NAME || 'integration-zeebe';
9
+ cluster;
10
+ constructor(page) {
11
+ this.page = page;
12
+ // The Clusters tab defaults to the card grid (`[data-test="cluster-card"]`),
13
+ // not a table — there is no `tbody` in that view.
14
+ this.clustersList = page.locator('[data-test="cluster-card"]');
15
+ this.cluster = this.clustersList.getByText(this.defaultClusterName).first();
16
+ }
17
+ async clickClusterLink() {
18
+ await (0, test_1.expect)(this.cluster).toBeVisible({ timeout: 60000 });
19
+ await this.cluster.click({ timeout: 30000 });
20
+ await (0, test_1.expect)(this.page.getByText('Cluster details').first()).toBeVisible({
21
+ timeout: 10000,
22
+ });
23
+ }
24
+ async assertCustomTagsAreVisible(tags) {
25
+ // The previous implementation called page.waitForLoadState('networkidle')
26
+ // here. The Console clusters page emits continuous polling/SSE traffic,
27
+ // so networkidle never fires — the test would hang for 12 min then
28
+ // retry, costing ~24 min total. The toBeVisible auto-waits below
29
+ // already cover the readiness window we actually need.
30
+ for (const tag of tags) {
31
+ await (0, test_1.expect)(this.page.getByText(tag, { exact: true }).first()).toBeVisible({
32
+ timeout: 60000,
33
+ });
34
+ }
35
+ }
36
+ }
37
+ exports.ClusterPage = ClusterPage;
@@ -0,0 +1,27 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class ConnectorMarketplacePage {
3
+ private page;
4
+ private browseAllConnectorMarketplacePage;
5
+ private connectorName?;
6
+ private legacyMarketplaceDialog;
7
+ readonly searchForConnectorTextbox: Locator;
8
+ readonly downloadToProjectButton: Locator;
9
+ readonly addToProjectButton: Locator;
10
+ readonly replaceResourceButton: Locator;
11
+ readonly saveAsCopyButton: Locator;
12
+ readonly cancelButton: Locator;
13
+ readonly marketplaceErrorMessage: Locator;
14
+ readonly noResultsMessage: Locator;
15
+ constructor(page: Page);
16
+ clickSearchForConnectorTextbox(): Promise<void>;
17
+ fillSearchForConnectorTextbox(connectorName: string): Promise<void>;
18
+ clickDownloadToProjectButton(): Promise<void>;
19
+ clickCancelButton(): Promise<void>;
20
+ clickReplaceResourceButton(): Promise<void>;
21
+ waitForConnectorSearchResults(): Promise<void>;
22
+ downloadConnectorToProject(): Promise<void>;
23
+ private confirmImport;
24
+ private waitForImportToSettle;
25
+ private getLegacyDownloadButton;
26
+ }
27
+ export { ConnectorMarketplacePage };
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConnectorMarketplacePage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ const BrowseAllConnectorMarketplacePage_1 = require("../BrowseAllConnectorMarketplacePage");
6
+ const sleep_1 = require("../../utils/sleep");
7
+ class ConnectorMarketplacePage {
8
+ page;
9
+ browseAllConnectorMarketplacePage;
10
+ connectorName;
11
+ legacyMarketplaceDialog;
12
+ searchForConnectorTextbox;
13
+ downloadToProjectButton;
14
+ addToProjectButton;
15
+ replaceResourceButton;
16
+ saveAsCopyButton;
17
+ cancelButton;
18
+ marketplaceErrorMessage;
19
+ noResultsMessage;
20
+ constructor(page) {
21
+ this.page = page;
22
+ this.browseAllConnectorMarketplacePage =
23
+ new BrowseAllConnectorMarketplacePage_1.BrowseAllConnectorMarketplacePage(page);
24
+ this.searchForConnectorTextbox =
25
+ this.browseAllConnectorMarketplacePage.searchForConnectorTextbox
26
+ .or(page.getByPlaceholder('Search for a connector'))
27
+ .first();
28
+ this.legacyMarketplaceDialog = page
29
+ .getByRole('dialog', { name: 'Browse Marketplace connectors' })
30
+ .or(page.getByRole('dialog', { name: 'Discover Connectors Dialog' }))
31
+ .first();
32
+ this.downloadToProjectButton = page
33
+ .getByRole('button', { name: 'Download to project' })
34
+ .first();
35
+ this.cancelButton = page.getByRole('button', { name: 'Cancel' });
36
+ this.addToProjectButton = page.getByRole('button', {
37
+ name: 'Add to project',
38
+ });
39
+ this.replaceResourceButton = page.getByRole('button', {
40
+ name: 'Replace resource',
41
+ });
42
+ this.saveAsCopyButton = page.getByRole('button', { name: 'Save as copy' });
43
+ this.marketplaceErrorMessage = page.getByText('an error occurred, please try again later');
44
+ this.noResultsMessage = page.getByText('find a match for your search phrase');
45
+ }
46
+ async clickSearchForConnectorTextbox() {
47
+ await this.searchForConnectorTextbox.click({ timeout: 60000 });
48
+ await (0, sleep_1.sleep)(2000);
49
+ }
50
+ async fillSearchForConnectorTextbox(connectorName) {
51
+ this.connectorName = connectorName;
52
+ await this.searchForConnectorTextbox.fill(connectorName, { timeout: 60000 });
53
+ await (0, sleep_1.sleep)(2000);
54
+ }
55
+ async clickDownloadToProjectButton() {
56
+ await this.getLegacyDownloadButton().click({ timeout: 60000 });
57
+ }
58
+ async clickCancelButton() {
59
+ await this.cancelButton.click({ timeout: 30000 });
60
+ }
61
+ async clickReplaceResourceButton() {
62
+ await this.replaceResourceButton.click({ timeout: 30000 });
63
+ }
64
+ async waitForConnectorSearchResults() {
65
+ if (await this.browseAllConnectorMarketplacePage.isOpen()) {
66
+ await this.browseAllConnectorMarketplacePage.waitForConnectorSearchResult(this.connectorName);
67
+ return;
68
+ }
69
+ const MAX_RETRIES = 4;
70
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
71
+ const downloadButton = this.getLegacyDownloadButton();
72
+ await (0, test_1.expect)(downloadButton
73
+ .or(this.marketplaceErrorMessage)
74
+ .or(this.noResultsMessage)).toBeVisible({ timeout: 60000 });
75
+ if (await downloadButton.isVisible()) {
76
+ return;
77
+ }
78
+ console.log(`Marketplace search attempt ${attempt} of ${MAX_RETRIES} returned an error or no results. Retrying search...`);
79
+ if (attempt < MAX_RETRIES) {
80
+ // The marketplace search API returns transient 5xx. Back off for
81
+ // growing intervals before re-issuing the query so a short outage
82
+ // self-heals instead of burning all attempts inside a few seconds.
83
+ await (0, sleep_1.sleep)(attempt * 5000);
84
+ const searchText = await this.searchForConnectorTextbox.inputValue();
85
+ await this.searchForConnectorTextbox.clear();
86
+ await (0, sleep_1.sleep)(2000);
87
+ await this.searchForConnectorTextbox.fill(searchText);
88
+ await (0, sleep_1.sleep)(2000);
89
+ }
90
+ }
91
+ throw new Error('Marketplace connector search failed after retries due to persistent error or no matching results');
92
+ }
93
+ async downloadConnectorToProject() {
94
+ if (await this.browseAllConnectorMarketplacePage.isOpen()) {
95
+ await this.browseAllConnectorMarketplacePage.importConnectorToProject(this.connectorName);
96
+ return;
97
+ }
98
+ await this.clickDownloadToProjectButton();
99
+ if (await this.confirmImport()) {
100
+ return;
101
+ }
102
+ // The modal is up but rendered none of the known import actions. Dismiss it
103
+ // so it does not block the next click on the diagram, then fail here:
104
+ // continuing would leave the diagram's connector template unresolved
105
+ // ("Template: Not found") and only surface 60s later as a missing
106
+ // properties-panel group, pointing at the wrong step.
107
+ if (await this.cancelButton.isVisible().catch(() => false)) {
108
+ await this.cancelButton.click({ timeout: 20000 });
109
+ throw new Error('Connector import modal offered no import action ("Add to project", "Replace resource" or "Save as copy"); the import was abandoned.');
110
+ }
111
+ // Hub imported without asking for confirmation, so the write is in flight
112
+ // here too.
113
+ await this.waitForImportToSettle();
114
+ }
115
+ // Hub's import modal labels its primary button after the project state:
116
+ // "Add to project" when the template is new to the project, "Replace
117
+ // resource" when the same template is already there, "Save as copy" on a
118
+ // conflicting version. Probe them in order and click the one actually
119
+ // rendered; clicking "Cancel" instead abandons the import and leaves the
120
+ // diagram's connector template unresolved ("Template: Not found"), which
121
+ // only surfaces much later as a missing properties-panel group.
122
+ async confirmImport() {
123
+ const importButtons = [
124
+ this.addToProjectButton,
125
+ this.replaceResourceButton,
126
+ this.saveAsCopyButton,
127
+ ];
128
+ // Carbon animates the modal in, so a click issued mid-transition is
129
+ // rejected ("element is not stable") and by the next Playwright retry the
130
+ // button can already be gone; keep probing the labels until one click
131
+ // actually lands instead of burning the whole budget on a single button.
132
+ const deadline = Date.now() + 45000;
133
+ do {
134
+ for (const button of importButtons) {
135
+ if (!(await button.isVisible().catch(() => false))) {
136
+ continue;
137
+ }
138
+ // Register the waiter before the click: the write can be acknowledged
139
+ // before the modal finishes unmounting.
140
+ const templateWritten = this.page
141
+ .waitForResponse((response) => response.request().method() === 'POST' &&
142
+ response.url().includes('/internal/files'), { timeout: 30000 })
143
+ .catch(() => null);
144
+ const clicked = await button
145
+ .click({ timeout: 5000 })
146
+ .then(() => true)
147
+ .catch(() => false);
148
+ if (!clicked) {
149
+ continue;
150
+ }
151
+ await (0, test_1.expect)(button).toBeHidden({ timeout: 60000 });
152
+ const written = await templateWritten;
153
+ // A rejected write leaves the project without the template just like
154
+ // an aborted one, so surface the status here instead of letting it
155
+ // resurface 60s later as a missing "Authentication" group in
156
+ // ModelerCreatePage.
157
+ if (written && !written.ok()) {
158
+ throw new Error(`Connector template import failed: writing it into the project returned HTTP ${written.status()}.`);
159
+ }
160
+ await this.waitForImportToSettle();
161
+ return true;
162
+ }
163
+ await (0, sleep_1.sleep)(1000);
164
+ } while (Date.now() < deadline);
165
+ return false;
166
+ }
167
+ // Hub unmounts the ImportModal as soon as the click is handled, but writes the
168
+ // template into the project with a POST that is still in flight at that point.
169
+ // Returning right after the button hides let the caller's `page.reload()`
170
+ // abort that write ~20ms later, leaving the project's connector-template list
171
+ // empty and every templated task on the diagram at "Template: Not found" --
172
+ // the properties panel then never renders the "Authentication" group.
173
+ async waitForImportToSettle() {
174
+ await this.page.waitForLoadState('networkidle').catch(() => { });
175
+ }
176
+ getLegacyDownloadButton() {
177
+ if (!this.connectorName) {
178
+ return this.downloadToProjectButton;
179
+ }
180
+ return this.legacyMarketplaceDialog
181
+ .getByText(this.connectorName, { exact: true })
182
+ .first()
183
+ .locator('xpath=ancestor::*[.//button[normalize-space()="Download to project"]][1]')
184
+ .getByRole('button', { name: 'Download to project' });
185
+ }
186
+ }
187
+ exports.ConnectorMarketplacePage = ConnectorMarketplacePage;
@@ -0,0 +1,41 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class ConnectorSettingsPage {
3
+ private page;
4
+ readonly urlInput: Locator;
5
+ readonly resultExpressionInput: Locator;
6
+ readonly authenticationTypeDropdown: Locator;
7
+ readonly usernameInput: Locator;
8
+ readonly passwordInput: Locator;
9
+ readonly methodTypeDropdown: Locator;
10
+ readonly resultVariableInput: Locator;
11
+ readonly bearerTokenInput: Locator;
12
+ readonly authenticationTab: Locator;
13
+ readonly outputMappingTab: Locator;
14
+ readonly httpEndpointTab: Locator;
15
+ readonly correlationTab: Locator;
16
+ readonly inputTab: Locator;
17
+ readonly webhookConfigurationTab: Locator;
18
+ constructor(page: Page);
19
+ clickUrlInput(): Promise<void>;
20
+ fillUrlInput(url: string): Promise<void>;
21
+ clickResultExpressionInput(): Promise<void>;
22
+ fillResultExpressionInput(resultExpression: string): Promise<void>;
23
+ selectAuthenticationType(authentication: string): Promise<void>;
24
+ clickUsernameInput(): Promise<void>;
25
+ fillUsernameInput(username: string): Promise<void>;
26
+ clickPasswordInput(): Promise<void>;
27
+ fillPasswordInput(password: string): Promise<void>;
28
+ selectMethodType(method: string): Promise<void>;
29
+ clickResultVariableInput(): Promise<void>;
30
+ fillResultVariableInput(variable: string): Promise<void>;
31
+ clickBearerTokenInput(): Promise<void>;
32
+ fillBearerTokenInput(token: string): Promise<void>;
33
+ private clickTabWithRetry;
34
+ clickAuthenticationTab(): Promise<void>;
35
+ clickOutputMappingTab(): Promise<void>;
36
+ clickHTTPEndpointTab(): Promise<void>;
37
+ clickCorrelationTab(): Promise<void>;
38
+ clickInputTab(): Promise<void>;
39
+ clickWebhookConfigurationTab(): Promise<void>;
40
+ }
41
+ export { ConnectorSettingsPage };
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConnectorSettingsPage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class ConnectorSettingsPage {
6
+ page;
7
+ urlInput;
8
+ resultExpressionInput;
9
+ authenticationTypeDropdown;
10
+ usernameInput;
11
+ passwordInput;
12
+ methodTypeDropdown;
13
+ resultVariableInput;
14
+ bearerTokenInput;
15
+ authenticationTab;
16
+ outputMappingTab;
17
+ httpEndpointTab;
18
+ correlationTab;
19
+ inputTab;
20
+ webhookConfigurationTab;
21
+ constructor(page) {
22
+ this.page = page;
23
+ this.urlInput = page.getByLabel('URL');
24
+ this.resultExpressionInput = page.getByLabel('Result expression');
25
+ this.authenticationTypeDropdown = page.getByLabel('Type');
26
+ this.usernameInput = page.getByLabel('Username');
27
+ this.passwordInput = page.getByLabel('Password', { exact: true });
28
+ this.methodTypeDropdown = page.getByLabel('Method');
29
+ this.resultVariableInput = page.getByLabel('Result variable');
30
+ this.bearerTokenInput = page.getByLabel('Bearer token');
31
+ this.authenticationTab = page
32
+ .locator('div')
33
+ .filter({ hasText: /^Authentication$/ })
34
+ .first();
35
+ this.outputMappingTab = page
36
+ .locator('div')
37
+ .filter({ hasText: /^Output mapping$/ })
38
+ .first();
39
+ this.httpEndpointTab = page
40
+ .locator('div')
41
+ .filter({ hasText: /^HTTP endpoint$/ })
42
+ .first();
43
+ this.correlationTab = page
44
+ .locator('div')
45
+ .filter({ hasText: /^Correlation$/ })
46
+ .first();
47
+ this.inputTab = page
48
+ .locator('div')
49
+ .filter({ hasText: /^Input$/ })
50
+ .first();
51
+ this.webhookConfigurationTab = page
52
+ .locator('div')
53
+ .filter({ hasText: /^Webhook configuration$/ })
54
+ .first();
55
+ }
56
+ async clickUrlInput() {
57
+ try {
58
+ await this.urlInput.click({ timeout: 60000 });
59
+ }
60
+ catch {
61
+ await this.httpEndpointTab.click();
62
+ await this.urlInput.click({ timeout: 60000 });
63
+ }
64
+ }
65
+ async fillUrlInput(url) {
66
+ await this.urlInput.fill(url);
67
+ await (0, test_1.expect)(this.page.getByText('URL must not be empty.')).not.toBeVisible({ timeout: 30000 });
68
+ }
69
+ async clickResultExpressionInput() {
70
+ try {
71
+ await this.resultExpressionInput.click();
72
+ }
73
+ catch {
74
+ await this.clickOutputMappingTab();
75
+ await this.resultExpressionInput.click();
76
+ }
77
+ }
78
+ async fillResultExpressionInput(resultExpression) {
79
+ await this.resultExpressionInput.fill(resultExpression);
80
+ }
81
+ async selectAuthenticationType(authentication) {
82
+ await this.authenticationTypeDropdown.selectOption(authentication);
83
+ }
84
+ async clickUsernameInput() {
85
+ await this.usernameInput.click({ timeout: 30000 });
86
+ }
87
+ async fillUsernameInput(username) {
88
+ await this.usernameInput.fill(username, { timeout: 30000 });
89
+ await (0, test_1.expect)(this.page.getByText('Username must not be empty.')).not.toBeVisible({ timeout: 30000 });
90
+ }
91
+ async clickPasswordInput() {
92
+ await this.passwordInput.click();
93
+ }
94
+ async fillPasswordInput(password) {
95
+ await this.passwordInput.fill(password);
96
+ await (0, test_1.expect)(this.page.getByText('Password must not be empty.')).not.toBeVisible({ timeout: 30000 });
97
+ }
98
+ async selectMethodType(method) {
99
+ await this.methodTypeDropdown.selectOption(method, { timeout: 60000 });
100
+ }
101
+ async clickResultVariableInput() {
102
+ await this.resultVariableInput.click();
103
+ }
104
+ async fillResultVariableInput(variable) {
105
+ await this.resultVariableInput.fill(variable);
106
+ }
107
+ async clickBearerTokenInput() {
108
+ await this.bearerTokenInput.click({ timeout: 30000 });
109
+ }
110
+ async fillBearerTokenInput(token) {
111
+ await this.bearerTokenInput.fill(token);
112
+ await (0, test_1.expect)(this.page.getByText('Bearer token must not be empty.')).not.toBeVisible({ timeout: 30000 });
113
+ }
114
+ // Connector settings tabs can take several seconds to render on slower clusters
115
+ // after the element type is changed. Each clickXxxTab method retries with a
116
+ // reload-free wait so a single slow render doesn't cause a hard timeout failure.
117
+ async clickTabWithRetry(tab, tabName, maxAttempts = 3) {
118
+ let lastError;
119
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
120
+ try {
121
+ await (0, test_1.expect)(tab).toBeVisible({ timeout: 30000 });
122
+ await tab.click({ timeout: 30000 });
123
+ return;
124
+ }
125
+ catch (err) {
126
+ lastError = err;
127
+ console.warn(`clickTabWithRetry: "${tabName}" attempt ${attempt + 1}/${maxAttempts} failed: ${err instanceof Error ? err.message : err}`);
128
+ }
129
+ }
130
+ throw lastError instanceof Error
131
+ ? lastError
132
+ : new Error(`Tab "${tabName}" not clickable after ${maxAttempts} attempts`);
133
+ }
134
+ async clickAuthenticationTab() {
135
+ await this.clickTabWithRetry(this.authenticationTab, 'Authentication');
136
+ }
137
+ async clickOutputMappingTab() {
138
+ await this.clickTabWithRetry(this.outputMappingTab, 'Output mapping');
139
+ }
140
+ async clickHTTPEndpointTab() {
141
+ await this.clickTabWithRetry(this.httpEndpointTab, 'HTTP endpoint');
142
+ }
143
+ async clickCorrelationTab() {
144
+ await this.clickTabWithRetry(this.correlationTab, 'Correlation');
145
+ }
146
+ async clickInputTab() {
147
+ await this.clickTabWithRetry(this.inputTab, 'Input');
148
+ }
149
+ async clickWebhookConfigurationTab() {
150
+ await this.clickTabWithRetry(this.webhookConfigurationTab, 'Webhook configuration');
151
+ }
152
+ }
153
+ exports.ConnectorSettingsPage = ConnectorSettingsPage;
@@ -0,0 +1,11 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class ConnectorTemplatePage {
3
+ private page;
4
+ readonly publishToOrgButton: Locator;
5
+ readonly publishButton: Locator;
6
+ constructor(page: Page);
7
+ clickPublishToOrgButton(): Promise<void>;
8
+ clickPublishButton(): Promise<void>;
9
+ publishConnector(): Promise<void>;
10
+ }
11
+ export { ConnectorTemplatePage };
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConnectorTemplatePage = void 0;
4
+ const test_1 = require("@playwright/test");
5
+ class ConnectorTemplatePage {
6
+ page;
7
+ publishToOrgButton;
8
+ publishButton;
9
+ constructor(page) {
10
+ this.page = page;
11
+ this.publishButton = page.getByRole('button', {
12
+ name: 'Publish',
13
+ exact: true,
14
+ });
15
+ this.publishToOrgButton = page.locator('[data-test="publish-to-org"]');
16
+ }
17
+ async clickPublishToOrgButton() {
18
+ await this.publishToOrgButton.click({ timeout: 90000 });
19
+ }
20
+ async clickPublishButton() {
21
+ await this.publishButton.click({ timeout: 90000 });
22
+ }
23
+ async publishConnector() {
24
+ try {
25
+ await (0, test_1.expect)(this.publishToOrgButton).toBeVisible({ timeout: 15000 });
26
+ }
27
+ catch (error) {
28
+ return;
29
+ }
30
+ await this.clickPublishToOrgButton();
31
+ await this.clickPublishButton();
32
+ }
33
+ }
34
+ exports.ConnectorTemplatePage = ConnectorTemplatePage;
@@ -0,0 +1,33 @@
1
+ import { Page, Locator } from '@playwright/test';
2
+ declare class FormJsPage {
3
+ private page;
4
+ readonly aiFormGeneratorButton: Locator;
5
+ readonly formRequestInput: Locator;
6
+ readonly generateFormButton: Locator;
7
+ readonly formEditor: Locator;
8
+ readonly filePicker: Locator;
9
+ readonly generalPanel: Locator;
10
+ readonly keyInput: Locator;
11
+ readonly uploadMultipleFilesToggle: Locator;
12
+ readonly documentReferenceInput: Locator;
13
+ readonly documentPreview: Locator;
14
+ readonly deployDialog: Locator;
15
+ readonly deployFormButton: Locator;
16
+ readonly deployModalSubmitButton: Locator;
17
+ readonly deploySuccessNotification: Locator;
18
+ constructor(page: Page);
19
+ clickAIFormGeneratorButton(): Promise<void>;
20
+ clickFormRequestInput(): Promise<void>;
21
+ fillFormRequestInput(formRequest: string): Promise<void>;
22
+ clickGenerateFormButton(): Promise<void>;
23
+ dragAndDrop(source: Locator, target: Locator): Promise<void>;
24
+ clickGeneralPropertiesPanel(): Promise<void>;
25
+ fillKeyInput(key: string): Promise<void>;
26
+ enableUploadMultipleFiles(): Promise<void>;
27
+ filldocumentReferenceInput(key: string): Promise<void>;
28
+ clickDeployFormButton(): Promise<void>;
29
+ clickDeployModalSubmitButton(): Promise<void>;
30
+ selectOnlyThisResource(): Promise<void>;
31
+ deployForm(): Promise<void>;
32
+ }
33
+ export { FormJsPage };