@camunda/e2e-test-suite 0.0.210 → 0.0.211

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/README.md CHANGED
@@ -245,6 +245,66 @@ IS_MT=true
245
245
  #### C8 Run
246
246
  To test locally against C8 Run, you must set up a local instance of C8 Run. Please follow the instructions provided in the [C8 Run README.md](https://github.com/camunda/camunda/blob/main/c8run/README.md). By default, the BASE_URL is localhost:8080, however if this is configured as something differently, tests can be run against this by inputting the new BASE_URL into your `.env` file under the `PLAYWRIGHT_BASE_URL` variable.
247
247
 
248
+ ## Running MCP Tests (c8Run Only)
249
+
250
+ The MCP (Model Context Protocol) test suite requires the MCP test server to be running locally. These tests are designed for **c8Run environments only**, as they require localhost access to the MCP server.
251
+
252
+ The MCP test server is available as a Docker image from the [camunda/mcp](https://github.com/camunda/mcp) repository.
253
+
254
+ ### Running MCP Tests Locally
255
+
256
+ To run MCP tests locally with c8Run, you need to start both the MCP test server and c8Run:
257
+
258
+ 1. Start the MCP server:
259
+
260
+ ```bash
261
+ docker run -d \
262
+ --name mcp-test-server \
263
+ --network host \
264
+ registry.camunda.cloud/mcp/mcp-test-server:latest
265
+ ```
266
+
267
+ 2. Start c8Run locally (follow [c8Run setup instructions](https://github.com/camunda/camunda/blob/main/c8run/README.md))
268
+
269
+ 3. Run the MCP tests:
270
+
271
+ ```bash
272
+ npx playwright test --project=chromium-v2 tests/c8Run-8.9/mcp-user-flows.spec.ts
273
+ ```
274
+
275
+ 4. Stop the MCP server when done:
276
+
277
+ ```bash
278
+ docker stop mcp-test-server && docker rm mcp-test-server
279
+ ```
280
+
281
+ ### MCP Server Configuration
282
+
283
+ The MCP test server runs on port `12001` by default and provides the following endpoints:
284
+
285
+ - **MCP Endpoint**: `http://localhost:12001/mcp`
286
+ - **Health Check**: `http://localhost:12001/actuator/health`
287
+
288
+ You can override the MCP server URL by setting the `MCP_SERVER_URL` environment variable in your `.env` file:
289
+
290
+ ```bash
291
+ MCP_SERVER_URL=http://localhost:12001
292
+ ```
293
+
294
+ ### Available MCP Tools
295
+
296
+ The MCP test server provides the following tools for testing:
297
+
298
+ - **String Tools**: `echo`, `uppercase`, `lowercase`, `base64Encode`, `base64Decode`
299
+ - **Greeting Tools**: `greet` (supports EN, DE, ES, IT)
300
+ - **Calculator Tools**: `add`
301
+
302
+ For more details about the MCP server and its capabilities, see the [MCP repository](https://github.com/camunda/mcp).
303
+
304
+ ### CI/CD Integration
305
+
306
+ In c8Run CI/CD pipelines (Linux, macOS, Windows), the MCP server is automatically started before running tests and stopped after tests complete. No additional configuration is required.
307
+
248
308
  ## Automated Nightly Test Runs
249
309
 
250
310
  The test suite is configured to run automatically every night. The results of these nightly test runs are published on TestRail. If any test fails during these automated runs, the Designated Responsible Individual (DRI) of the project is notified via email for immediate attention and resolution. On a nightly basis, the test suite is configured to run the following tests:
@@ -11,7 +11,9 @@ declare class OperateProcessInstancePage {
11
11
  constructor(page: Page);
12
12
  connectorResultVariableName(name: string): Promise<Locator>;
13
13
  connectorResultVariableValue(variableName: string): Promise<Locator>;
14
+ getProcessVariableValue(variableName: string): Promise<Locator>;
14
15
  completedIconAssertion(): Promise<void>;
15
16
  activeIconAssertion(): Promise<void>;
17
+ assertProcessVariableContainsText(variableName: string, text: string): Promise<void>;
16
18
  }
17
19
  export { OperateProcessInstancePage };
@@ -32,6 +32,12 @@ class OperateProcessInstancePage {
32
32
  async connectorResultVariableValue(variableName) {
33
33
  return await this.page.getByTestId(variableName).locator('td').last();
34
34
  }
35
+ async getProcessVariableValue(variableName) {
36
+ return await this.page
37
+ .getByTestId(`variable-${variableName}`)
38
+ .getByRole('cell')
39
+ .nth(1);
40
+ }
35
41
  async completedIconAssertion() {
36
42
  let retryCount = 0;
37
43
  const maxRetries = 6;
@@ -72,5 +78,21 @@ class OperateProcessInstancePage {
72
78
  }
73
79
  throw new Error(`Active icon not visible after ${maxRetries} attempts.`);
74
80
  }
81
+ async assertProcessVariableContainsText(variableName, text) {
82
+ const maxRetries = 3;
83
+ for (let retries = 0; retries < maxRetries; retries++) {
84
+ try {
85
+ const valueCell = await this.getProcessVariableValue(variableName);
86
+ await (0, test_1.expect)(valueCell).toContainText(text, { timeout: 30000 });
87
+ return;
88
+ }
89
+ catch (error) {
90
+ console.log(`Failed to assert variable ${variableName}: ${error}`);
91
+ await this.page.reload();
92
+ await (0, sleep_1.sleep)(10000);
93
+ }
94
+ }
95
+ throw new Error(`Failed to assert variable ${variableName} contains ${text} after ${maxRetries} attempts.`);
96
+ }
75
97
  }
76
98
  exports.OperateProcessInstancePage = OperateProcessInstancePage;
@@ -6,6 +6,10 @@ const TaskPanelPage_1 = require("../../pages/8.9/TaskPanelPage");
6
6
  const TaskDetailsPage_1 = require("../../pages/8.9/TaskDetailsPage");
7
7
  const AppsPage_1 = require("../../pages/8.9/AppsPage");
8
8
  const OperateProcessInstancePage_1 = require("../../pages/8.9/OperateProcessInstancePage");
9
+ // TODO: Re-enable Optimize imports when bug is fixed
10
+ // import {OptimizeHomePage} from '../../pages/8.9/OptimizeHomePage';
11
+ // import {OptimizeDashboardPage} from '../../pages/8.9/OptimizeDashboardPage';
12
+ const fileUpload_1 = require("../../utils/fileUpload");
9
13
  const _setup_1 = require("../../test-setup.js");
10
14
  const UtilitiesPage_1 = require("../../pages/8.9/UtilitiesPage");
11
15
  const deleteOrg_1 = require("../../utils/deleteOrg");
@@ -541,4 +545,58 @@ _8_9_1.test.describe('Web Modeler User Flow Tests', () => {
541
545
  await operateProcessInstancePage.assertProcessCompleteStatusWithRetry(40000);
542
546
  });
543
547
  });
548
+ (0, _8_9_1.test)('Conditional Events - Deploy, verify in Operate and verify process in Optimize dashboard @tasklistV2', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, }) => {
549
+ _8_9_1.test.slow();
550
+ const bpmnFileName = 'Conditional_Events_All.bpmn';
551
+ // TODO: Uncomment when Optimize tests are re-enabled
552
+ // const processName = 'Conditional Events Auto-Run';
553
+ await _8_9_1.test.step('Navigate to Web Modeler', async () => {
554
+ await (0, test_1.expect)(homePage.camundaComponentsButton).toBeVisible({
555
+ timeout: 120000,
556
+ });
557
+ await appsPage.clickCamundaApps();
558
+ await appsPage.clickModeler();
559
+ await (0, test_1.expect)(modelerHomePage.modelerPageBanner).toBeVisible({
560
+ timeout: 180000,
561
+ });
562
+ });
563
+ await _8_9_1.test.step('Open Cross Component Test Project and upload BPMN file', async () => {
564
+ await modelerHomePage.clickCrossComponentProjectFolder();
565
+ await modelerHomePage.clickDiagramTypeDropdown();
566
+ await modelerHomePage.clickUploadFilesButton();
567
+ await (0, fileUpload_1.uploadFile)(page, bpmnFileName);
568
+ });
569
+ await _8_9_1.test.step('Open uploaded BPMN diagram', async () => {
570
+ await (0, sleep_1.sleep)(5000);
571
+ await modelerHomePage.clickProcessDiagram(bpmnFileName.replace('.bpmn', ''));
572
+ });
573
+ await _8_9_1.test.step('Deploy and run process with variable', async () => {
574
+ const variables = '{"myVar": 8}';
575
+ await modelerCreatePage.runProcessInstance(clusterName, variables);
576
+ });
577
+ await _8_9_1.test.step('View process instance in Operate and verify completion', async () => {
578
+ await (0, test_1.expect)(modelerCreatePage.viewProcessInstanceLink).toBeVisible({
579
+ timeout: 120000,
580
+ });
581
+ await modelerCreatePage.clickViewProcessInstanceLink();
582
+ const operateTabPromise = page.waitForEvent('popup', { timeout: 60000 });
583
+ const operateTab = await operateTabPromise;
584
+ // TODO: Uncomment when Optimize tests are re-enabled
585
+ // const operateTabAppsPage = new AppsPage(operateTab);
586
+ const operateProcessInstancePage = new OperateProcessInstancePage_1.OperateProcessInstancePage(operateTab);
587
+ await operateProcessInstancePage.assertProcessCompleteStatusWithRetry(60000, 15);
588
+ await operateProcessInstancePage.assertProcessVariableContainsText('myVar', '8');
589
+ // //Skipped due to bug 46344: https://github.com/camunda/camunda/issues/46344
590
+ // await test.step('Navigate to Optimize and verify process in dashboard', async () => {
591
+ // const operateTabAppsPage = new AppsPage(operateTab);
592
+ // await operateTabAppsPage.clickCamundaApps();
593
+ // await operateTabAppsPage.clickOptimize(clusterName);
594
+ // const optimizeHomePage = new OptimizeHomePage(operateTab);
595
+ // const optimizeDashboardPage = new OptimizeDashboardPage(operateTab);
596
+ // await optimizeHomePage.clickDashboardLink();
597
+ // await sleep(60000);
598
+ // await optimizeDashboardPage.processLinkAssertion(processName, 5);
599
+ // });
600
+ });
601
+ });
544
602
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const c8Run_8_9_1 = require("../../fixtures/c8Run-8.9");
4
+ const UtilitiesPage_1 = require("../../pages/c8Run-8.9/UtilitiesPage");
5
+ const _setup_1 = require("../../test-setup.js");
6
+ const apiHelpers_1 = require("../../utils/apiHelpers");
7
+ const zeebeClient_1 = require("../../utils/zeebeClient");
8
+ const sleep_1 = require("../../utils/sleep");
9
+ c8Run_8_9_1.test.beforeAll(async () => {
10
+ await (0, apiHelpers_1.validateMcpServerHealth)();
11
+ await (0, zeebeClient_1.deploy)('./resources/mcp_server/mcp_server_list_tools.bpmn');
12
+ await (0, zeebeClient_1.createInstances)('mcp_remote_client', 1, 1);
13
+ await (0, sleep_1.sleep)(5000);
14
+ });
15
+ c8Run_8_9_1.test.beforeEach(async ({ page, operateLoginPage, operateHomePage }) => {
16
+ await (0, UtilitiesPage_1.navigateToApp)(page, 'operate');
17
+ await operateLoginPage.login('demo', 'demo');
18
+ await operateHomePage.operateBannerIsVisible();
19
+ });
20
+ c8Run_8_9_1.test.describe('@tasklistV2 MCP Test Server User Flows', () => {
21
+ c8Run_8_9_1.test.afterEach(async ({ page }, testInfo) => {
22
+ await (0, _setup_1.captureScreenshot)(page, testInfo);
23
+ await (0, _setup_1.captureFailureVideo)(page, testInfo);
24
+ });
25
+ (0, c8Run_8_9_1.test)('MCP server returns list of tools from process', async ({ operateHomePage, operateProcessInstancePage, operateProcessesPage, }) => {
26
+ c8Run_8_9_1.test.slow();
27
+ await c8Run_8_9_1.test.step('User can access the completed process on operate', async () => {
28
+ await operateHomePage.clickProcessesTab();
29
+ await operateProcessesPage.clickProcessCompletedCheckbox();
30
+ await operateProcessesPage.clickProcessInstanceLink('mcp_remote_client');
31
+ await operateProcessInstancePage.completedIconAssertion();
32
+ });
33
+ await c8Run_8_9_1.test.step('Verify MCP tools are returned in the process result', async () => {
34
+ await operateProcessInstancePage.assertProcessVariableContainsText('toolCallResult', 'add');
35
+ await operateProcessInstancePage.assertProcessVariableContainsText('toolCallResult', 'greet');
36
+ await operateProcessInstancePage.assertProcessVariableContainsText('toolCallResult', 'echo');
37
+ });
38
+ });
39
+ });
@@ -10,6 +10,7 @@ export declare function authAPI(environment: 'sm', audience?: string): Promise<s
10
10
  export declare function authSaasAPI(audience?: string): Promise<string>;
11
11
  export declare function authSmAPI(): Promise<string>;
12
12
  export declare function authC8runAPI(name: string, password: string): Promise<void>;
13
+ export declare function validateMcpServerHealth(serverUrl?: string): Promise<APIResponse>;
13
14
  export declare function deployProcess(filePath: string, authToken?: string, environment?: 'saas' | 'sm'): Promise<number | null>;
14
15
  export declare function createProcessInstance(processDefinitionKey: string, authToken?: string, environment?: 'saas' | 'sm'): Promise<string>;
15
16
  export declare function createGlobalClusterVariable(authToken?: string, environment?: 'saas' | 'sm'): Promise<void>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.updateCollectionScope = exports.createSingleProcessReport = exports.createDashboard = exports.createCollection = exports.getOptimizeCoockie = exports.createGlobalClusterVariable = exports.createProcessInstance = exports.deployProcess = exports.authC8runAPI = exports.authSmAPI = exports.authSaasAPI = exports.authAPI = exports.sendRequestAndAssertResponse = exports.assertResponseStatus = void 0;
6
+ exports.updateCollectionScope = exports.createSingleProcessReport = exports.createDashboard = exports.createCollection = exports.getOptimizeCoockie = exports.createGlobalClusterVariable = exports.createProcessInstance = exports.deployProcess = exports.validateMcpServerHealth = exports.authC8runAPI = exports.authSmAPI = exports.authSaasAPI = exports.authAPI = exports.sendRequestAndAssertResponse = exports.assertResponseStatus = void 0;
7
7
  const test_1 = require("@playwright/test");
8
8
  const sleep_1 = require("./sleep");
9
9
  const fs_1 = __importDefault(require("fs"));
@@ -156,6 +156,28 @@ async function authC8runAPI(name, password) {
156
156
  await apiRequestContext.storageState({ path: 'utils/.auth' });
157
157
  }
158
158
  exports.authC8runAPI = authC8runAPI;
159
+ // ---- MCP Server Health Check ----
160
+ async function validateMcpServerHealth(serverUrl) {
161
+ apiRequestContext = await getApiRequestContext();
162
+ const mcpServerUrl = serverUrl || process.env.MCP_SERVER_URL || 'http://localhost:12001';
163
+ const healthEndpoint = `${mcpServerUrl}/actuator/health`;
164
+ try {
165
+ const response = await apiRequestContext.get(healthEndpoint);
166
+ if (response.status() !== 200) {
167
+ const errorBody = await response.text();
168
+ throw new Error(`MCP server health check failed with status ${response.status()}. Response: ${errorBody}`);
169
+ }
170
+ return response;
171
+ }
172
+ catch (error) {
173
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
174
+ throw new Error(`MCP server is not available at ${healthEndpoint}. ` +
175
+ `Error: ${errorMessage}. ` +
176
+ 'Please ensure the MCP docker container is running with: ' +
177
+ 'docker run -d --name mcp-test-server --network host registry.camunda.cloud/mcp/mcp-test-server:latest');
178
+ }
179
+ }
180
+ exports.validateMcpServerHealth = validateMcpServerHealth;
159
181
  // ---- Zeebe: API helpers ----
160
182
  async function deployProcess(filePath, authToken, environment) {
161
183
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.210",
3
+ "version": "0.0.211",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",