@camunda/e2e-test-suite 0.0.1465 → 0.0.1467
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/BrowseAllConnectorMarketplacePage.d.ts +1 -1
- package/dist/pages/BrowseAllConnectorMarketplacePage.js +20 -7
- package/dist/pages/SM-8.10/ConnectorMarketplacePage.d.ts +3 -1
- package/dist/pages/SM-8.10/ConnectorMarketplacePage.js +32 -3
- package/dist/pages/SM-8.10/ModelerCreatePage.d.ts +9 -0
- package/dist/pages/SM-8.10/ModelerCreatePage.js +100 -1
- package/dist/pages/SM-8.10/ModelerHomePage.d.ts +4 -0
- package/dist/pages/SM-8.10/ModelerHomePage.js +57 -0
- package/dist/tests/8.7/web-modeler-user-flows.spec.js +5 -0
- package/dist/tests/SM-8.10/connectors-user-flows.spec.js +106 -35
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ declare class BrowseAllConnectorMarketplacePage {
|
|
|
10
10
|
constructor(page: Page);
|
|
11
11
|
isOpen(): Promise<boolean>;
|
|
12
12
|
waitForConnectorSearchResult(connectorName?: string): Promise<Locator>;
|
|
13
|
-
importConnectorToProject(connectorName?: string): Promise<
|
|
13
|
+
importConnectorToProject(connectorName?: string): Promise<boolean>;
|
|
14
14
|
private waitForInspectionReady;
|
|
15
15
|
private waitForAnyVisible;
|
|
16
16
|
private completeImportReviewIfNecessary;
|
|
@@ -46,6 +46,9 @@ class BrowseAllConnectorMarketplacePage {
|
|
|
46
46
|
}
|
|
47
47
|
return await this.findConnectorCard(connectorName);
|
|
48
48
|
}
|
|
49
|
+
// Resolves to whether an "Add" click actually happened. It is false when
|
|
50
|
+
// the project already had the connector ("Added to this project"), in which
|
|
51
|
+
// case the import write path was never exercised.
|
|
49
52
|
async importConnectorToProject(connectorName) {
|
|
50
53
|
const connectorCard = await this.waitForConnectorSearchResult(connectorName);
|
|
51
54
|
await connectorCard.click({ timeout: 60000 });
|
|
@@ -60,6 +63,7 @@ class BrowseAllConnectorMarketplacePage {
|
|
|
60
63
|
const retryButton = this.marketplaceDetailFooter.getByRole('button', {
|
|
61
64
|
name: 'Try again',
|
|
62
65
|
});
|
|
66
|
+
let addClicked = false;
|
|
63
67
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
64
68
|
await this.waitForInspectionReady(addButton, addedStatus, retryButton);
|
|
65
69
|
if (await addedStatus.isVisible()) {
|
|
@@ -73,6 +77,7 @@ class BrowseAllConnectorMarketplacePage {
|
|
|
73
77
|
continue;
|
|
74
78
|
}
|
|
75
79
|
await addButton.click({ timeout: 60000 });
|
|
80
|
+
addClicked = true;
|
|
76
81
|
if (await this.completeImportReviewIfNecessary(addButton, retryButton, addedStatus)) {
|
|
77
82
|
break;
|
|
78
83
|
}
|
|
@@ -85,6 +90,7 @@ class BrowseAllConnectorMarketplacePage {
|
|
|
85
90
|
.getByRole('button', { name: 'Close' })
|
|
86
91
|
.click({ timeout: 60000 });
|
|
87
92
|
await browseAllDialog.waitFor({ state: 'hidden', timeout: 60000 });
|
|
93
|
+
return addClicked;
|
|
88
94
|
}
|
|
89
95
|
async waitForInspectionReady(addButton, addedStatus, retryButton) {
|
|
90
96
|
const checkingStatus = this.marketplaceDetailFooter.getByText('Checking this project…', { exact: true });
|
|
@@ -164,21 +170,28 @@ class BrowseAllConnectorMarketplacePage {
|
|
|
164
170
|
.getByRole('button', {
|
|
165
171
|
name: new RegExp(`^View details for .*${searchWords}.* from Marketplace$`, 'i'),
|
|
166
172
|
})
|
|
167
|
-
.
|
|
173
|
+
.filter({ visible: true });
|
|
168
174
|
const exactVisible = await exactCard
|
|
169
175
|
.waitFor({ state: 'visible', timeout: 15000 })
|
|
170
176
|
.then(() => true)
|
|
171
|
-
.catch(() =>
|
|
177
|
+
.catch((error) => {
|
|
178
|
+
if (error instanceof test_1.errors.TimeoutError) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
});
|
|
172
183
|
if (exactVisible) {
|
|
173
184
|
return exactCard;
|
|
174
185
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return
|
|
186
|
+
await (0, test_1.expect)(relatedCard, `Browse All returned no Marketplace connector matching "${connectorName}".`).not.toHaveCount(0, { timeout: 105000 });
|
|
187
|
+
if (await exactCard.isVisible()) {
|
|
188
|
+
return exactCard;
|
|
178
189
|
}
|
|
179
|
-
|
|
180
|
-
|
|
190
|
+
const matches = await relatedCard.count();
|
|
191
|
+
if (matches !== 1) {
|
|
192
|
+
throw new Error(`Browse All returned ${matches} Marketplace connectors matching "${connectorName}"; expected one unique match.`);
|
|
181
193
|
}
|
|
194
|
+
return relatedCard;
|
|
182
195
|
}
|
|
183
196
|
}
|
|
184
197
|
exports.BrowseAllConnectorMarketplacePage = BrowseAllConnectorMarketplacePage;
|
|
@@ -12,6 +12,7 @@ declare class ConnectorMarketplacePage {
|
|
|
12
12
|
readonly cancelButton: Locator;
|
|
13
13
|
readonly marketplaceErrorMessage: Locator;
|
|
14
14
|
readonly noResultsMessage: Locator;
|
|
15
|
+
readonly importErrorMessage: Locator;
|
|
15
16
|
constructor(page: Page);
|
|
16
17
|
clickSearchForConnectorTextbox(): Promise<void>;
|
|
17
18
|
fillSearchForConnectorTextbox(connectorName: string): Promise<void>;
|
|
@@ -19,7 +20,8 @@ declare class ConnectorMarketplacePage {
|
|
|
19
20
|
clickCancelButton(): Promise<void>;
|
|
20
21
|
clickReplaceResourceButton(): Promise<void>;
|
|
21
22
|
waitForConnectorSearchResults(): Promise<void>;
|
|
22
|
-
|
|
23
|
+
importConnectorAndAssertNoImportError(): Promise<boolean>;
|
|
24
|
+
downloadConnectorToProject(): Promise<boolean>;
|
|
23
25
|
private confirmImport;
|
|
24
26
|
private waitForImportToSettle;
|
|
25
27
|
private getLegacyDownloadButton;
|
|
@@ -17,6 +17,7 @@ class ConnectorMarketplacePage {
|
|
|
17
17
|
cancelButton;
|
|
18
18
|
marketplaceErrorMessage;
|
|
19
19
|
noResultsMessage;
|
|
20
|
+
importErrorMessage;
|
|
20
21
|
constructor(page) {
|
|
21
22
|
this.page = page;
|
|
22
23
|
this.browseAllConnectorMarketplacePage =
|
|
@@ -42,6 +43,12 @@ class ConnectorMarketplacePage {
|
|
|
42
43
|
this.saveAsCopyButton = page.getByRole('button', { name: 'Save as copy' });
|
|
43
44
|
this.marketplaceErrorMessage = page.getByText('an error occurred, please try again later');
|
|
44
45
|
this.noResultsMessage = page.getByText('find a match for your search phrase');
|
|
46
|
+
// Hub's error when a Marketplace import fails, e.g. "Couldn't add this
|
|
47
|
+
// connector ... partial import removed" when an entry carries several
|
|
48
|
+
// versions of one template. The apostrophe may be straight or typographic.
|
|
49
|
+
this.importErrorMessage = page
|
|
50
|
+
.getByText(/couldn.t add this connector/i)
|
|
51
|
+
.first();
|
|
45
52
|
}
|
|
46
53
|
async clickSearchForConnectorTextbox() {
|
|
47
54
|
await this.searchForConnectorTextbox.click({ timeout: 60000 });
|
|
@@ -90,14 +97,35 @@ class ConnectorMarketplacePage {
|
|
|
90
97
|
}
|
|
91
98
|
throw new Error('Marketplace connector search failed after retries due to persistent error or no matching results');
|
|
92
99
|
}
|
|
100
|
+
// Imports the connector like downloadConnectorToProject, but fails with
|
|
101
|
+
// Hub's own import error instead of the generic "could not import after 3
|
|
102
|
+
// attempts" when the import is rejected, and asserts the error is not shown
|
|
103
|
+
// once the import is done.
|
|
104
|
+
// Resolves to whether the import was actually performed (see
|
|
105
|
+
// downloadConnectorToProject).
|
|
106
|
+
async importConnectorAndAssertNoImportError() {
|
|
107
|
+
let imported;
|
|
108
|
+
try {
|
|
109
|
+
imported = await this.downloadConnectorToProject();
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (await this.importErrorMessage.isVisible()) {
|
|
113
|
+
throw new Error(`Hub rejected the Marketplace import of "${this.connectorName}" ("Couldn't add this connector"). Original error: ${error}`);
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
await (0, test_1.expect)(this.importErrorMessage).toBeHidden({ timeout: 5000 });
|
|
118
|
+
return imported;
|
|
119
|
+
}
|
|
120
|
+
// Resolves to whether an import write was actually attempted: false when
|
|
121
|
+
// Browse all reported the connector as already added to the project.
|
|
93
122
|
async downloadConnectorToProject() {
|
|
94
123
|
if (await this.browseAllConnectorMarketplacePage.isOpen()) {
|
|
95
|
-
await this.browseAllConnectorMarketplacePage.importConnectorToProject(this.connectorName);
|
|
96
|
-
return;
|
|
124
|
+
return await this.browseAllConnectorMarketplacePage.importConnectorToProject(this.connectorName);
|
|
97
125
|
}
|
|
98
126
|
await this.clickDownloadToProjectButton();
|
|
99
127
|
if (await this.confirmImport()) {
|
|
100
|
-
return;
|
|
128
|
+
return true;
|
|
101
129
|
}
|
|
102
130
|
// The modal is up but rendered none of the known import actions. Dismiss it
|
|
103
131
|
// so it does not block the next click on the diagram, then fail here:
|
|
@@ -111,6 +139,7 @@ class ConnectorMarketplacePage {
|
|
|
111
139
|
// Hub imported without asking for confirmation, so the write is in flight
|
|
112
140
|
// here too.
|
|
113
141
|
await this.waitForImportToSettle();
|
|
142
|
+
return true;
|
|
114
143
|
}
|
|
115
144
|
// Hub's import modal labels its primary button after the project state:
|
|
116
145
|
// "Add to project" when the template is new to the project, "Replace
|
|
@@ -38,6 +38,10 @@ declare class ModelerCreatePage {
|
|
|
38
38
|
readonly restConnectorOption: Locator;
|
|
39
39
|
readonly changeElementSearchInput: Locator;
|
|
40
40
|
readonly changeElementResults: Locator;
|
|
41
|
+
readonly aiAgentTaskConnectorOption: Locator;
|
|
42
|
+
readonly aiAgentSubProcessConnectorOption: Locator;
|
|
43
|
+
readonly adHocSubProcessOption: Locator;
|
|
44
|
+
readonly propertiesPanel: Locator;
|
|
41
45
|
readonly reusableAssetsTab: Locator;
|
|
42
46
|
readonly marketPlaceButton: Locator;
|
|
43
47
|
readonly clientIdTextbox: Locator;
|
|
@@ -120,6 +124,7 @@ declare class ModelerCreatePage {
|
|
|
120
124
|
fillElementIdInput(id: string): Promise<void>;
|
|
121
125
|
clickStartEventElement(): Promise<void>;
|
|
122
126
|
selectStartEventElement(): Promise<void>;
|
|
127
|
+
appendTaskToStartEvent(): Promise<string>;
|
|
123
128
|
private clickCreatePadEntry;
|
|
124
129
|
private appendViaPopup;
|
|
125
130
|
clickAppendTaskButton(): Promise<void>;
|
|
@@ -167,7 +172,11 @@ declare class ModelerCreatePage {
|
|
|
167
172
|
revealChangeElementTemplate(option: Locator, searchTerm: string): Promise<boolean>;
|
|
168
173
|
private isVisibleWithin;
|
|
169
174
|
private openChangeElementPopup;
|
|
175
|
+
openChangeElementPopupForElement(elementId: string): Promise<void>;
|
|
170
176
|
private clickChangeElementTemplateOption;
|
|
177
|
+
assertChangeElementTemplateListed(option: Locator, searchTerm: string, elementId: string): Promise<void>;
|
|
178
|
+
changeElementToAdHocSubProcess(elementId: string): Promise<void>;
|
|
179
|
+
applyAiAgentSubProcessTemplate(): Promise<void>;
|
|
171
180
|
clickWebhookMessageStartEventConnectorOption(): Promise<void>;
|
|
172
181
|
clickWebhookIdInput(): Promise<void>;
|
|
173
182
|
clearWebhookIdInput(): Promise<void>;
|
|
@@ -45,6 +45,10 @@ class ModelerCreatePage {
|
|
|
45
45
|
restConnectorOption;
|
|
46
46
|
changeElementSearchInput;
|
|
47
47
|
changeElementResults;
|
|
48
|
+
aiAgentTaskConnectorOption;
|
|
49
|
+
aiAgentSubProcessConnectorOption;
|
|
50
|
+
adHocSubProcessOption;
|
|
51
|
+
propertiesPanel;
|
|
48
52
|
reusableAssetsTab;
|
|
49
53
|
marketPlaceButton;
|
|
50
54
|
clientIdTextbox;
|
|
@@ -227,8 +231,19 @@ class ModelerCreatePage {
|
|
|
227
231
|
this.restConnectorOption = page
|
|
228
232
|
.locator('.djs-popup-results')
|
|
229
233
|
.locator('[data-id="replace.template-io.camunda.connectors.HttpJson.v2"]');
|
|
234
|
+
// Require the supported 8.10 template, not the deprecated v1 variant.
|
|
235
|
+
this.aiAgentSubProcessConnectorOption = page
|
|
236
|
+
.locator('.djs-popup-results')
|
|
237
|
+
.locator('[data-id="replace.template-io.camunda.connectors.agenticai.ai-agent-subprocess.v2"]');
|
|
238
|
+
this.adHocSubProcessOption = page
|
|
239
|
+
.locator('.djs-popup-results')
|
|
240
|
+
.locator('[data-id="replace-with-ad-hoc-subprocess"]');
|
|
241
|
+
this.propertiesPanel = page.locator('[data-test="properties-panel"]');
|
|
230
242
|
this.changeElementSearchInput = page.locator('.djs-popup-search input');
|
|
231
243
|
this.changeElementResults = page.locator('.djs-popup-results');
|
|
244
|
+
this.aiAgentTaskConnectorOption = page
|
|
245
|
+
.locator('.djs-popup-results')
|
|
246
|
+
.locator('[data-id="replace.template-io.camunda.connectors.agenticai.ai-agent-task.v2"]');
|
|
232
247
|
// The tab renders its label as text content, and the product source
|
|
233
248
|
// spells it both "Reusable Assets" and "Reusable assets".
|
|
234
249
|
this.reusableAssetsTab = page.getByRole('tab', {
|
|
@@ -604,6 +619,27 @@ class ModelerCreatePage {
|
|
|
604
619
|
async selectStartEventElement() {
|
|
605
620
|
await this.startEventElement.click();
|
|
606
621
|
}
|
|
622
|
+
async appendTaskToStartEvent() {
|
|
623
|
+
const startEvent = this.page.locator('.djs-shape[data-element-id="StartEvent_1"]');
|
|
624
|
+
await (0, test_1.expect)(startEvent).toBeVisible({ timeout: 30000 });
|
|
625
|
+
// Renaming can refresh canvas selection; clicking a selected shape toggles it off.
|
|
626
|
+
await (0, test_1.expect)(async () => {
|
|
627
|
+
if (!(await startEvent.evaluate((element) => element.classList.contains('selected')))) {
|
|
628
|
+
await startEvent.click();
|
|
629
|
+
}
|
|
630
|
+
await (0, test_1.expect)(startEvent).toHaveClass(/selected/);
|
|
631
|
+
}).toPass({ timeout: 30000 });
|
|
632
|
+
await this.page
|
|
633
|
+
.getByRole('button', { name: 'Append task', exact: true })
|
|
634
|
+
.click();
|
|
635
|
+
const task = this.page.locator('.djs-shape.selected');
|
|
636
|
+
await (0, test_1.expect)(task).not.toHaveAttribute('data-element-id', 'StartEvent_1');
|
|
637
|
+
const elementId = await task.getAttribute('data-element-id');
|
|
638
|
+
if (!elementId) {
|
|
639
|
+
throw new Error('The appended task has no element ID.');
|
|
640
|
+
}
|
|
641
|
+
return elementId;
|
|
642
|
+
}
|
|
607
643
|
// The create pad's direct append icons no longer carry the bpmn-js `title`
|
|
608
644
|
// attributes ("Append task", "Append intermediate/boundary", "Append end
|
|
609
645
|
// event"), so append through the "append anything" entry instead: it opens
|
|
@@ -771,6 +807,7 @@ class ModelerCreatePage {
|
|
|
771
807
|
return;
|
|
772
808
|
}
|
|
773
809
|
}
|
|
810
|
+
throw new Error(`The diagram did not commit Camunda version ${version}.`);
|
|
774
811
|
}
|
|
775
812
|
async clickChangeTypeButton() {
|
|
776
813
|
try {
|
|
@@ -1331,9 +1368,26 @@ class ModelerCreatePage {
|
|
|
1331
1368
|
// bare 30s force-click here has no recovery and loses the reopen race on a
|
|
1332
1369
|
// freshly installed cluster.
|
|
1333
1370
|
await (0, test_1.expect)(element).toBeVisible({ timeout: 60000 });
|
|
1334
|
-
await element.
|
|
1371
|
+
if (!(await element.evaluate((shape) => shape.classList.contains('selected')))) {
|
|
1372
|
+
await element.click({ timeout: 30000 });
|
|
1373
|
+
}
|
|
1335
1374
|
await this.clickChangeTypeButton();
|
|
1336
1375
|
}
|
|
1376
|
+
async openChangeElementPopupForElement(elementId) {
|
|
1377
|
+
const element = this.page.locator(`.djs-shape[data-element-id="${elementId}"]`);
|
|
1378
|
+
// A visible popup may belong to another shape or to the append action.
|
|
1379
|
+
await this.page.keyboard.press('Escape');
|
|
1380
|
+
await (0, test_1.expect)(this.changeElementSearchInput).toBeHidden({ timeout: 30000 });
|
|
1381
|
+
await (0, test_1.expect)(element).toBeVisible({ timeout: 30000 });
|
|
1382
|
+
await (0, test_1.expect)(async () => {
|
|
1383
|
+
if (!(await element.evaluate((shape) => shape.classList.contains('selected')))) {
|
|
1384
|
+
await element.click({ timeout: 5000 });
|
|
1385
|
+
}
|
|
1386
|
+
await (0, test_1.expect)(element).toHaveClass(/(?:^|\s)selected(?:\s|$)/);
|
|
1387
|
+
}).toPass({ timeout: 30000 });
|
|
1388
|
+
await this.changeTypeButton.click({ timeout: 30000 });
|
|
1389
|
+
await (0, test_1.expect)(this.changeElementSearchInput).toBeVisible({ timeout: 30000 });
|
|
1390
|
+
}
|
|
1337
1391
|
async clickChangeElementTemplateOption(option, element, searchTerm) {
|
|
1338
1392
|
const maxRetries = 3;
|
|
1339
1393
|
let lastError;
|
|
@@ -1360,6 +1414,51 @@ class ModelerCreatePage {
|
|
|
1360
1414
|
}
|
|
1361
1415
|
throw new Error(`Failed to click the connector template after ${maxRetries} attempts: ${lastError}`);
|
|
1362
1416
|
}
|
|
1417
|
+
// Reopens the change-element popup on the appended element (the Marketplace
|
|
1418
|
+
// import closes it) and asserts that `option` is listed, i.e. that the
|
|
1419
|
+
// imported template really landed in the project.
|
|
1420
|
+
async assertChangeElementTemplateListed(option, searchTerm, elementId) {
|
|
1421
|
+
await this.openChangeElementPopupForElement(elementId);
|
|
1422
|
+
const revealed = await this.revealChangeElementTemplate(option, searchTerm);
|
|
1423
|
+
(0, test_1.expect)(revealed, `"${searchTerm}" was not listed in the change-element popup after the Marketplace import.`).toBe(true);
|
|
1424
|
+
await (0, test_1.expect)(option).toBeVisible({ timeout: 30000 });
|
|
1425
|
+
await (0, test_1.expect)(option).toBeEnabled({ timeout: 30000 });
|
|
1426
|
+
}
|
|
1427
|
+
// Turns the appended task into an ad-hoc sub-process through the
|
|
1428
|
+
// change-element popup. The popup is filtered first: it virtualizes its list.
|
|
1429
|
+
async changeElementToAdHocSubProcess(elementId) {
|
|
1430
|
+
const element = this.page.locator(`.djs-shape[data-element-id="${elementId}"]`);
|
|
1431
|
+
await this.openChangeElementPopupForElement(elementId);
|
|
1432
|
+
await (0, test_1.expect)(this.changeElementSearchInput).toBeVisible({ timeout: 30000 });
|
|
1433
|
+
await this.changeElementSearchInput.click();
|
|
1434
|
+
await this.changeElementSearchInput.fill('');
|
|
1435
|
+
await this.changeElementSearchInput.pressSequentially('Ad-hoc', {
|
|
1436
|
+
delay: 50,
|
|
1437
|
+
});
|
|
1438
|
+
await this.adHocSubProcessOption.click({ timeout: 30000 });
|
|
1439
|
+
await (0, test_1.expect)(element.locator('[data-marker="adhoc"]')).toBeVisible({
|
|
1440
|
+
timeout: 30000,
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
// Applies the listed AI Agent Sub-process template to the selected ad-hoc
|
|
1444
|
+
// sub-process and asserts the properties panel resolved it.
|
|
1445
|
+
async applyAiAgentSubProcessTemplate() {
|
|
1446
|
+
await this.aiAgentSubProcessConnectorOption.click({ timeout: 30000 });
|
|
1447
|
+
await this.changeElementSearchInput.fill('');
|
|
1448
|
+
await this.changeElementSearchInput.pressSequentially('OpenAI API', {
|
|
1449
|
+
delay: 50,
|
|
1450
|
+
});
|
|
1451
|
+
const popup = this.page.locator('.djs-popup');
|
|
1452
|
+
await popup
|
|
1453
|
+
.getByRole('option', { name: 'OpenAI API', exact: true })
|
|
1454
|
+
.click({ timeout: 30000 });
|
|
1455
|
+
await (0, test_1.expect)(popup).toBeHidden({ timeout: 30000 });
|
|
1456
|
+
await (0, test_1.expect)(this.page
|
|
1457
|
+
.locator('.bio-properties-panel-header')
|
|
1458
|
+
.getByText('AI Agent Sub-process', { exact: true })).toBeVisible({ timeout: 60000 });
|
|
1459
|
+
await (0, test_1.expect)(this.propertiesPanel.getByText('Applied', { exact: true })).toBeVisible({ timeout: 30000 });
|
|
1460
|
+
await (0, test_1.expect)(this.templateNotFoundTag).toBeHidden({ timeout: 10000 });
|
|
1461
|
+
}
|
|
1363
1462
|
async clickWebhookMessageStartEventConnectorOption() {
|
|
1364
1463
|
await this.clickChangeElementTemplateOption(this.webhookMessageStartEventConnectorOption, this.startEventElement, 'Webhook');
|
|
1365
1464
|
}
|
|
@@ -7,6 +7,8 @@ declare class ModelerHomePage {
|
|
|
7
7
|
private processApplicationName?;
|
|
8
8
|
private workspaceProjectsUrl?;
|
|
9
9
|
private workspacesOverviewUrl?;
|
|
10
|
+
private disposableWorkspaceUrl?;
|
|
11
|
+
private disposableWorkspaceName?;
|
|
10
12
|
readonly modelerPageBanner: Locator;
|
|
11
13
|
readonly createNewProjectButton: Locator;
|
|
12
14
|
readonly createWorkspaceButton: Locator;
|
|
@@ -65,6 +67,8 @@ declare class ModelerHomePage {
|
|
|
65
67
|
password: string;
|
|
66
68
|
}): Promise<void>;
|
|
67
69
|
private ensureWorkspaceOpen;
|
|
70
|
+
createDisposableWorkspace(name: string): Promise<void>;
|
|
71
|
+
deleteDisposableWorkspace(): Promise<void>;
|
|
68
72
|
private gotoWorkspacesOverview;
|
|
69
73
|
private createWorkspace;
|
|
70
74
|
private submitWorkspaceWizard;
|
|
@@ -30,6 +30,8 @@ class ModelerHomePage {
|
|
|
30
30
|
// re-walk the hierarchy from the root each time.
|
|
31
31
|
workspaceProjectsUrl;
|
|
32
32
|
workspacesOverviewUrl;
|
|
33
|
+
disposableWorkspaceUrl;
|
|
34
|
+
disposableWorkspaceName;
|
|
33
35
|
modelerPageBanner;
|
|
34
36
|
createNewProjectButton;
|
|
35
37
|
// /workspaces overview controls (flag-on). The "Create workspace" CTA is
|
|
@@ -211,6 +213,7 @@ class ModelerHomePage {
|
|
|
211
213
|
// sibling options chevron whose name would otherwise substring-match.
|
|
212
214
|
this.createWorkspaceButton = page.getByRole('button', {
|
|
213
215
|
name: 'Create workspace',
|
|
216
|
+
exact: true,
|
|
214
217
|
});
|
|
215
218
|
this.workspaceOpenButton = page
|
|
216
219
|
.getByRole('button', { name: /^open workspace /i })
|
|
@@ -479,6 +482,60 @@ class ModelerHomePage {
|
|
|
479
482
|
}
|
|
480
483
|
}
|
|
481
484
|
}
|
|
485
|
+
// Creates a new, randomly named Workspace and leaves the browser on its
|
|
486
|
+
// projects listing. Template IDs are unique per Workspace, so a connector
|
|
487
|
+
// import into a fresh one always exercises the write path instead of finding
|
|
488
|
+
// the connector already added by an earlier run.
|
|
489
|
+
async createDisposableWorkspace(name) {
|
|
490
|
+
await this.gotoWorkspacesOverview();
|
|
491
|
+
await this.waitForModelerReady();
|
|
492
|
+
await this.clickMessageBanner();
|
|
493
|
+
await this.dismissModals();
|
|
494
|
+
this.disposableWorkspaceName = name;
|
|
495
|
+
try {
|
|
496
|
+
await this.createWorkspace(name);
|
|
497
|
+
}
|
|
498
|
+
finally {
|
|
499
|
+
const current = new URL(this.page.url());
|
|
500
|
+
if (/\/workspaces?\/[^/]+\/projects$/.test(current.pathname)) {
|
|
501
|
+
this.disposableWorkspaceUrl = `${current.origin}${current.pathname}`;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
async deleteDisposableWorkspace() {
|
|
506
|
+
if (!this.disposableWorkspaceName) {
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (this.disposableWorkspaceUrl) {
|
|
510
|
+
await this.page.goto(this.disposableWorkspaceUrl.replace(/\/projects$/, '/manage?tab=general'), { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
await this.gotoWorkspacesOverview();
|
|
514
|
+
await this.waitForModelerReady(30000);
|
|
515
|
+
const manage = this.page.getByRole('button', {
|
|
516
|
+
name: `Manage workspace ${this.disposableWorkspaceName}`,
|
|
517
|
+
exact: true,
|
|
518
|
+
});
|
|
519
|
+
await (0, test_1.expect)(manage).toBeVisible({ timeout: 15000 });
|
|
520
|
+
await manage.click({ timeout: 15000 });
|
|
521
|
+
await this.page
|
|
522
|
+
.getByRole('tab', { name: 'General', exact: true })
|
|
523
|
+
.click({ timeout: 15000 });
|
|
524
|
+
}
|
|
525
|
+
await this.page
|
|
526
|
+
.getByRole('tabpanel', { name: 'General', exact: true })
|
|
527
|
+
.getByRole('button', { name: 'Delete', exact: true })
|
|
528
|
+
.click({ timeout: 30000 });
|
|
529
|
+
const dialog = this.page.getByRole('dialog').filter({
|
|
530
|
+
has: this.page.getByRole('heading', { name: /^Delete workspace(?:\s|$)/ }),
|
|
531
|
+
});
|
|
532
|
+
await dialog
|
|
533
|
+
.getByRole('button', { name: 'Delete workspace', exact: true })
|
|
534
|
+
.click({ timeout: 30000 });
|
|
535
|
+
await this.page.waitForURL(/\/workspaces\/?$/, { timeout: 30000 });
|
|
536
|
+
this.disposableWorkspaceUrl = undefined;
|
|
537
|
+
this.disposableWorkspaceName = undefined;
|
|
538
|
+
}
|
|
482
539
|
// Navigates to the Workspaces overview by resolving it against the Modeler app
|
|
483
540
|
// root in the current URL, so it works whether Modeler is served under
|
|
484
541
|
// `/modeler` (Self-Managed combined ingress) or at the app root.
|
|
@@ -650,6 +650,11 @@ _8_7_1.test.describe('Web Modeler User Flow Tests', () => {
|
|
|
650
650
|
});
|
|
651
651
|
});
|
|
652
652
|
(0, _8_7_1.test)('Public Start Form', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, context, taskDetailsPage, loginPage, taskPanelPage, operateHomePage, operateProcessesPage, operateProcessInstancePage, }) => {
|
|
653
|
+
// Form + BPMN + two Hub deploys (incl. stage-cluster binding), a public
|
|
654
|
+
// form submit, then Tasklist and Operate: the Hub flow alone takes ~10
|
|
655
|
+
// minutes, so the 12-minute default leaves no room for the Tasklist /
|
|
656
|
+
// Operate half. Same budget as the other multi-app Hub tests in this file.
|
|
657
|
+
_8_7_1.test.slow();
|
|
653
658
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
654
659
|
const processName = 'User_Task_Process_With_Public_Form' + randomString;
|
|
655
660
|
const formName = 'Public form' + randomString;
|
|
@@ -2,10 +2,25 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const test_1 = require("@playwright/test");
|
|
4
4
|
const SM_8_10_1 = require("../../fixtures/SM-8.10");
|
|
5
|
+
const ModelerHomePage_1 = require("../../pages/SM-8.10/ModelerHomePage");
|
|
5
6
|
const _setup_1 = require("../../test-setup.js");
|
|
6
7
|
const UtilitiesPage_1 = require("../../pages/SM-8.10/UtilitiesPage");
|
|
7
8
|
const sleep_1 = require("../../utils/sleep");
|
|
8
9
|
const constants_1 = require("../../utils/constants");
|
|
10
|
+
const test = SM_8_10_1.test.extend({
|
|
11
|
+
modelerHomePage: [
|
|
12
|
+
async ({ page }, use) => {
|
|
13
|
+
const home = new ModelerHomePage_1.ModelerHomePage(page);
|
|
14
|
+
try {
|
|
15
|
+
await use(home);
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
await home.deleteDisposableWorkspace();
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{ scope: 'test', timeout: 120000 },
|
|
22
|
+
],
|
|
23
|
+
});
|
|
9
24
|
// Serial: the two active webhook tests both fall back to importing the
|
|
10
25
|
// "Webhook Connector" marketplace package (which bundles the Boundary,
|
|
11
26
|
// Intermediate and Message-Start template variants) when the template is not
|
|
@@ -17,31 +32,31 @@ const constants_1 = require("../../utils/constants");
|
|
|
17
32
|
// Running them serially lets the first import register the templates
|
|
18
33
|
// Workspace-wide; the second test then reveals them directly and skips the
|
|
19
34
|
// import, so there is no collision.
|
|
20
|
-
|
|
21
|
-
|
|
35
|
+
test.describe.configure({ mode: 'serial' });
|
|
36
|
+
test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
22
37
|
const mtTenant = process.env.IS_MT === 'true' ? '<default>' : '';
|
|
23
|
-
|
|
38
|
+
test.beforeEach(async ({ navigationPage }, testInfo) => {
|
|
24
39
|
await navigationPage.goToModeler((testInfo.workerIndex + 1) * 1000);
|
|
25
40
|
});
|
|
26
|
-
|
|
41
|
+
test.afterEach(async ({ page }, testInfo) => {
|
|
27
42
|
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
28
43
|
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
29
44
|
});
|
|
30
45
|
// Skipped due to bug #7716: https://github.com/camunda/connectors/issues/7716
|
|
31
|
-
|
|
32
|
-
|
|
46
|
+
test.skip('REST Connector No Auth User Flow', async ({ page, operateHomePage, modelerHomePage, operateProcessInstancePage, modelerCreatePage, connectorSettingsPage, operateProcessesPage, connectorMarketplacePage, navigationPage, }) => {
|
|
47
|
+
test.slow();
|
|
33
48
|
const processName = 'REST_Connector_No_Auth_Process' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
34
|
-
await
|
|
49
|
+
await test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
|
|
35
50
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
36
51
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
37
52
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
38
53
|
});
|
|
39
|
-
await
|
|
54
|
+
await test.step('Create BPMN Diagram with REST Connector and Start Process Instance', async () => {
|
|
40
55
|
await (0, UtilitiesPage_1.modelRestConnector)(modelerCreatePage, connectorSettingsPage, connectorMarketplacePage, processName, constants_1.REST_MOCK_URL, 'noAuth', 'body');
|
|
41
56
|
await modelerCreatePage.runProcessInstance('', mtTenant);
|
|
42
57
|
await (0, sleep_1.sleep)(20000);
|
|
43
58
|
});
|
|
44
|
-
await
|
|
59
|
+
await test.step('View Process Instance in Operate, assert it completes and assert result expression', async () => {
|
|
45
60
|
await navigationPage.goToOperate();
|
|
46
61
|
await operateHomePage.clickProcessesTab();
|
|
47
62
|
await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
|
|
@@ -56,21 +71,21 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
56
71
|
});
|
|
57
72
|
});
|
|
58
73
|
});
|
|
59
|
-
|
|
60
|
-
|
|
74
|
+
test('REST Connector Bearer Token Auth User Flow', async ({ page, operateHomePage, modelerHomePage, modelerCreatePage, connectorSettingsPage, navigationPage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, }) => {
|
|
75
|
+
test.slow();
|
|
61
76
|
const processName = 'REST_Connector_Bearer_Auth_Process' +
|
|
62
77
|
(await (0, _setup_1.generateRandomStringAsync)(3));
|
|
63
|
-
await
|
|
78
|
+
await test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
|
|
64
79
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
65
80
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
66
81
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
67
82
|
});
|
|
68
|
-
await
|
|
83
|
+
await test.step('Create BPMN Diagram with REST Connector with Basic Auth and Start Process Instance', async () => {
|
|
69
84
|
await (0, UtilitiesPage_1.modelRestConnector)(modelerCreatePage, connectorSettingsPage, connectorMarketplacePage, processName, constants_1.REST_MOCK_URL, 'bearer', '{message:response.body.message}');
|
|
70
85
|
await modelerCreatePage.runProcessInstance('', mtTenant);
|
|
71
86
|
await (0, sleep_1.sleep)(20000);
|
|
72
87
|
});
|
|
73
|
-
await
|
|
88
|
+
await test.step('View Process Instance in Operate, assert it completes and assert result expression', async () => {
|
|
74
89
|
await navigationPage.goToOperate();
|
|
75
90
|
await operateHomePage.clickProcessesTab();
|
|
76
91
|
await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
|
|
@@ -85,16 +100,16 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
85
100
|
});
|
|
86
101
|
});
|
|
87
102
|
});
|
|
88
|
-
|
|
89
|
-
|
|
103
|
+
test('Message Start Event Webhook Connector No Auth User Flow', async ({ modelerHomePage, navigationPage, modelerCreatePage, request, operateHomePage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, connectorSettingsPage, }) => {
|
|
104
|
+
test.slow();
|
|
90
105
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
91
106
|
const processName = 'Start_Event_Webhook_Connector_No_Auth_Process' + randomString;
|
|
92
|
-
await
|
|
107
|
+
await test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
|
|
93
108
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
94
109
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
95
110
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
96
111
|
});
|
|
97
|
-
await
|
|
112
|
+
await test.step('Create BPMN Diagram with REST Connector and Deploy Diagram', async () => {
|
|
98
113
|
await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({
|
|
99
114
|
timeout: 60000,
|
|
100
115
|
});
|
|
@@ -133,7 +148,7 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
133
148
|
await modelerCreatePage.deployProcessInstance(mtTenant);
|
|
134
149
|
await (0, sleep_1.sleep)(20000);
|
|
135
150
|
});
|
|
136
|
-
await
|
|
151
|
+
await test.step('Make Authorization Request', async () => {
|
|
137
152
|
const baseURL = process.env.PLAYWRIGHT_BASE_URL ||
|
|
138
153
|
`http://gke-${process.env.BASE_URL}.ci.distro.ultrawombat.com`;
|
|
139
154
|
const url = `${baseURL}/connectors/inbound/test-webhook-id${randomString}`;
|
|
@@ -154,7 +169,7 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
154
169
|
throw new Error(`Webhook request failed with status ${response?.status()} after ${attempt} attempts`);
|
|
155
170
|
}
|
|
156
171
|
});
|
|
157
|
-
await
|
|
172
|
+
await test.step('Assert Diagram Has Successfully Completed in Operate', async () => {
|
|
158
173
|
await navigationPage.goToOperate();
|
|
159
174
|
await operateHomePage.clickProcessesTab();
|
|
160
175
|
await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
|
|
@@ -163,15 +178,15 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
163
178
|
});
|
|
164
179
|
});
|
|
165
180
|
// Skipped due to bug #7716: https://github.com/camunda/connectors/issues/7716
|
|
166
|
-
|
|
167
|
-
|
|
181
|
+
test.skip('Connector Secrets User Flow', async ({ operateHomePage, modelerHomePage, navigationPage, modelerCreatePage, connectorSettingsPage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, }) => {
|
|
182
|
+
test.slow();
|
|
168
183
|
const processName = 'REST_Connector_Process' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
169
|
-
await
|
|
184
|
+
await test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
|
|
170
185
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
171
186
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
172
187
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
173
188
|
});
|
|
174
|
-
await
|
|
189
|
+
await test.step('Create BPMN Diagram with REST Connector using secrets and Start Process Instance', async () => {
|
|
175
190
|
await (0, UtilitiesPage_1.modelRestConnector)(modelerCreatePage, connectorSettingsPage, connectorMarketplacePage, processName, constants_1.REST_MOCK_BASIC_AUTH_URL, 'basic', '{message:response.body.message}', {
|
|
176
191
|
resultVariable: 'result',
|
|
177
192
|
basicAuthCredentials: {
|
|
@@ -182,7 +197,7 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
182
197
|
await modelerCreatePage.runProcessInstance('', mtTenant);
|
|
183
198
|
await (0, sleep_1.sleep)(20000);
|
|
184
199
|
});
|
|
185
|
-
await
|
|
200
|
+
await test.step('View Process Instance in Operate, assert it completes and assert result expression', async () => {
|
|
186
201
|
await navigationPage.goToOperate();
|
|
187
202
|
await operateHomePage.clickProcessesTab();
|
|
188
203
|
await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
|
|
@@ -192,16 +207,16 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
192
207
|
await operateProcessInstancePage.assertProcessVariableContainsText('message', '"Message from Mock!"');
|
|
193
208
|
});
|
|
194
209
|
});
|
|
195
|
-
|
|
196
|
-
|
|
210
|
+
test('Intermediate Event Webhook Connector No Auth User Flow', async ({ modelerHomePage, modelerCreatePage, request, operateHomePage, operateProcessInstancePage, operateProcessesPage, navigationPage, connectorMarketplacePage, connectorSettingsPage, }) => {
|
|
211
|
+
test.slow();
|
|
197
212
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
198
213
|
const processName = 'Intermediate_Event_Webhook_Connector_No_Auth_Process' + randomString;
|
|
199
|
-
await
|
|
214
|
+
await test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
|
|
200
215
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
201
216
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
202
217
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
203
218
|
});
|
|
204
|
-
await
|
|
219
|
+
await test.step('Create BPMN Diagram with Intermediate Event Webhook Connector and Run Diagram', async () => {
|
|
205
220
|
await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({
|
|
206
221
|
timeout: 120000,
|
|
207
222
|
});
|
|
@@ -251,7 +266,7 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
251
266
|
await modelerCreatePage.runProcessInstance('', mtTenant);
|
|
252
267
|
await (0, sleep_1.sleep)(20000);
|
|
253
268
|
});
|
|
254
|
-
await
|
|
269
|
+
await test.step('Make Authorization Request', async () => {
|
|
255
270
|
const baseURL = process.env.PLAYWRIGHT_BASE_URL ||
|
|
256
271
|
`http://gke-${process.env.BASE_URL}.ci.distro.ultrawombat.com`;
|
|
257
272
|
const url = `${baseURL}/connectors/inbound/test-webhook-intermediate${randomString}`;
|
|
@@ -272,7 +287,7 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
272
287
|
}
|
|
273
288
|
await (0, sleep_1.sleep)(60000);
|
|
274
289
|
});
|
|
275
|
-
await
|
|
290
|
+
await test.step('Assert Diagram Has Successfully Completed in Operate', async () => {
|
|
276
291
|
await navigationPage.goToOperate();
|
|
277
292
|
await operateHomePage.clickProcessesTab();
|
|
278
293
|
await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
|
|
@@ -280,14 +295,70 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
280
295
|
(0, test_1.expect)(result).toBe('completed');
|
|
281
296
|
});
|
|
282
297
|
});
|
|
298
|
+
// Template IDs are unique per Workspace. A fresh Workspace forces each test
|
|
299
|
+
// through the import write instead of accepting an already-added connector.
|
|
300
|
+
// The fixture deletes it after screenshot hooks, even on failure or timeout.
|
|
301
|
+
const importAiAgentFromMarketplace = async ({ modelerHomePage, modelerCreatePage, connectorMarketplacePage, }, processName) => {
|
|
302
|
+
await test.step('Create a Workspace and a BPMN Diagram Template', async () => {
|
|
303
|
+
await modelerHomePage.createDisposableWorkspace('AI Agent Import Workspace ' + processName);
|
|
304
|
+
await modelerHomePage.clickDiagramTypeDropdown();
|
|
305
|
+
await modelerHomePage.clickBpmnTemplateOption();
|
|
306
|
+
});
|
|
307
|
+
const taskElementId = await test.step('Append a Task and Open the Change Element Popup', async () => {
|
|
308
|
+
await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({
|
|
309
|
+
timeout: 120000,
|
|
310
|
+
});
|
|
311
|
+
// Only the diagram name is set. The sibling flows also set the process
|
|
312
|
+
// ID here, but this test does not need it, and typing it before the
|
|
313
|
+
// canvas click has deselected the start event puts the ID on the start
|
|
314
|
+
// event: renaming StartEvent_1 drops its append indicator and the create
|
|
315
|
+
// pad never opens.
|
|
316
|
+
await modelerCreatePage.enterDiagramName(processName);
|
|
317
|
+
const elementId = await modelerCreatePage.appendTaskToStartEvent();
|
|
318
|
+
// The AI Agent templates require engines.camunda ^8.10; on a lower
|
|
319
|
+
// diagram version they land in "Requires newer Camunda version".
|
|
320
|
+
await modelerCreatePage.setEngineVersion('8.10');
|
|
321
|
+
await modelerCreatePage.openChangeElementPopupForElement(elementId);
|
|
322
|
+
return elementId;
|
|
323
|
+
});
|
|
324
|
+
await test.step('Import the AI Agent Connector from the Marketplace', async () => {
|
|
325
|
+
await modelerCreatePage.clickMarketPlaceButton();
|
|
326
|
+
await connectorMarketplacePage.clickSearchForConnectorTextbox();
|
|
327
|
+
await connectorMarketplacePage.fillSearchForConnectorTextbox('AI Agent');
|
|
328
|
+
await connectorMarketplacePage.waitForConnectorSearchResults();
|
|
329
|
+
const imported = await connectorMarketplacePage.importConnectorAndAssertNoImportError();
|
|
330
|
+
(0, test_1.expect)(imported, 'A fresh Workspace must exercise the AI Agent Marketplace import write.').toBe(true);
|
|
331
|
+
});
|
|
332
|
+
return taskElementId;
|
|
333
|
+
};
|
|
334
|
+
test('AI Agent Marketplace Import User Flow', async ({ modelerHomePage, modelerCreatePage, connectorMarketplacePage, }) => {
|
|
335
|
+
test.slow();
|
|
336
|
+
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
337
|
+
const taskElementId = await importAiAgentFromMarketplace({ modelerHomePage, modelerCreatePage, connectorMarketplacePage }, 'AI_Agent_Marketplace_Import_Process' + randomString);
|
|
338
|
+
await test.step('Assert the AI Agent Task Template Is Available', async () => {
|
|
339
|
+
await modelerCreatePage.assertChangeElementTemplateListed(modelerCreatePage.aiAgentTaskConnectorOption, 'AI Agent', taskElementId);
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
test('AI Agent Sub-process Marketplace Import User Flow', async ({ modelerHomePage, modelerCreatePage, connectorMarketplacePage, }) => {
|
|
343
|
+
test.slow();
|
|
344
|
+
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
345
|
+
const taskElementId = await importAiAgentFromMarketplace({ modelerHomePage, modelerCreatePage, connectorMarketplacePage }, 'AI_Agent_SubProcess_Import_Process' + randomString);
|
|
346
|
+
await test.step('Turn the Task into an Ad-hoc Sub-process', async () => {
|
|
347
|
+
await modelerCreatePage.changeElementToAdHocSubProcess(taskElementId);
|
|
348
|
+
});
|
|
349
|
+
await test.step('Assert the AI Agent Sub-process Template Is Available and Applies', async () => {
|
|
350
|
+
await modelerCreatePage.assertChangeElementTemplateListed(modelerCreatePage.aiAgentSubProcessConnectorOption, 'AI Agent', taskElementId);
|
|
351
|
+
await modelerCreatePage.applyAiAgentSubProcessTemplate();
|
|
352
|
+
});
|
|
353
|
+
});
|
|
283
354
|
//Skipped due to bug 1252: https://github.com/camunda/c8-cross-component-e2e-tests/issues/1252
|
|
284
|
-
|
|
285
|
-
|
|
355
|
+
test.skip('Connectors Timer Event User Flow', async ({ page, modelerHomePage, modelerCreatePage, connectorMarketplacePage, connectorTemplatePage, navigationPage, operateProcessInstancePage, operateHomePage, operateProcessesPage, }) => {
|
|
356
|
+
test.slow();
|
|
286
357
|
const processName = 'Connectors_Timer_Event_Process' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
287
|
-
await
|
|
358
|
+
await test.step('Open Cross Component Test Project and Create a REST Connector Document Handling Flow', async () => {
|
|
288
359
|
await (0, UtilitiesPage_1.modelAndRunConnectorsTimerEventDiagram)(modelerCreatePage, modelerHomePage, processName, page, connectorMarketplacePage, connectorTemplatePage, mtTenant);
|
|
289
360
|
});
|
|
290
|
-
await
|
|
361
|
+
await test.step('View Process Instance in Operate, assert it completes and assert variable values are correct', async () => {
|
|
291
362
|
await navigationPage.goToOperate();
|
|
292
363
|
await operateHomePage.clickProcessesTab();
|
|
293
364
|
await operateProcessesPage.clickProcessInstanceLink(processName);
|