@camunda/e2e-test-suite 0.0.243 → 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.
@@ -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
- process.env.ZEEBE_API_CLIENT_ID = variables.zeebeClientId;
371
- process.env.ZEEBE_API_CLIENT_SECRET = variables.zeebeClientSecret;
372
- process.env.ZEEBE_API_AUTH_URL = variables.zeebeAuthUrl;
373
- process.env.ZEEBE_API_URL = variables.zeebeUrl;
374
- process.env.ZEEBE_API_TOKEN_AUDIENCE = variables.tokenAudience;
375
- process.env.CAMUNDA_OPTIMIZE_BASE_URL = variables.optimizeBaseUrl;
376
- process.env.OPTIMIZE_API_TOKEN_AUDIENCE = 'optimize.ultrawombat.com';
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)(1000);
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
- await this.page.getByTestId('diagram').getByLabel('Start instance').click();
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 = 2;
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.click();
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.taskCompletedBanner).toBeVisible({
107
- timeout: 200000,
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() {
@@ -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
- const response = await request.post(`${baseURL}/connectors/inbound/test-webhook-id${randomString}`);
208
- await (0, test_1.expect)(response.status()).toBe(200);
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 () => {
@@ -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
@@ -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 = process.env.ZEEBE_API_TOKEN_AUDIENCE) {
140
- return authAPI('saas', audience);
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.243",
3
+ "version": "0.0.244",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",