@camunda/e2e-test-suite 0.0.1276 → 0.0.1278
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.
- package/dist/pages/8.8/AppsPage.d.ts +4 -0
- package/dist/pages/8.8/AppsPage.js +209 -22
- package/dist/pages/8.8/ClusterDetailsPage.d.ts +9 -0
- package/dist/pages/8.8/ClusterDetailsPage.js +154 -3
- package/dist/pages/8.8/ClusterPage.d.ts +1 -0
- package/dist/pages/8.8/ClusterPage.js +49 -20
- package/dist/pages/8.8/ConnectorMarketplacePage.d.ts +2 -0
- package/dist/pages/8.8/ConnectorMarketplacePage.js +44 -2
- package/dist/pages/8.8/ConsoleOrganizationPage.js +63 -18
- package/dist/pages/8.8/FormJsPage.d.ts +4 -0
- package/dist/pages/8.8/FormJsPage.js +31 -1
- package/dist/pages/8.8/ModelerCreatePage.d.ts +3 -0
- package/dist/pages/8.8/ModelerCreatePage.js +167 -18
- package/dist/pages/8.8/PlayPage.js +14 -3
- package/dist/pages/8.8/SettingsPage.js +19 -2
- package/dist/pages/8.8/UtilitiesPage.js +43 -3
- package/dist/pages/8.8/WorkspaceMembersPage.d.ts +20 -0
- package/dist/pages/8.8/WorkspaceMembersPage.js +258 -0
- package/dist/tests/8.8/access-user-role-management.spec.js +95 -0
- package/dist/tests/8.8/console-user-flows.spec.js +6 -0
- package/dist/tests/8.8/web-modeler-user-flows.spec.js +6 -2
- package/dist/utils/consoleApiHelpers.js +38 -11
- package/package.json +1 -1
|
@@ -82,28 +82,32 @@ class ClusterPage {
|
|
|
82
82
|
});
|
|
83
83
|
this.clusterVersionOption = page.getByText(`${process.env.CLUSTER_VERSION}`, { exact: true });
|
|
84
84
|
this.generationSearchInput = page.getByPlaceholder('Search generations');
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.
|
|
89
|
-
|
|
90
|
-
});
|
|
91
|
-
this.
|
|
85
|
+
// Camunda Hub's create-cluster form replaced the Carbon tiles (a <label>
|
|
86
|
+
// per option) and tabs with design-system choice cards and toggle groups,
|
|
87
|
+
// all exposed as role="radio" named by their title. Each locator below
|
|
88
|
+
// accepts either shape via this helper. Ported from
|
|
89
|
+
// pages/8.10/ClusterPage.ts (#3730), where the same change was made.
|
|
90
|
+
const choice = (legacy, name) => legacy.or(page.getByRole('radio', { name, exact: true }));
|
|
91
|
+
this.g3DevClusterType = choice(page.locator('label').filter({ hasText: this.defaultClusterType }), this.defaultClusterType);
|
|
92
|
+
this.londonRegion = choice(page.locator('label').filter({ hasText: 'London, Europe (europe-west2)' }), 'London, Europe (europe-west2)');
|
|
93
|
+
this.ohioRegion = choice(page.locator('label').filter({
|
|
92
94
|
hasText: 'Ohio, North America (us-east-2)',
|
|
93
|
-
});
|
|
94
|
-
this.belgiumRegion = page.locator('label').filter({
|
|
95
|
+
}), 'Ohio, North America (us-east-2)');
|
|
96
|
+
this.belgiumRegion = choice(page.locator('label').filter({
|
|
95
97
|
hasText: 'Chaos, Belgium, Europe (europe-west1)',
|
|
96
|
-
});
|
|
97
|
-
this.finlandRegion = page.locator('label').filter({
|
|
98
|
+
}), 'Chaos, Belgium, Europe (europe-west1)');
|
|
99
|
+
this.finlandRegion = choice(page.locator('label').filter({
|
|
98
100
|
hasText: 'Finland, Europe (europe-north1)',
|
|
99
|
-
});
|
|
100
|
-
this.alphaTab = page.getByRole('tab', { name: 'Alpha' });
|
|
101
|
-
this.devTab = page.getByRole('tab', { name: 'Internal Dev' });
|
|
102
|
-
this.stableTab = page.getByRole('tab', { name: 'Stable' });
|
|
103
|
-
this.qaGenerationsTab = page.getByRole('tab', { name: 'QA Generations' });
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
}), 'Finland, Europe (europe-north1)');
|
|
102
|
+
this.alphaTab = choice(page.getByRole('tab', { name: 'Alpha' }), 'Alpha');
|
|
103
|
+
this.devTab = choice(page.getByRole('tab', { name: 'Internal Dev' }), 'Internal Dev');
|
|
104
|
+
this.stableTab = choice(page.getByRole('tab', { name: 'Stable' }), 'Stable');
|
|
105
|
+
this.qaGenerationsTab = choice(page.getByRole('tab', { name: 'QA Generations' }), 'QA Generations');
|
|
106
|
+
// The cloud-provider picker is a design-system toggle group, not tabs:
|
|
107
|
+
// a nightly trace's DOM has
|
|
108
|
+
// <button role="radio" aria-checked="true" data-slot="toggle-group-item">GCP</button>
|
|
109
|
+
// inside a role="radiogroup", and no role="tab" anywhere on the form.
|
|
110
|
+
this.gcpRegion = choice(page.getByRole('tab', { name: 'GCP' }), 'GCP');
|
|
107
111
|
this.clustersList = page
|
|
108
112
|
.getByRole('row')
|
|
109
113
|
.filter({ hasNotText: 'Generation' }); //Filter out header row
|
|
@@ -224,6 +228,15 @@ class ClusterPage {
|
|
|
224
228
|
visibilityTimeout: 20000,
|
|
225
229
|
totalTimeout: 80000,
|
|
226
230
|
postAction: async () => {
|
|
231
|
+
// The clusters route intermittently answers with an Envoy gateway
|
|
232
|
+
// error ("upstream connect error or disconnect/reset before headers.
|
|
233
|
+
// reset reason: connection timeout"), which renders as a bare text
|
|
234
|
+
// document -- clicking the banner cannot recover that, so every
|
|
235
|
+
// remaining attempt retried against a dead page. Reload first, then
|
|
236
|
+
// fall back to the banner for the ordinary not-yet-navigated case.
|
|
237
|
+
await this.page
|
|
238
|
+
.reload({ waitUntil: 'domcontentloaded', timeout: 30000 })
|
|
239
|
+
.catch(() => { });
|
|
227
240
|
await this.clickClusterBanner();
|
|
228
241
|
},
|
|
229
242
|
});
|
|
@@ -276,7 +289,7 @@ class ClusterPage {
|
|
|
276
289
|
await this.clickClusterNameInput();
|
|
277
290
|
await this.fillClusterNameInput(name);
|
|
278
291
|
await this.clickClusterType();
|
|
279
|
-
await this.
|
|
292
|
+
await this.clickProviderOption(region);
|
|
280
293
|
await this.selectSubRegion(region);
|
|
281
294
|
await this.clickClusterOption(process.env.CLUSTER_VERSION);
|
|
282
295
|
await this.determineTasklistAPI(tasklistV1Api);
|
|
@@ -284,6 +297,22 @@ class ClusterPage {
|
|
|
284
297
|
await this.logClusterCreationInfo(name);
|
|
285
298
|
await this.clickClustersBreadcrumb(name);
|
|
286
299
|
}
|
|
300
|
+
// Selects the cloud provider ("GCP"/"AWS"). Hub renders the picker as a
|
|
301
|
+
// toggle group of role="radio" buttons rather than tabs, and it arrives with
|
|
302
|
+
// GCP already selected -- so a `role=tab` click both targeted nothing and
|
|
303
|
+
// was unnecessary. Accept either shape and skip the click when the option is
|
|
304
|
+
// already the selected one.
|
|
305
|
+
async clickProviderOption(region) {
|
|
306
|
+
const providerOption = this.page
|
|
307
|
+
.getByRole('tab', { name: region })
|
|
308
|
+
.or(this.page.getByRole('radio', { name: region, exact: true }))
|
|
309
|
+
.first();
|
|
310
|
+
await (0, test_1.expect)(providerOption).toBeVisible({ timeout: 40000 });
|
|
311
|
+
if ((await providerOption.getAttribute('aria-checked')) === 'true') {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
await providerOption.click({ timeout: 30000 });
|
|
315
|
+
}
|
|
287
316
|
async selectSubRegion(region) {
|
|
288
317
|
if (region === 'GCP') {
|
|
289
318
|
if (process.env.IS_PROD == 'true') {
|
|
@@ -8,7 +8,9 @@ declare class ConnectorMarketplacePage {
|
|
|
8
8
|
readonly replaceResourceButton: Locator;
|
|
9
9
|
readonly addToProjectButton: Locator;
|
|
10
10
|
readonly saveAsCopyButton: Locator;
|
|
11
|
+
readonly cancelButton: Locator;
|
|
11
12
|
readonly importModal: Locator;
|
|
13
|
+
readonly browseAllMarketplaceDetailsButton: Locator;
|
|
12
14
|
constructor(page: Page);
|
|
13
15
|
clickSearchForConnectorTextbox(): Promise<void>;
|
|
14
16
|
fillSearchForConnectorTextbox(connectorName: string): Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ConnectorMarketplacePage = void 0;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
4
5
|
class ConnectorMarketplacePage {
|
|
5
6
|
page;
|
|
6
7
|
searchForConnectorTextbox;
|
|
@@ -10,10 +11,27 @@ class ConnectorMarketplacePage {
|
|
|
10
11
|
replaceResourceButton;
|
|
11
12
|
addToProjectButton;
|
|
12
13
|
saveAsCopyButton;
|
|
14
|
+
cancelButton;
|
|
13
15
|
importModal;
|
|
16
|
+
browseAllMarketplaceDetailsButton;
|
|
14
17
|
constructor(page) {
|
|
15
18
|
this.page = page;
|
|
16
|
-
|
|
19
|
+
// The legacy marketplace modal, or camunda-hub's "Browse all" dialog,
|
|
20
|
+
// which lists Marketplace connectors alongside the diagram's own elements
|
|
21
|
+
// and reusable assets. Same shape as pages/8.7.
|
|
22
|
+
this.searchForConnectorTextbox = page
|
|
23
|
+
.getByPlaceholder('Search for a connector')
|
|
24
|
+
.or(page.locator('#browse-all-search'))
|
|
25
|
+
.or(page.getByRole('searchbox', {
|
|
26
|
+
name: 'Search elements and reusable assets',
|
|
27
|
+
}))
|
|
28
|
+
.first();
|
|
29
|
+
// A Browse all Marketplace card opens its review step ("Add to project")
|
|
30
|
+
// through this button; self-hosted connectors only link to setup docs.
|
|
31
|
+
this.browseAllMarketplaceDetailsButton = page
|
|
32
|
+
.getByRole('list', { name: 'Marketplace connectors' })
|
|
33
|
+
.getByRole('button', { name: /^View details for .+ from Marketplace$/ })
|
|
34
|
+
.first();
|
|
17
35
|
this.downloadToProjectButton = page
|
|
18
36
|
.getByRole('button', { name: 'Download to project' })
|
|
19
37
|
.first();
|
|
@@ -26,6 +44,7 @@ class ConnectorMarketplacePage {
|
|
|
26
44
|
name: 'Add to project',
|
|
27
45
|
});
|
|
28
46
|
this.saveAsCopyButton = page.getByRole('button', { name: 'Save as copy' });
|
|
47
|
+
this.cancelButton = page.getByRole('button', { name: 'Cancel' });
|
|
29
48
|
this.importModal = page.locator('[data-test="import-modal"]');
|
|
30
49
|
}
|
|
31
50
|
async clickSearchForConnectorTextbox() {
|
|
@@ -47,7 +66,30 @@ class ConnectorMarketplacePage {
|
|
|
47
66
|
await this.replaceResourceButton.click({ timeout: 60000 });
|
|
48
67
|
}
|
|
49
68
|
async downloadConnectorToProject() {
|
|
50
|
-
|
|
69
|
+
// Browse all has no "Download to project": a result is a card that opens
|
|
70
|
+
// its own review step, which is where the import action lives. Wait for
|
|
71
|
+
// whichever entry point this shell renders before deciding -- isVisible()
|
|
72
|
+
// never waits, so probing it straight away raced the dialog's own render
|
|
73
|
+
// and fell through both branches.
|
|
74
|
+
await (0, test_1.expect)(this.downloadToProjectButton
|
|
75
|
+
.or(this.browseAllMarketplaceDetailsButton)
|
|
76
|
+
.first()).toBeVisible({ timeout: 60000 });
|
|
77
|
+
if (await this.downloadToProjectButton.isVisible()) {
|
|
78
|
+
await this.clickDownloadToProjectButton();
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
await this.browseAllMarketplaceDetailsButton.click({ timeout: 30000 });
|
|
82
|
+
}
|
|
83
|
+
// The Browse all review step fetches the connector's details before it
|
|
84
|
+
// renders "Add to project". Let one of the outcomes render before the
|
|
85
|
+
// probes below, which would otherwise repeat that same race.
|
|
86
|
+
await this.addToProjectButton
|
|
87
|
+
.or(this.replaceResourceButton)
|
|
88
|
+
.or(this.saveAsCopyButton)
|
|
89
|
+
.or(this.cancelButton)
|
|
90
|
+
.first()
|
|
91
|
+
.waitFor({ state: 'visible', timeout: 60000 })
|
|
92
|
+
.catch(() => { });
|
|
51
93
|
// "Download to project" opens Web Modeler's "Import resource" modal, which
|
|
52
94
|
// can take ~20s to appear. The import-confirming button depends on whether
|
|
53
95
|
// the connector template already exists in the project: an existing one
|
|
@@ -43,20 +43,44 @@ class ConsoleOrganizationPage {
|
|
|
43
43
|
constructor(page) {
|
|
44
44
|
this.page = page;
|
|
45
45
|
this.usersTab = page.getByRole('tab', { name: 'Users' });
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.getByRole('
|
|
54
|
-
.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
46
|
+
// Hub's org-management Users table is a design-system data table whose
|
|
47
|
+
// per-row action affordance is a kebab named "Row actions", not Carbon's
|
|
48
|
+
// "Options" -- a nightly screenshot shows the kebab and the trace has no
|
|
49
|
+
// "Options" node at all. Scoped to the visible tab panel so another tab's
|
|
50
|
+
// rows cannot match. Same shape as pages/8.9.
|
|
51
|
+
this.optionsButton = page
|
|
52
|
+
.getByRole('button', { name: 'Options' })
|
|
53
|
+
.or(page.getByRole('tabpanel').getByRole('button', { name: 'Row actions' }))
|
|
54
|
+
.first();
|
|
55
|
+
this.editUserMenuItem = page.getByRole('menuitem', {
|
|
56
|
+
name: /^Edit user$/i,
|
|
57
|
+
});
|
|
58
|
+
// The "Edit user" dialog's role toggles are plain Carbon Checkboxes
|
|
59
|
+
// (@camunda/ccma-saas-frontend c4-user-details-page.tsx), each its own
|
|
60
|
+
// labelText-bound <input type="checkbox">, not a role="group" of
|
|
61
|
+
// <label>s -- there is no group wrapper around them at all. Scoped to
|
|
62
|
+
// whichever dialog is open rather than one named "Edit user": a modal
|
|
63
|
+
// whose heading isn't wired via aria-labelledby carries no accessible
|
|
64
|
+
// name at all, which silently zeroes out a name-matched dialog locator.
|
|
65
|
+
const openDialog = page.getByRole('dialog');
|
|
66
|
+
// Hub renamed the platform roles, and the "Edit user" dialog states each
|
|
67
|
+
// mapping in the role's own description (confirmed live against the
|
|
68
|
+
// nightly org): "Member ... Formerly the Modeler role.",
|
|
69
|
+
// "Organization Admin ... Formerly the Admin role.", "DevOps ... Formerly
|
|
70
|
+
// the Operations Engineer role."; Analyst is unchanged. There is no
|
|
71
|
+
// "Modeler" checkbox at all any more, which is why the exact-name lookup
|
|
72
|
+
// resolved to nothing.
|
|
73
|
+
//
|
|
74
|
+
// Anchored regex rather than `exact`: each checkbox's accessible name
|
|
75
|
+
// carries that description after the label, so an exact match on the bare
|
|
76
|
+
// role name would miss it.
|
|
77
|
+
const roleCheckbox = (current, legacy) => openDialog
|
|
78
|
+
.getByRole('checkbox', { name: current })
|
|
79
|
+
.or(openDialog.getByRole('checkbox', { name: legacy, exact: true }))
|
|
80
|
+
.first();
|
|
81
|
+
this.modelerCheckbox = roleCheckbox(/^Member\b/, 'Modeler');
|
|
82
|
+
this.adminCheckbox = roleCheckbox(/^Organization Admin\b/, 'Admin');
|
|
83
|
+
this.analystCheckbox = roleCheckbox(/^Analyst\b/, 'Analyst');
|
|
60
84
|
this.confirmButton = page.getByRole('button', { name: 'Confirm' });
|
|
61
85
|
this.settingsTab = page.getByRole('tab', { name: 'Settings' });
|
|
62
86
|
this.optInButton = page.getByRole('button', { name: 'Opt-in', exact: true });
|
|
@@ -118,9 +142,16 @@ class ConsoleOrganizationPage {
|
|
|
118
142
|
name: 'danger',
|
|
119
143
|
})
|
|
120
144
|
.last();
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
145
|
+
// Hub's org-management "Users" tab renders its table filter as a
|
|
146
|
+
// design-system <input type="search" placeholder="Search"
|
|
147
|
+
// aria-label="Search">, not Carbon's "Filter table" -- confirmed from a
|
|
148
|
+
// nightly trace's DOM snapshot, where "Filter table" occurs only inside
|
|
149
|
+
// our own call log. Keep the legacy name as a fallback. Same shape as
|
|
150
|
+
// pages/8.9.
|
|
151
|
+
this.filterTableSearchbox = page
|
|
152
|
+
.getByRole('searchbox', { name: 'Search', exact: true })
|
|
153
|
+
.or(page.getByRole('searchbox', { name: 'Filter table' }))
|
|
154
|
+
.first();
|
|
124
155
|
}
|
|
125
156
|
async filterTable(names) {
|
|
126
157
|
for (const name of names) {
|
|
@@ -189,7 +220,21 @@ class ConsoleOrganizationPage {
|
|
|
189
220
|
await this.optionsButton.click({ timeout: 60000 });
|
|
190
221
|
}
|
|
191
222
|
async clickEditUserMenuItem() {
|
|
192
|
-
|
|
223
|
+
// Hub's row menu is a Radix dropdown that animates in and re-mounts its
|
|
224
|
+
// items while opening. A live run against the nightly org resolved this
|
|
225
|
+
// item correctly -- <div role="menuitem" data-slot="dropdown-menu-item">
|
|
226
|
+
// Edit user</div> -- and still failed the click: "element is not stable"
|
|
227
|
+
// twice, then "element was detached from the DOM, retrying" until the 60s
|
|
228
|
+
// budget ran out. A detached item means the menu itself went away, so
|
|
229
|
+
// clicking harder cannot help; re-open it and retry the pair as one unit,
|
|
230
|
+
// gated on the dialog actually opening.
|
|
231
|
+
await (0, test_1.expect)(async () => {
|
|
232
|
+
if (!(await this.editUserMenuItem.isVisible().catch(() => false))) {
|
|
233
|
+
await this.clickOptionsButton();
|
|
234
|
+
}
|
|
235
|
+
await this.editUserMenuItem.click({ timeout: 10000 });
|
|
236
|
+
await (0, test_1.expect)(this.dialog.first()).toBeVisible({ timeout: 10000 });
|
|
237
|
+
}).toPass({ timeout: 120000, intervals: [1000, 2000, 5000] });
|
|
193
238
|
}
|
|
194
239
|
async checkModelerCheckbox() {
|
|
195
240
|
if (!(await this.modelerCheckbox.isChecked({ timeout: 60000 }))) {
|
|
@@ -3,6 +3,9 @@ declare class FormJsPage {
|
|
|
3
3
|
private page;
|
|
4
4
|
private processApplicationPage;
|
|
5
5
|
readonly aiFormGeneratorButton: Locator;
|
|
6
|
+
readonly copilotCtaButton: Locator;
|
|
7
|
+
readonly copilotChatInput: Locator;
|
|
8
|
+
readonly copilotSendButton: Locator;
|
|
6
9
|
readonly formRequestInput: Locator;
|
|
7
10
|
readonly generateFormButton: Locator;
|
|
8
11
|
readonly formEditor: Locator;
|
|
@@ -22,6 +25,7 @@ declare class FormJsPage {
|
|
|
22
25
|
readonly deployErrorMessage: Locator;
|
|
23
26
|
constructor(page: Page);
|
|
24
27
|
generateAIForm(request?: string): Promise<void>;
|
|
28
|
+
private generateFormWithCopilot;
|
|
25
29
|
clickAIFormGeneratorButton(): Promise<void>;
|
|
26
30
|
clickFormRequestInput(): Promise<void>;
|
|
27
31
|
fillFormRequestInput(formRequest: string): Promise<void>;
|
|
@@ -11,6 +11,9 @@ class FormJsPage {
|
|
|
11
11
|
page;
|
|
12
12
|
processApplicationPage;
|
|
13
13
|
aiFormGeneratorButton;
|
|
14
|
+
copilotCtaButton;
|
|
15
|
+
copilotChatInput;
|
|
16
|
+
copilotSendButton;
|
|
14
17
|
formRequestInput;
|
|
15
18
|
generateFormButton;
|
|
16
19
|
formEditor;
|
|
@@ -34,6 +37,16 @@ class FormJsPage {
|
|
|
34
37
|
this.aiFormGeneratorButton = page.getByRole('button', {
|
|
35
38
|
name: 'AI Form Generator',
|
|
36
39
|
});
|
|
40
|
+
// camunda-hub #21398 retired the form page's AI Form Generator in favour
|
|
41
|
+
// of the Camunda Copilot sidecar: with One Copilot on, the empty form
|
|
42
|
+
// offers "Try Camunda Copilot" instead (FormDs.tsx / CopilotCTA.tsx), and
|
|
43
|
+
// the sidecar's chat input and send button come from
|
|
44
|
+
// camunda-copilot-client's ChatInput. Same shape as pages/8.7.
|
|
45
|
+
this.copilotCtaButton = page.getByRole('button', {
|
|
46
|
+
name: 'Try Camunda Copilot',
|
|
47
|
+
});
|
|
48
|
+
this.copilotChatInput = page.getByPlaceholder('Type a message...');
|
|
49
|
+
this.copilotSendButton = page.getByRole('button', { name: 'Send message' });
|
|
37
50
|
this.formRequestInput = page.getByPlaceholder('A form for an american standard loan request');
|
|
38
51
|
this.generateFormButton = page.getByRole('button', { name: 'Generate form' });
|
|
39
52
|
this.formEditor = page.getByLabel('Form Definition');
|
|
@@ -89,9 +102,13 @@ class FormJsPage {
|
|
|
89
102
|
this.deployErrorMessage = this.dialog.getByText('The form failed to deploy');
|
|
90
103
|
}
|
|
91
104
|
async generateAIForm(request = 'Create a form with the following fields: 1. A text field with the label "Full Name" 2. A number with the label "Count" 3. A date input with the label "Date of birth"4. A Checkbox with the label "Agree"') {
|
|
92
|
-
await (0, test_1.expect)(this.aiFormGeneratorButton).toBeVisible({
|
|
105
|
+
await (0, test_1.expect)(this.aiFormGeneratorButton.or(this.copilotCtaButton).first()).toBeVisible({
|
|
93
106
|
timeout: 90000,
|
|
94
107
|
});
|
|
108
|
+
if (!(await this.aiFormGeneratorButton.isVisible())) {
|
|
109
|
+
await this.generateFormWithCopilot(request);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
95
112
|
await this.clickAIFormGeneratorButton();
|
|
96
113
|
await this.clickFormRequestInput();
|
|
97
114
|
await this.fillFormRequestInput(request);
|
|
@@ -100,6 +117,19 @@ class FormJsPage {
|
|
|
100
117
|
await (0, test_1.expect)(this.page.getByText('Successfully generated smart form.')).toBeVisible({ timeout: 300000 });
|
|
101
118
|
await (0, sleep_1.sleep)(60000);
|
|
102
119
|
}
|
|
120
|
+
async generateFormWithCopilot(request) {
|
|
121
|
+
await this.copilotCtaButton.click({ timeout: 30000 });
|
|
122
|
+
await (0, test_1.expect)(this.copilotChatInput).toBeVisible({ timeout: 60000 });
|
|
123
|
+
await this.copilotChatInput.fill(request);
|
|
124
|
+
await this.copilotSendButton.click({ timeout: 30000 });
|
|
125
|
+
// Copilot edits the open form in place; the generated form is ready once
|
|
126
|
+
// every requested field shows up on the canvas.
|
|
127
|
+
for (const label of ['Full Name', 'Count', 'Date of birth', 'Agree']) {
|
|
128
|
+
await (0, test_1.expect)(this.formEditor.getByText(label).first()).toBeVisible({
|
|
129
|
+
timeout: 300000,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
103
133
|
async clickAIFormGeneratorButton() {
|
|
104
134
|
await this.aiFormGeneratorButton.click();
|
|
105
135
|
}
|
|
@@ -71,6 +71,7 @@ declare class ModelerCreatePage {
|
|
|
71
71
|
readonly publicAccessToggle: Locator;
|
|
72
72
|
readonly publicationTab: Locator;
|
|
73
73
|
readonly copyPublicLinkButton: Locator;
|
|
74
|
+
readonly publicLinkCodeBlock: Locator;
|
|
74
75
|
readonly closeButton: Locator;
|
|
75
76
|
readonly rbaEnabledDeployedDialog: Locator;
|
|
76
77
|
readonly viewProcessLink: Locator;
|
|
@@ -214,9 +215,11 @@ declare class ModelerCreatePage {
|
|
|
214
215
|
fillJobTypeInput(name: string): Promise<void>;
|
|
215
216
|
private suppressTestModeAnnouncement;
|
|
216
217
|
switchToPlay(): Promise<void>;
|
|
218
|
+
private selectPlayDeploySingleResource;
|
|
217
219
|
completePlayConfiguration(clusterName: string): Promise<void>;
|
|
218
220
|
embedForm(formName: string): Promise<void>;
|
|
219
221
|
fillStartEventVariablesForDocHandling(zeebeUrl: string, zeebeClientId: string, zeebeClientSecret: string): Promise<void>;
|
|
222
|
+
private openOutputMappingEntry;
|
|
220
223
|
fillZeebeClientId(clientId: string): Promise<void>;
|
|
221
224
|
fillZeebeSecretValue(zeebeSecret: string): Promise<void>;
|
|
222
225
|
fillZeebeRestValue(zeebeUrl: string): Promise<void>;
|