@camunda/e2e-test-suite 0.0.242 → 0.0.244
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.9/ClusterDetailsPage.d.ts +10 -1
- package/dist/pages/8.9/ClusterDetailsPage.js +78 -8
- package/dist/pages/SM-8.6/ModelerCreatePage.js +1 -0
- package/dist/pages/SM-8.6/OperateProcessesPage.js +2 -1
- package/dist/pages/SM-8.6/PlayPage.d.ts +5 -0
- package/dist/pages/SM-8.6/PlayPage.js +40 -2
- package/dist/pages/SM-8.6/TaskDetailsPage.js +26 -3
- package/dist/pages/SM-8.7/ModelerCreatePage.js +1 -0
- package/dist/pages/SM-8.7/OperateProcessesPage.js +2 -1
- package/dist/pages/SM-8.7/PlayPage.d.ts +1 -0
- package/dist/pages/SM-8.7/PlayPage.js +12 -1
- package/dist/pages/SM-8.7/TaskDetailsPage.js +22 -2
- package/dist/tests/8.9/orchestration-cluster-mcp-server/mcp-cluster-tools.spec.d.ts +1 -0
- package/dist/tests/8.9/orchestration-cluster-mcp-server/mcp-cluster-tools.spec.js +75 -0
- package/dist/tests/8.9/test-setup.spec.js +25 -0
- package/dist/tests/SM-8.6/connectors-user-flows.spec.js +6 -2
- package/dist/tests/SM-8.7/connectors-user-flows.spec.js +4 -4
- package/dist/utils/apiHelpers.d.ts +5 -5
- package/dist/utils/apiHelpers.js +63 -15
- package/dist/utils/mcpSecrets.d.ts +11 -0
- package/dist/utils/mcpSecrets.js +13 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Page, Locator } from '@playwright/test';
|
|
2
2
|
import { ClientCredentialsDetailsPage } from './ClientCredentialsDetailsPage';
|
|
3
|
+
import { McpCredentials } from '../../utils/mcpSecrets';
|
|
3
4
|
declare class ClusterDetailsPage {
|
|
4
5
|
private page;
|
|
5
6
|
readonly apiTab: Locator;
|
|
@@ -40,6 +41,9 @@ declare class ClusterDetailsPage {
|
|
|
40
41
|
readonly clientCredentialsLink: (clientCredentials: string) => Locator;
|
|
41
42
|
readonly clientRow: (name: string) => Locator;
|
|
42
43
|
readonly clientRowDeleteButton: (name: string) => Locator;
|
|
44
|
+
readonly mcpSupportToggle: Locator;
|
|
45
|
+
readonly mcpTab: Locator;
|
|
46
|
+
readonly mcpTextarea: Locator;
|
|
43
47
|
constructor(page: Page);
|
|
44
48
|
clickAPITab(): Promise<void>;
|
|
45
49
|
clickCreateClientButton(): Promise<void>;
|
|
@@ -66,7 +70,7 @@ declare class ClusterDetailsPage {
|
|
|
66
70
|
deleteAlerts(): Promise<void>;
|
|
67
71
|
private doDelete;
|
|
68
72
|
assertComponentsHealth(components?: string[]): Promise<void>;
|
|
69
|
-
createAPIClientAndReturnVariables(name: string, setEnvVariables?: boolean): Promise<{
|
|
73
|
+
createAPIClientAndReturnVariables(name: string, setEnvVariables?: boolean, clusterType?: string): Promise<{
|
|
70
74
|
[key: string]: string;
|
|
71
75
|
}>;
|
|
72
76
|
createAPIClient(name: string): Promise<void>;
|
|
@@ -79,5 +83,10 @@ declare class ClusterDetailsPage {
|
|
|
79
83
|
fillAPIClientName(name: string): Promise<void>;
|
|
80
84
|
assertAlertText(text: string, timeout?: number, maxRetries?: number): Promise<void>;
|
|
81
85
|
checkOrchestrationClusterCheckbox(): Promise<void>;
|
|
86
|
+
checkMcpSupportToggle(): Promise<void>;
|
|
87
|
+
clickMCPTab(): Promise<void>;
|
|
88
|
+
clickMCPTextarea(): Promise<void>;
|
|
89
|
+
getMcpConfigurationText(): Promise<string>;
|
|
90
|
+
createMCPClientAndReturnVariables(name: string, setEnvVariables?: boolean): Promise<McpCredentials>;
|
|
82
91
|
}
|
|
83
92
|
export { ClusterDetailsPage };
|
|
@@ -46,6 +46,9 @@ class ClusterDetailsPage {
|
|
|
46
46
|
clientCredentialsLink;
|
|
47
47
|
clientRow;
|
|
48
48
|
clientRowDeleteButton;
|
|
49
|
+
mcpSupportToggle;
|
|
50
|
+
mcpTab;
|
|
51
|
+
mcpTextarea;
|
|
49
52
|
constructor(page) {
|
|
50
53
|
this.page = page;
|
|
51
54
|
this.apiTab = page.getByRole('tab', { name: 'API' });
|
|
@@ -128,6 +131,11 @@ class ClusterDetailsPage {
|
|
|
128
131
|
this.clientCredentialsLink = (clientCredentials) => page.getByRole('cell', { name: clientCredentials });
|
|
129
132
|
this.clientRow = (name) => this.clientsList.filter({ hasText: name });
|
|
130
133
|
this.clientRowDeleteButton = (name) => this.clientRow(name).getByRole('button', { name: 'Delete' });
|
|
134
|
+
this.mcpSupportToggle = page.getByRole('switch', {
|
|
135
|
+
name: /Enable MCP Support/i,
|
|
136
|
+
});
|
|
137
|
+
this.mcpTab = page.getByRole('tab', { name: 'MCP' });
|
|
138
|
+
this.mcpTextarea = page.getByLabel('MCP', { exact: true }).locator('pre');
|
|
131
139
|
}
|
|
132
140
|
async clickAPITab() {
|
|
133
141
|
await (0, test_1.expect)(this.apiTab).toBeVisible({ timeout: 60000 });
|
|
@@ -355,7 +363,7 @@ class ClusterDetailsPage {
|
|
|
355
363
|
});
|
|
356
364
|
}
|
|
357
365
|
}
|
|
358
|
-
async createAPIClientAndReturnVariables(name, setEnvVariables = true) {
|
|
366
|
+
async createAPIClientAndReturnVariables(name, setEnvVariables = true, clusterType) {
|
|
359
367
|
await this.createAPIClient(name);
|
|
360
368
|
await this.clickEnvVarsButton();
|
|
361
369
|
const variables = {
|
|
@@ -367,13 +375,31 @@ class ClusterDetailsPage {
|
|
|
367
375
|
optimizeBaseUrl: await this.clientCredentialsText(/export CAMUNDA_OPTIMIZE_BASE_URL='([^']+)'/),
|
|
368
376
|
};
|
|
369
377
|
if (setEnvVariables) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
378
|
+
if (clusterType) {
|
|
379
|
+
// Use cluster-specific suffixed env vars
|
|
380
|
+
const suffix = clusterType.toUpperCase().replace(/[\s-]/g, '_');
|
|
381
|
+
process.env[`ZEEBE_API_CLIENT_ID_${suffix}`] = variables.zeebeClientId;
|
|
382
|
+
process.env[`ZEEBE_API_CLIENT_SECRET_${suffix}`] =
|
|
383
|
+
variables.zeebeClientSecret;
|
|
384
|
+
process.env[`ZEEBE_API_AUTH_URL_${suffix}`] = variables.zeebeAuthUrl;
|
|
385
|
+
process.env[`ZEEBE_API_URL_${suffix}`] = variables.zeebeUrl;
|
|
386
|
+
process.env[`ZEEBE_API_TOKEN_AUDIENCE_${suffix}`] =
|
|
387
|
+
variables.tokenAudience;
|
|
388
|
+
process.env[`CAMUNDA_OPTIMIZE_BASE_URL_${suffix}`] =
|
|
389
|
+
variables.optimizeBaseUrl;
|
|
390
|
+
console.log(`[ClusterDetailsPage] Set credentials for cluster type: ${clusterType}`);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
// Default/Test cluster - use standard env vars (existing behavior)
|
|
394
|
+
process.env.ZEEBE_API_CLIENT_ID = variables.zeebeClientId;
|
|
395
|
+
process.env.ZEEBE_API_CLIENT_SECRET = variables.zeebeClientSecret;
|
|
396
|
+
process.env.ZEEBE_API_AUTH_URL = variables.zeebeAuthUrl;
|
|
397
|
+
process.env.ZEEBE_API_URL = variables.zeebeUrl;
|
|
398
|
+
process.env.ZEEBE_API_TOKEN_AUDIENCE = variables.tokenAudience;
|
|
399
|
+
process.env.CAMUNDA_OPTIMIZE_BASE_URL = variables.optimizeBaseUrl;
|
|
400
|
+
process.env.OPTIMIZE_API_TOKEN_AUDIENCE = 'optimize.ultrawombat.com';
|
|
401
|
+
console.log('[ClusterDetailsPage] Set credentials for default Test Cluster');
|
|
402
|
+
}
|
|
377
403
|
}
|
|
378
404
|
return variables;
|
|
379
405
|
}
|
|
@@ -475,5 +501,49 @@ class ClusterDetailsPage {
|
|
|
475
501
|
await this.orchestrationClusterCheckbox.click();
|
|
476
502
|
}
|
|
477
503
|
}
|
|
504
|
+
async checkMcpSupportToggle() {
|
|
505
|
+
if (!(await this.mcpSupportToggle.isVisible())) {
|
|
506
|
+
throw new Error('MCP Support toggle is not visible');
|
|
507
|
+
}
|
|
508
|
+
// Only click if not already enabled to avoid disabling on reruns
|
|
509
|
+
if (!(await this.mcpSupportToggle.isChecked())) {
|
|
510
|
+
await this.mcpSupportToggle.click({ force: true });
|
|
511
|
+
}
|
|
512
|
+
await (0, test_1.expect)(this.mcpSupportToggle).toBeChecked();
|
|
513
|
+
}
|
|
514
|
+
async clickMCPTab() {
|
|
515
|
+
await (0, test_1.expect)(this.mcpTab).toBeVisible({ timeout: 60000 });
|
|
516
|
+
await this.mcpTab.click();
|
|
517
|
+
}
|
|
518
|
+
async clickMCPTextarea() {
|
|
519
|
+
await (0, test_1.expect)(this.mcpTextarea).toBeVisible({ timeout: 60000 });
|
|
520
|
+
await this.mcpTextarea.click();
|
|
521
|
+
}
|
|
522
|
+
async getMcpConfigurationText() {
|
|
523
|
+
await (0, test_1.expect)(this.mcpTextarea).toBeVisible({ timeout: 60000 });
|
|
524
|
+
return await this.mcpTextarea.innerText();
|
|
525
|
+
}
|
|
526
|
+
async createMCPClientAndReturnVariables(name, setEnvVariables = true) {
|
|
527
|
+
await this.createAPIClient(name);
|
|
528
|
+
await this.clickMCPTab();
|
|
529
|
+
const mcpConfigText = await this.getMcpConfigurationText();
|
|
530
|
+
const mcpConfig = JSON.parse(mcpConfigText);
|
|
531
|
+
const env = mcpConfig.servers.camunda.env;
|
|
532
|
+
const credentials = {
|
|
533
|
+
baseURL: env.CAMUNDA_BASE_URL,
|
|
534
|
+
clientID: env.CAMUNDA_CLIENT_ID,
|
|
535
|
+
clientSecret: env.CAMUNDA_CLIENT_SECRET,
|
|
536
|
+
OauthURL: env.CAMUNDA_OAUTH_URL,
|
|
537
|
+
tokenAudience: env.CAMUNDA_TOKEN_AUDIENCE,
|
|
538
|
+
};
|
|
539
|
+
if (setEnvVariables) {
|
|
540
|
+
process.env.MCP_BASE_URL = credentials.baseURL;
|
|
541
|
+
process.env.MCP_CLIENT_ID = credentials.clientID;
|
|
542
|
+
process.env.MCP_CLIENT_SECRET = credentials.clientSecret;
|
|
543
|
+
process.env.MCP_OAUTH_URL = credentials.OauthURL;
|
|
544
|
+
process.env.MCP_TOKEN_AUDIENCE = credentials.tokenAudience;
|
|
545
|
+
}
|
|
546
|
+
return credentials;
|
|
547
|
+
}
|
|
478
548
|
}
|
|
479
549
|
exports.ClusterDetailsPage = ClusterDetailsPage;
|
|
@@ -521,6 +521,7 @@ class ModelerCreatePage {
|
|
|
521
521
|
await this.tasklistAudienceTextbox.fill('tasklist-api');
|
|
522
522
|
await this.continueToPlayButton.click({ timeout });
|
|
523
523
|
await (0, test_1.expect)(this.page.getByText('Play environment is ready')).toBeVisible({ timeout: 90000 });
|
|
524
|
+
await (0, test_1.expect)(this.dialog).not.toBeVisible();
|
|
524
525
|
return; // Exit if successful
|
|
525
526
|
}
|
|
526
527
|
catch (error) {
|
|
@@ -44,6 +44,7 @@ class OperateProcessesPage {
|
|
|
44
44
|
this.tenantDropdownOption = (name) => page.getByRole('option', { name: name });
|
|
45
45
|
}
|
|
46
46
|
async checkCheckbox(checkbox) {
|
|
47
|
+
await checkbox.waitFor({ state: 'visible', timeout: constants_1._1_SECOND_IN_MS * 10 });
|
|
47
48
|
if (!(await checkbox.isChecked())) {
|
|
48
49
|
await checkbox.click();
|
|
49
50
|
await (0, test_1.expect)(checkbox).toBeChecked({
|
|
@@ -157,7 +158,7 @@ class OperateProcessesPage {
|
|
|
157
158
|
throw new Error(`Failed to open instance "${processName}" after ${MAX_ATTEMPTS} attempts. Last error: ${String(err)}`);
|
|
158
159
|
}
|
|
159
160
|
await this.page.reload();
|
|
160
|
-
await (0, sleep_1.sleep)(
|
|
161
|
+
await (0, sleep_1.sleep)(5000);
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
}
|
|
@@ -2,6 +2,11 @@ import { Page, Locator } from '@playwright/test';
|
|
|
2
2
|
declare class PlayPage {
|
|
3
3
|
private page;
|
|
4
4
|
readonly completeJobButton: Locator;
|
|
5
|
+
readonly restartProcess: Locator;
|
|
6
|
+
readonly diagram: Locator;
|
|
7
|
+
readonly startInstanceButton: Locator;
|
|
8
|
+
readonly loadingInstanceDetailsText: Locator;
|
|
9
|
+
readonly dialog: Locator;
|
|
5
10
|
constructor(page: Page);
|
|
6
11
|
waitForCompleteJobButtonToBeAvailable(): Promise<void>;
|
|
7
12
|
clickCompleteJobButton(): Promise<void>;
|
|
@@ -2,15 +2,30 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PlayPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
+
const sleep_1 = require("../../utils/sleep");
|
|
5
6
|
const maxWaitTimeSeconds = 120000;
|
|
6
7
|
class PlayPage {
|
|
7
8
|
page;
|
|
8
9
|
completeJobButton;
|
|
10
|
+
restartProcess;
|
|
11
|
+
diagram;
|
|
12
|
+
startInstanceButton;
|
|
13
|
+
loadingInstanceDetailsText;
|
|
14
|
+
dialog;
|
|
9
15
|
constructor(page) {
|
|
10
16
|
this.page = page;
|
|
11
17
|
this.completeJobButton = page
|
|
12
18
|
.getByTestId('diagram')
|
|
13
19
|
.getByLabel('Complete job');
|
|
20
|
+
this.restartProcess = this.page.getByRole('button', {
|
|
21
|
+
name: 'Restart process',
|
|
22
|
+
});
|
|
23
|
+
this.diagram = page.getByTestId('diagram');
|
|
24
|
+
this.startInstanceButton = this.page
|
|
25
|
+
.getByTestId('diagram')
|
|
26
|
+
.getByLabel('Start instance');
|
|
27
|
+
this.loadingInstanceDetailsText = this.page.getByText('Loading instance details...');
|
|
28
|
+
this.dialog = page.getByRole('dialog');
|
|
14
29
|
}
|
|
15
30
|
async waitForCompleteJobButtonToBeAvailable() {
|
|
16
31
|
await (0, test_1.expect)(this.completeJobButton).toBeVisible({
|
|
@@ -21,7 +36,27 @@ class PlayPage {
|
|
|
21
36
|
await this.completeJobButton.click();
|
|
22
37
|
}
|
|
23
38
|
async clickStartInstanceButton() {
|
|
24
|
-
|
|
39
|
+
const maxRetries = 3;
|
|
40
|
+
let attempts = 0;
|
|
41
|
+
while (attempts < maxRetries) {
|
|
42
|
+
try {
|
|
43
|
+
await this.diagram.waitFor({ state: 'visible', timeout: 30000 });
|
|
44
|
+
await this.startInstanceButton.click({ timeout: 30000 });
|
|
45
|
+
await (0, test_1.expect)(this.loadingInstanceDetailsText).toBeVisible();
|
|
46
|
+
await (0, test_1.expect)(this.loadingInstanceDetailsText).not.toBeVisible({
|
|
47
|
+
timeout: 60000,
|
|
48
|
+
});
|
|
49
|
+
await (0, test_1.expect)(this.dialog).not.toBeVisible({ timeout: 15000 });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (attempts >= maxRetries - 1)
|
|
54
|
+
throw error;
|
|
55
|
+
await this.page.reload();
|
|
56
|
+
await (0, sleep_1.sleep)(2000);
|
|
57
|
+
attempts++;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
25
60
|
}
|
|
26
61
|
async dismissStartModal() {
|
|
27
62
|
await this.page
|
|
@@ -31,7 +66,7 @@ class PlayPage {
|
|
|
31
66
|
.click();
|
|
32
67
|
}
|
|
33
68
|
async waitForInstanceDetailsToBeLoaded() {
|
|
34
|
-
const maxRetries =
|
|
69
|
+
const maxRetries = 3;
|
|
35
70
|
let attempts = 0;
|
|
36
71
|
while (attempts < maxRetries) {
|
|
37
72
|
try {
|
|
@@ -47,6 +82,9 @@ class PlayPage {
|
|
|
47
82
|
if (attempts >= maxRetries - 1)
|
|
48
83
|
throw error;
|
|
49
84
|
await this.page.reload();
|
|
85
|
+
const startButton = this.restartProcess.or(this.startInstanceButton);
|
|
86
|
+
await startButton.waitFor({ state: 'visible', timeout: 30000 });
|
|
87
|
+
await startButton.click();
|
|
50
88
|
attempts++;
|
|
51
89
|
}
|
|
52
90
|
}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TaskDetailsPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
+
const sleep_1 = require("../../utils/sleep");
|
|
6
|
+
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
5
7
|
function cardinalToOrdinal(numberValue) {
|
|
6
8
|
const realOrderIndex = numberValue.toString();
|
|
7
9
|
if (['11', '12', '13'].includes(realOrderIndex.slice(-2))) {
|
|
@@ -96,15 +98,36 @@ class TaskDetailsPage {
|
|
|
96
98
|
.getByText('Assigned to me');
|
|
97
99
|
}
|
|
98
100
|
async clickAssignToMeButton() {
|
|
99
|
-
await this.assignToMeButton.
|
|
101
|
+
await (0, test_1.expect)(this.assignToMeButton).toBeVisible({ timeout: 60000 });
|
|
102
|
+
await this.assignToMeButton.click({ timeout: 60000 });
|
|
103
|
+
await (0, sleep_1.sleep)(1000);
|
|
104
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.assignedToMeText, {
|
|
105
|
+
postAction: async () => {
|
|
106
|
+
await this.page.reload();
|
|
107
|
+
await (0, sleep_1.sleep)(5000);
|
|
108
|
+
if (await this.assignToMeButton.isVisible()) {
|
|
109
|
+
await this.assignToMeButton.click({ timeout: 60000 });
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
});
|
|
100
113
|
}
|
|
101
114
|
async clickUnassignButton() {
|
|
102
115
|
await this.unassignButton.click();
|
|
103
116
|
}
|
|
104
117
|
async clickCompleteTaskButton() {
|
|
105
118
|
await this.completeTaskButton.click({ timeout: 60000 });
|
|
106
|
-
await (0, test_1.expect)(this.
|
|
107
|
-
timeout:
|
|
119
|
+
await (0, test_1.expect)(this.page.getByText('Completing task...')).not.toBeVisible({
|
|
120
|
+
timeout: 60000,
|
|
121
|
+
});
|
|
122
|
+
await (0, sleep_1.sleep)(1000);
|
|
123
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.taskCompletedBanner, {
|
|
124
|
+
postAction: async () => {
|
|
125
|
+
await this.page.reload();
|
|
126
|
+
await (0, sleep_1.sleep)(5000);
|
|
127
|
+
if (await this.completeTaskButton.isVisible()) {
|
|
128
|
+
await this.completeTaskButton.click({ timeout: 60000 });
|
|
129
|
+
}
|
|
130
|
+
},
|
|
108
131
|
});
|
|
109
132
|
}
|
|
110
133
|
async clickAddVariableButton() {
|
|
@@ -612,6 +612,7 @@ class ModelerCreatePage {
|
|
|
612
612
|
await this.switchToPlay(); // Call switchToPlay on subsequent attempts
|
|
613
613
|
await this.continueToPlayButton.click({ timeout });
|
|
614
614
|
await (0, test_1.expect)(this.page.getByText('Play environment is ready')).toBeVisible({ timeout: 90000 });
|
|
615
|
+
await (0, test_1.expect)(this.dialog).not.toBeVisible();
|
|
615
616
|
return; // Exit if successful
|
|
616
617
|
}
|
|
617
618
|
catch (error) {
|
|
@@ -42,6 +42,7 @@ class OperateProcessesPage {
|
|
|
42
42
|
this.tenantDropdownOption = page.getByRole('option', { name: 'All tenants' });
|
|
43
43
|
}
|
|
44
44
|
async checkCheckbox(checkbox) {
|
|
45
|
+
await checkbox.waitFor({ state: 'visible', timeout: constants_1._1_SECOND_IN_MS * 10 });
|
|
45
46
|
if (!(await checkbox.isChecked())) {
|
|
46
47
|
await checkbox.click();
|
|
47
48
|
await (0, test_1.expect)(checkbox).toBeChecked({
|
|
@@ -151,7 +152,7 @@ class OperateProcessesPage {
|
|
|
151
152
|
throw new Error(`Failed to open instance "${processName}" after ${MAX_ATTEMPTS} attempts. Last error: ${String(err)}`);
|
|
152
153
|
}
|
|
153
154
|
await this.page.reload({ waitUntil: 'domcontentloaded' });
|
|
154
|
-
await (0, sleep_1.sleep)(
|
|
155
|
+
await (0, sleep_1.sleep)(5000);
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
}
|
|
@@ -18,6 +18,7 @@ declare class PlayPage {
|
|
|
18
18
|
readonly dialog: Locator;
|
|
19
19
|
readonly loadingInstanceDetailsText: Locator;
|
|
20
20
|
readonly retryButton: Locator;
|
|
21
|
+
readonly restartProcess: Locator;
|
|
21
22
|
constructor(page: Page);
|
|
22
23
|
waitForCompleteJobButtonToBeAvailable(): Promise<void>;
|
|
23
24
|
clickCompleteJobButton(): Promise<void>;
|
|
@@ -25,6 +25,7 @@ class PlayPage {
|
|
|
25
25
|
dialog;
|
|
26
26
|
loadingInstanceDetailsText;
|
|
27
27
|
retryButton;
|
|
28
|
+
restartProcess;
|
|
28
29
|
constructor(page) {
|
|
29
30
|
this.page = page;
|
|
30
31
|
this.completeJobButton = page
|
|
@@ -55,6 +56,9 @@ class PlayPage {
|
|
|
55
56
|
this.saveScenarioModal = page.getByTestId('save-scenario-modal');
|
|
56
57
|
this.loadingInstanceDetailsText = this.page.getByText('Loading instance details...');
|
|
57
58
|
this.retryButton = this.page.getByRole('button', { name: 'Retry' });
|
|
59
|
+
this.restartProcess = this.page.getByRole('button', {
|
|
60
|
+
name: 'Restart process',
|
|
61
|
+
});
|
|
58
62
|
}
|
|
59
63
|
async waitForCompleteJobButtonToBeAvailable() {
|
|
60
64
|
await (0, test_1.expect)(this.completeJobButton).toBeVisible({
|
|
@@ -75,6 +79,7 @@ class PlayPage {
|
|
|
75
79
|
await (0, test_1.expect)(this.loadingInstanceDetailsText).not.toBeVisible({
|
|
76
80
|
timeout: 60000,
|
|
77
81
|
});
|
|
82
|
+
await (0, test_1.expect)(this.dialog).not.toBeVisible({ timeout: 15000 });
|
|
78
83
|
return;
|
|
79
84
|
}
|
|
80
85
|
catch (error) {
|
|
@@ -104,7 +109,7 @@ class PlayPage {
|
|
|
104
109
|
throw new Error('Could not find start instance button with any expected variation');
|
|
105
110
|
}
|
|
106
111
|
async waitForInstanceDetailsToBeLoaded() {
|
|
107
|
-
const maxRetries =
|
|
112
|
+
const maxRetries = 3;
|
|
108
113
|
let attempts = 0;
|
|
109
114
|
while (attempts < maxRetries) {
|
|
110
115
|
try {
|
|
@@ -120,6 +125,9 @@ class PlayPage {
|
|
|
120
125
|
if (attempts >= maxRetries - 1)
|
|
121
126
|
throw error;
|
|
122
127
|
await this.page.reload();
|
|
128
|
+
const startButton = this.restartProcess.or(this.startInstanceButton);
|
|
129
|
+
await startButton.waitFor({ state: 'visible', timeout: 30000 });
|
|
130
|
+
await startButton.click();
|
|
123
131
|
attempts++;
|
|
124
132
|
}
|
|
125
133
|
}
|
|
@@ -150,6 +158,9 @@ class PlayPage {
|
|
|
150
158
|
await (0, test_1.expect)(this.page.getByText(/completed/i)).toBeVisible({
|
|
151
159
|
timeout: maxWaitTimeSeconds,
|
|
152
160
|
});
|
|
161
|
+
await (0, test_1.expect)(this.page.getByText(/completed/i)).not.toBeVisible({
|
|
162
|
+
timeout: 60000,
|
|
163
|
+
});
|
|
153
164
|
}
|
|
154
165
|
async clickSaveScenarioButton() {
|
|
155
166
|
await this.notifications
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TaskDetailsPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const sleep_1 = require("../../utils/sleep");
|
|
6
|
+
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
6
7
|
function cardinalToOrdinal(numberValue) {
|
|
7
8
|
const realOrderIndex = numberValue.toString();
|
|
8
9
|
if (['11', '12', '13'].includes(realOrderIndex.slice(-2))) {
|
|
@@ -101,14 +102,33 @@ class TaskDetailsPage {
|
|
|
101
102
|
await (0, test_1.expect)(this.assignToMeButton).toBeVisible({ timeout: 60000 });
|
|
102
103
|
await this.assignToMeButton.click({ timeout: 60000 });
|
|
103
104
|
await (0, sleep_1.sleep)(1000);
|
|
105
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.assignedToMeText, {
|
|
106
|
+
postAction: async () => {
|
|
107
|
+
await this.page.reload();
|
|
108
|
+
await (0, sleep_1.sleep)(5000);
|
|
109
|
+
if (await this.assignToMeButton.isVisible()) {
|
|
110
|
+
await this.assignToMeButton.click({ timeout: 60000 });
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
});
|
|
104
114
|
}
|
|
105
115
|
async clickUnassignButton() {
|
|
106
116
|
await this.unassignButton.click();
|
|
107
117
|
}
|
|
108
118
|
async clickCompleteTaskButton() {
|
|
109
119
|
await this.completeTaskButton.click({ timeout: 60000 });
|
|
110
|
-
await (0, test_1.expect)(this.
|
|
111
|
-
timeout:
|
|
120
|
+
await (0, test_1.expect)(this.page.getByText('Completing task...')).not.toBeVisible({
|
|
121
|
+
timeout: 60000,
|
|
122
|
+
});
|
|
123
|
+
await (0, sleep_1.sleep)(1000);
|
|
124
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.taskCompletedBanner, {
|
|
125
|
+
postAction: async () => {
|
|
126
|
+
await this.page.reload();
|
|
127
|
+
await (0, sleep_1.sleep)(5000);
|
|
128
|
+
if (await this.completeTaskButton.isVisible()) {
|
|
129
|
+
await this.completeTaskButton.click({ timeout: 60000 });
|
|
130
|
+
}
|
|
131
|
+
},
|
|
112
132
|
});
|
|
113
133
|
}
|
|
114
134
|
async clickAddVariableButton() {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const _8_9_1 = require("../../../fixtures/8.9");
|
|
4
|
+
const UtilitiesPage_1 = require("../../../pages/8.9/UtilitiesPage");
|
|
5
|
+
const _setup_1 = require("../../../test-setup.js");
|
|
6
|
+
const apiHelpers_1 = require("../../../utils/apiHelpers");
|
|
7
|
+
const users_1 = require("../../../utils/users");
|
|
8
|
+
const test_1 = require("@playwright/test");
|
|
9
|
+
const testUser = (0, users_1.getTestUser)('fourteenthUser');
|
|
10
|
+
let authToken;
|
|
11
|
+
let instanceKey;
|
|
12
|
+
_8_9_1.test.describe.configure({ mode: 'parallel' });
|
|
13
|
+
_8_9_1.test.describe('Orchestration Cluster MCP Server - Cluster Tools', () => {
|
|
14
|
+
const clusterName = 'Agentic Orchestration Cluster';
|
|
15
|
+
_8_9_1.test.beforeAll(async () => {
|
|
16
|
+
authToken = await (0, apiHelpers_1.authSaasAPI)(undefined, 'agentic_cluster');
|
|
17
|
+
const processDefinitionKey = await (0, apiHelpers_1.deployProcess)('./resources/mcp_server_saas/mcp_cluster_tools.bpmn', authToken, 'saas', 'agentic_cluster');
|
|
18
|
+
if (processDefinitionKey == null) {
|
|
19
|
+
throw new Error('Failed to deploy cluster tools process');
|
|
20
|
+
}
|
|
21
|
+
instanceKey = await (0, apiHelpers_1.createProcessInstance)(String(processDefinitionKey), authToken, 'saas', 'agentic_cluster');
|
|
22
|
+
});
|
|
23
|
+
_8_9_1.test.beforeEach(async ({ page, loginPage }, testInfo) => {
|
|
24
|
+
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, testUser, (testInfo.workerIndex + 1) * 1000);
|
|
25
|
+
});
|
|
26
|
+
_8_9_1.test.afterEach(async ({ page }, testInfo) => {
|
|
27
|
+
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
28
|
+
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
29
|
+
});
|
|
30
|
+
const clusterToolTests = [
|
|
31
|
+
{
|
|
32
|
+
name: 'getClusterStatus - returns cluster health status',
|
|
33
|
+
variable: 'mcpResultClusterStatus',
|
|
34
|
+
assertions: [
|
|
35
|
+
{
|
|
36
|
+
text: 'HEALTHY',
|
|
37
|
+
description: 'cluster status response contains healthy field',
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'getTopology - returns cluster topology information',
|
|
43
|
+
variable: 'mcpResultTopology',
|
|
44
|
+
assertions: [
|
|
45
|
+
{ text: 'brokers', description: 'topology response contains brokers' },
|
|
46
|
+
{
|
|
47
|
+
text: 'partitionsCount',
|
|
48
|
+
description: 'topology response contains partitions count',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
for (const testCase of clusterToolTests) {
|
|
54
|
+
(0, _8_9_1.test)(testCase.name, async ({ homePage, appsPage, operateHomePage, operateProcessesPage, operateProcessInstancePage, }) => {
|
|
55
|
+
_8_9_1.test.slow();
|
|
56
|
+
await _8_9_1.test.step('Navigate to completed process in Operate', async () => {
|
|
57
|
+
await homePage.clickClusters();
|
|
58
|
+
await appsPage.clickOperate(clusterName);
|
|
59
|
+
await (0, test_1.expect)(operateHomePage.operateBanner).toBeVisible({
|
|
60
|
+
timeout: 60000,
|
|
61
|
+
});
|
|
62
|
+
await operateHomePage.clickProcessesTab();
|
|
63
|
+
await operateProcessesPage.clickProcessCompletedCheckbox();
|
|
64
|
+
await operateProcessesPage.applyMoreFilters('Process Instance Key(s)', String(instanceKey));
|
|
65
|
+
await operateProcessesPage.clickProcessInstanceLink('MCP Cluster tools');
|
|
66
|
+
await operateProcessInstancePage.assertProcessCompleteStatusWithRetry();
|
|
67
|
+
});
|
|
68
|
+
for (const assertion of testCase.assertions) {
|
|
69
|
+
await _8_9_1.test.step(`Verify ${assertion.description}`, async () => {
|
|
70
|
+
await operateProcessInstancePage.assertProcessVariableContainsText(testCase.variable, assertion.text);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
@@ -5,6 +5,7 @@ const _8_9_1 = require("../../fixtures/8.9");
|
|
|
5
5
|
const _setup_1 = require("../../test-setup.js");
|
|
6
6
|
const sleep_1 = require("../../utils/sleep");
|
|
7
7
|
const connectorSecrets_1 = require("../../utils/connectorSecrets");
|
|
8
|
+
const mcpSecrets_1 = require("../../utils/mcpSecrets");
|
|
8
9
|
const UtilitiesPage_1 = require("../../pages/8.9/UtilitiesPage");
|
|
9
10
|
const users_1 = require("../../utils/users");
|
|
10
11
|
_8_9_1.test.describe.configure({ mode: 'parallel' });
|
|
@@ -51,6 +52,30 @@ _8_9_1.test.describe('Cluster Setup Tests', () => {
|
|
|
51
52
|
await clusterSecretsPage.createSetOfSecrets(clusterName, connectorSecrets_1.connectorSecretsValues);
|
|
52
53
|
}
|
|
53
54
|
});
|
|
55
|
+
(0, _8_9_1.test)('Create Agentic Orchestration Cluster', async ({ page, loginPage, homePage, clusterPage, clusterDetailsPage, clusterSecretsPage, }, testInfo) => {
|
|
56
|
+
_8_9_1.test.slow();
|
|
57
|
+
const clusterName = 'Agentic Orchestration Cluster';
|
|
58
|
+
const apiClientName = 'Test_API_Client' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
59
|
+
const mcpClientName = 'MCP_Test_API_Client' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
60
|
+
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, users_1.testUsers.mainUser, (testInfo.workerIndex + 1) * 1000);
|
|
61
|
+
await homePage.clickClusters();
|
|
62
|
+
await clusterPage.createCluster(clusterName);
|
|
63
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(clusterName);
|
|
64
|
+
await clusterPage.clickClusterLink(clusterName);
|
|
65
|
+
await clusterDetailsPage.assertComponentsHealth();
|
|
66
|
+
await clusterDetailsPage.clickSettingsTab();
|
|
67
|
+
await clusterDetailsPage.checkMcpSupportToggle();
|
|
68
|
+
await homePage.clickClusters();
|
|
69
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(clusterName);
|
|
70
|
+
await clusterPage.clickClusterLink(clusterName);
|
|
71
|
+
await clusterDetailsPage.clickAPITab();
|
|
72
|
+
await clusterDetailsPage.createAPIClientAndReturnVariables(apiClientName, true, 'agentic_cluster');
|
|
73
|
+
await clusterDetailsPage.clickCloseModalButton();
|
|
74
|
+
const mcpCredentials = await clusterDetailsPage.createMCPClientAndReturnVariables(mcpClientName);
|
|
75
|
+
await clusterDetailsPage.clickCloseModalButton();
|
|
76
|
+
await clusterPage.clickConnectorSecretsTab(clusterName);
|
|
77
|
+
await clusterSecretsPage.createSetOfSecrets(clusterName, (0, mcpSecrets_1.mcpSecretsValues)(mcpCredentials));
|
|
78
|
+
});
|
|
54
79
|
(0, _8_9_1.test)('Create AWS Cluster', async ({ page, loginPage, homePage, clusterPage, clusterDetailsPage, clusterSecretsPage, }, testInfo) => {
|
|
55
80
|
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, users_1.testUsers.mainUser, (testInfo.workerIndex + 1) * 1000);
|
|
56
81
|
_8_9_1.test.slow();
|
|
@@ -5,6 +5,8 @@ const SM_8_6_1 = require("../../fixtures/SM-8.6");
|
|
|
5
5
|
const _setup_1 = require("../../test-setup.js");
|
|
6
6
|
const UtlitiesPage_1 = require("../../pages/SM-8.6/UtlitiesPage");
|
|
7
7
|
const sleep_1 = require("../../utils/sleep");
|
|
8
|
+
const apiHelpers_1 = require("../../utils/apiHelpers");
|
|
9
|
+
const constants_1 = require("../../utils/constants");
|
|
8
10
|
SM_8_6_1.test.describe.configure({ mode: 'parallel' });
|
|
9
11
|
SM_8_6_1.test.describe('Connectors User Flow Tests', () => {
|
|
10
12
|
SM_8_6_1.test.beforeEach(async ({ navigationPage }, testInfo) => {
|
|
@@ -204,8 +206,10 @@ SM_8_6_1.test.describe('Connectors User Flow Tests', () => {
|
|
|
204
206
|
await SM_8_6_1.test.step('Make Authorization Request', async () => {
|
|
205
207
|
const baseURL = process.env.PLAYWRIGHT_BASE_URL ||
|
|
206
208
|
`http://gke-${process.env.BASE_URL}.ci.distro.ultrawombat.com`;
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
await (0, test_1.expect)(async () => {
|
|
210
|
+
const response = await request.post(`${baseURL}/connectors/inbound/test-webhook-id${randomString}`);
|
|
211
|
+
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
212
|
+
}).toPass(constants_1.defaultAssertionOptions);
|
|
209
213
|
await (0, sleep_1.sleep)(30000);
|
|
210
214
|
});
|
|
211
215
|
await SM_8_6_1.test.step('Assert Diagram Has Successfully Completed in Operate', async () => {
|
|
@@ -99,8 +99,8 @@ SM_8_7_1.test.describe.parallel('Connectors User Flow Tests', () => {
|
|
|
99
99
|
await SM_8_7_1.test.step('Make Authorization Request', async () => {
|
|
100
100
|
const baseURL = process.env.PLAYWRIGHT_BASE_URL ||
|
|
101
101
|
`http://gke-${process.env.BASE_URL}.ci.distro.ultrawombat.com`;
|
|
102
|
-
const timeout =
|
|
103
|
-
const interval =
|
|
102
|
+
const timeout = 60000;
|
|
103
|
+
const interval = 5000;
|
|
104
104
|
const startTime = Date.now();
|
|
105
105
|
let response;
|
|
106
106
|
while (Date.now() - startTime < timeout) {
|
|
@@ -171,8 +171,8 @@ SM_8_7_1.test.describe.parallel('Connectors User Flow Tests', () => {
|
|
|
171
171
|
`http://gke-${process.env.BASE_URL}.ci.distro.ultrawombat.com`;
|
|
172
172
|
// It takes about 6 seconds for the process to appear in the connectors endpoint
|
|
173
173
|
// So we need to wait for it to appear before making the request
|
|
174
|
-
const timeout =
|
|
175
|
-
const interval =
|
|
174
|
+
const timeout = 60000;
|
|
175
|
+
const interval = 5000;
|
|
176
176
|
const startTime = Date.now();
|
|
177
177
|
let response;
|
|
178
178
|
while (Date.now() - startTime < timeout) {
|
|
@@ -7,14 +7,14 @@ export declare function authAPI(environment: 'saas'): Promise<string>;
|
|
|
7
7
|
export declare function authAPI(environment: 'sm'): Promise<string>;
|
|
8
8
|
export declare function authAPI(environment: 'saas', audience?: string): Promise<string>;
|
|
9
9
|
export declare function authAPI(environment: 'sm', audience?: string): Promise<string>;
|
|
10
|
-
export declare function authSaasAPI(audience?: string): Promise<string>;
|
|
10
|
+
export declare function authSaasAPI(audience?: string, clusterType?: string): Promise<string>;
|
|
11
11
|
export declare function authSmAPI(): Promise<string>;
|
|
12
12
|
export declare function authC8runAPI(name: string, password: string): Promise<void>;
|
|
13
13
|
export declare function validateMcpServerHealth(serverUrl?: string): Promise<APIResponse>;
|
|
14
|
-
export declare function deployProcess(filePath: string, authToken?: string, environment?: 'saas' | 'sm'): Promise<number | null>;
|
|
15
|
-
export declare function createProcessInstance(processDefinitionKey: string, authToken?: string, environment?: 'saas' | 'sm'): Promise<string>;
|
|
16
|
-
export declare function createJsonClusterVariable(authToken?: string, environment?: 'saas' | 'sm', customVariableName?: string, customVariableValue?: string): Promise<void>;
|
|
17
|
-
export declare function createStringClusterVariable(authToken?: string, environment?: 'saas' | 'sm', customVariableName?: string, customVariableValue?: string): Promise<void>;
|
|
14
|
+
export declare function deployProcess(filePath: string, authToken?: string, environment?: 'saas' | 'sm', clusterType?: string): Promise<number | null>;
|
|
15
|
+
export declare function createProcessInstance(processDefinitionKey: string, authToken?: string, environment?: 'saas' | 'sm', clusterType?: string): Promise<string>;
|
|
16
|
+
export declare function createJsonClusterVariable(authToken?: string, environment?: 'saas' | 'sm', customVariableName?: string, customVariableValue?: string, clusterType?: string): Promise<void>;
|
|
17
|
+
export declare function createStringClusterVariable(authToken?: string, environment?: 'saas' | 'sm', customVariableName?: string, customVariableValue?: string, clusterType?: string): Promise<void>;
|
|
18
18
|
/**
|
|
19
19
|
* @deprecated This function will be removed when SM-8.9 cluster variables test is updated.
|
|
20
20
|
* Use createJsonClusterVariable() for JSON variables or
|
package/dist/utils/apiHelpers.js
CHANGED
|
@@ -45,6 +45,29 @@ async function sendRequestAndAssertResponse(request, url, requestBody, maxRetrie
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
exports.sendRequestAndAssertResponse = sendRequestAndAssertResponse;
|
|
48
|
+
// ---- Cluster Credentials Helper ----
|
|
49
|
+
function getClusterCredentials(clusterType) {
|
|
50
|
+
if (!clusterType) {
|
|
51
|
+
return {
|
|
52
|
+
clientId: process.env.ZEEBE_API_CLIENT_ID,
|
|
53
|
+
clientSecret: process.env.ZEEBE_API_CLIENT_SECRET,
|
|
54
|
+
authUrl: process.env.ZEEBE_API_AUTH_URL,
|
|
55
|
+
apiUrl: process.env.ZEEBE_API_URL,
|
|
56
|
+
tokenAudience: process.env.ZEEBE_API_TOKEN_AUDIENCE,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const suffix = clusterType.toUpperCase().replace(/[\s-]/g, '_');
|
|
60
|
+
const clientId = process.env[`ZEEBE_API_CLIENT_ID_${suffix}`];
|
|
61
|
+
const clientSecret = process.env[`ZEEBE_API_CLIENT_SECRET_${suffix}`];
|
|
62
|
+
const authUrl = process.env[`ZEEBE_API_AUTH_URL_${suffix}`];
|
|
63
|
+
const apiUrl = process.env[`ZEEBE_API_URL_${suffix}`];
|
|
64
|
+
const tokenAudience = process.env[`ZEEBE_API_TOKEN_AUDIENCE_${suffix}`];
|
|
65
|
+
if (!clientId || !clientSecret || !authUrl || !apiUrl || !tokenAudience) {
|
|
66
|
+
throw new Error(`Credentials for cluster type "${clusterType}" not found. ` +
|
|
67
|
+
`Expected env vars: ZEEBE_API_CLIENT_ID_${suffix}, etc.`);
|
|
68
|
+
}
|
|
69
|
+
return { clientId, clientSecret, authUrl, apiUrl, tokenAudience };
|
|
70
|
+
}
|
|
48
71
|
// ---- Zeebe: URL building (SaaS vs SM) ----
|
|
49
72
|
function inferZeebeEnvironment(override) {
|
|
50
73
|
if (override) {
|
|
@@ -65,8 +88,13 @@ function normalizeOrigin(value, defaultProtocol = 'https') {
|
|
|
65
88
|
}
|
|
66
89
|
return `${defaultProtocol}://${trimmed}`;
|
|
67
90
|
}
|
|
68
|
-
function getZeebeApiOrigin(environment) {
|
|
91
|
+
function getZeebeApiOrigin(environment, clusterType) {
|
|
69
92
|
if (environment === 'saas') {
|
|
93
|
+
// Use cluster-specific credentials if clusterType provided
|
|
94
|
+
if (clusterType) {
|
|
95
|
+
const creds = getClusterCredentials(clusterType);
|
|
96
|
+
return creds.apiUrl.replace(/\/+$/, '');
|
|
97
|
+
}
|
|
70
98
|
const saasUrl = process.env.ZEEBE_API_URL?.trim();
|
|
71
99
|
if (!saasUrl) {
|
|
72
100
|
throw new Error('Missing ZEEBE_API_URL (SaaS).');
|
|
@@ -79,9 +107,9 @@ function getZeebeApiOrigin(environment) {
|
|
|
79
107
|
}
|
|
80
108
|
throw new Error('Missing BASE_URL (SM).');
|
|
81
109
|
}
|
|
82
|
-
function buildZeebeApiUrl(resourcePath, environmentOverride) {
|
|
110
|
+
function buildZeebeApiUrl(resourcePath, environmentOverride, clusterType) {
|
|
83
111
|
const environment = inferZeebeEnvironment(environmentOverride);
|
|
84
|
-
const baseUrl = getZeebeApiOrigin(environment);
|
|
112
|
+
const baseUrl = getZeebeApiOrigin(environment, clusterType);
|
|
85
113
|
const normalizedPath = resourcePath.startsWith('/')
|
|
86
114
|
? resourcePath
|
|
87
115
|
: `/${resourcePath}`;
|
|
@@ -136,8 +164,28 @@ async function authAPI(environment, audience = process.env.ZEEBE_API_TOKEN_AUDIE
|
|
|
136
164
|
return bearerToken;
|
|
137
165
|
}
|
|
138
166
|
exports.authAPI = authAPI;
|
|
139
|
-
async function authSaasAPI(audience
|
|
140
|
-
|
|
167
|
+
async function authSaasAPI(audience, clusterType) {
|
|
168
|
+
const creds = getClusterCredentials(clusterType);
|
|
169
|
+
const tokenAudience = audience ?? creds.tokenAudience;
|
|
170
|
+
apiRequestContext = await getApiRequestContext();
|
|
171
|
+
const tokenResponse = await apiRequestContext.post(creds.authUrl, {
|
|
172
|
+
headers: {
|
|
173
|
+
'Content-Type': 'application/json',
|
|
174
|
+
},
|
|
175
|
+
data: {
|
|
176
|
+
audience: tokenAudience,
|
|
177
|
+
client_id: creds.clientId,
|
|
178
|
+
client_secret: creds.clientSecret,
|
|
179
|
+
grant_type: 'client_credentials',
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
if (tokenResponse.status() !== 200) {
|
|
183
|
+
const errorBody = await tokenResponse.text();
|
|
184
|
+
throw new Error(`Failed to fetch access token. Response: ${errorBody}`);
|
|
185
|
+
}
|
|
186
|
+
const tokenJson = await tokenResponse.json();
|
|
187
|
+
const bearerToken = `Bearer ${tokenJson.access_token}`;
|
|
188
|
+
return bearerToken;
|
|
141
189
|
}
|
|
142
190
|
exports.authSaasAPI = authSaasAPI;
|
|
143
191
|
async function authSmAPI() {
|
|
@@ -179,7 +227,7 @@ async function validateMcpServerHealth(serverUrl) {
|
|
|
179
227
|
}
|
|
180
228
|
exports.validateMcpServerHealth = validateMcpServerHealth;
|
|
181
229
|
// ---- Zeebe: API helpers ----
|
|
182
|
-
async function deployProcess(filePath, authToken, environment) {
|
|
230
|
+
async function deployProcess(filePath, authToken, environment, clusterType) {
|
|
183
231
|
try {
|
|
184
232
|
apiRequestContext = await getApiRequestContext();
|
|
185
233
|
const fileContent = fs_1.default.readFileSync(filePath);
|
|
@@ -195,7 +243,7 @@ async function deployProcess(filePath, authToken, environment) {
|
|
|
195
243
|
mimeType,
|
|
196
244
|
buffer: fileContent,
|
|
197
245
|
};
|
|
198
|
-
const url = buildZeebeApiUrl('/v2/deployments', environment);
|
|
246
|
+
const url = buildZeebeApiUrl('/v2/deployments', environment, clusterType);
|
|
199
247
|
const response = await apiRequestContext.post(url, {
|
|
200
248
|
headers: {
|
|
201
249
|
Authorization: authToken ?? '',
|
|
@@ -221,9 +269,9 @@ async function deployProcess(filePath, authToken, environment) {
|
|
|
221
269
|
}
|
|
222
270
|
}
|
|
223
271
|
exports.deployProcess = deployProcess;
|
|
224
|
-
async function createProcessInstance(processDefinitionKey, authToken, environment) {
|
|
272
|
+
async function createProcessInstance(processDefinitionKey, authToken, environment, clusterType) {
|
|
225
273
|
apiRequestContext = await getApiRequestContext();
|
|
226
|
-
const url = buildZeebeApiUrl('/v2/process-instances', environment);
|
|
274
|
+
const url = buildZeebeApiUrl('/v2/process-instances', environment, clusterType);
|
|
227
275
|
const response = await apiRequestContext.post(url, {
|
|
228
276
|
headers: {
|
|
229
277
|
Authorization: authToken ?? '',
|
|
@@ -242,10 +290,10 @@ async function createProcessInstance(processDefinitionKey, authToken, environmen
|
|
|
242
290
|
return String(processInstanceKey);
|
|
243
291
|
}
|
|
244
292
|
exports.createProcessInstance = createProcessInstance;
|
|
245
|
-
async function createClusterVariableInternal(authToken, environment, variableName, variableValue, variableType) {
|
|
293
|
+
async function createClusterVariableInternal(authToken, environment, variableName, variableValue, variableType, clusterType) {
|
|
246
294
|
try {
|
|
247
295
|
apiRequestContext = await getApiRequestContext();
|
|
248
|
-
const url = buildZeebeApiUrl('/v2/cluster-variables/global', environment);
|
|
296
|
+
const url = buildZeebeApiUrl('/v2/cluster-variables/global', environment, clusterType);
|
|
249
297
|
const response = await apiRequestContext.post(url, {
|
|
250
298
|
headers: {
|
|
251
299
|
Authorization: authToken,
|
|
@@ -276,18 +324,18 @@ async function createClusterVariableInternal(authToken, environment, variableNam
|
|
|
276
324
|
throw new Error(`Unexpected error creating ${variableType} cluster variable "${variableName}": ${errorMessage}`);
|
|
277
325
|
}
|
|
278
326
|
}
|
|
279
|
-
async function createJsonClusterVariable(authToken, environment = 'saas', customVariableName, customVariableValue) {
|
|
327
|
+
async function createJsonClusterVariable(authToken, environment = 'saas', customVariableName, customVariableValue, clusterType) {
|
|
280
328
|
const variableName = customVariableName ?? String(process.env.CLUSTER_VARIABLE_NAME);
|
|
281
329
|
const variableValue = customVariableValue
|
|
282
330
|
? JSON.parse(customVariableValue)
|
|
283
331
|
: JSON.parse(process.env.CLUSTER_VARIABLE_JSON);
|
|
284
|
-
await createClusterVariableInternal(authToken ?? '', environment, variableName, variableValue, 'JSON');
|
|
332
|
+
await createClusterVariableInternal(authToken ?? '', environment, variableName, variableValue, 'JSON', clusterType);
|
|
285
333
|
}
|
|
286
334
|
exports.createJsonClusterVariable = createJsonClusterVariable;
|
|
287
|
-
async function createStringClusterVariable(authToken, environment = 'saas', customVariableName, customVariableValue) {
|
|
335
|
+
async function createStringClusterVariable(authToken, environment = 'saas', customVariableName, customVariableValue, clusterType) {
|
|
288
336
|
const variableName = customVariableName ?? String(process.env.CLUSTER_VARIABLE_STRING_NAME);
|
|
289
337
|
const variableValue = customVariableValue ?? process.env.CLUSTER_VARIABLE_STRING_VALUE;
|
|
290
|
-
await createClusterVariableInternal(authToken ?? '', environment, variableName, variableValue, 'String');
|
|
338
|
+
await createClusterVariableInternal(authToken ?? '', environment, variableName, variableValue, 'String', clusterType);
|
|
291
339
|
}
|
|
292
340
|
exports.createStringClusterVariable = createStringClusterVariable;
|
|
293
341
|
/**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type McpCredentials = {
|
|
2
|
+
baseURL: string;
|
|
3
|
+
clientID: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
OauthURL: string;
|
|
6
|
+
tokenAudience: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function mcpSecretsValues(credentials: McpCredentials): {
|
|
9
|
+
name: string;
|
|
10
|
+
value: string;
|
|
11
|
+
}[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mcpSecretsValues = void 0;
|
|
4
|
+
function mcpSecretsValues(credentials) {
|
|
5
|
+
return [
|
|
6
|
+
{ name: 'MCP_BASE_URL', value: credentials.baseURL },
|
|
7
|
+
{ name: 'MCP_CLIENT_ID', value: credentials.clientID },
|
|
8
|
+
{ name: 'MCP_CLIENT_SECRET', value: credentials.clientSecret },
|
|
9
|
+
{ name: 'MCP_OAUTH_URL', value: credentials.OauthURL },
|
|
10
|
+
{ name: 'MCP_TOKEN_AUDIENCE', value: credentials.tokenAudience },
|
|
11
|
+
];
|
|
12
|
+
}
|
|
13
|
+
exports.mcpSecretsValues = mcpSecretsValues;
|