@camunda/e2e-test-suite 0.0.483 → 0.0.485
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.10/ClusterDetailsPage.d.ts +9 -1
- package/dist/pages/8.10/ClusterDetailsPage.js +72 -8
- package/dist/pages/SM-8.10/ModelerCreatePage.d.ts +1 -0
- package/dist/pages/SM-8.10/ModelerCreatePage.js +6 -0
- package/dist/pages/SM-8.10/PlayPage.js +48 -42
- package/dist/tests/8.10/orchestration-cluster-mcp-server/mcp-cluster-tools.spec.d.ts +1 -0
- package/dist/tests/8.10/orchestration-cluster-mcp-server/mcp-cluster-tools.spec.js +75 -0
- package/dist/tests/8.10/orchestration-cluster-mcp-server/mcp-incident-tools.spec.d.ts +1 -0
- package/dist/tests/8.10/orchestration-cluster-mcp-server/mcp-incident-tools.spec.js +123 -0
- package/dist/tests/8.10/test-setup.spec.js +27 -0
- package/dist/tests/SM-8.10/play.spec.js +22 -43
- package/package.json +1 -1
- package/resources/Play_Test_User_Service_Task.bpmn +56 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Page, Locator } from '@playwright/test';
|
|
2
|
+
import { McpCredentials } from '../../utils/mcpSecrets';
|
|
2
3
|
import { ClientCredentialsDetailsPage } from './ClientCredentialsDetailsPage';
|
|
3
4
|
declare class ClusterDetailsPage {
|
|
4
5
|
private page;
|
|
@@ -41,6 +42,9 @@ declare class ClusterDetailsPage {
|
|
|
41
42
|
readonly reviewUpdateButton: Locator;
|
|
42
43
|
readonly updateAvailableDialog: Locator;
|
|
43
44
|
readonly updateButton: Locator;
|
|
45
|
+
readonly mcpSupportToggle: Locator;
|
|
46
|
+
readonly mcpTab: Locator;
|
|
47
|
+
readonly mcpTextarea: Locator;
|
|
44
48
|
constructor(page: Page);
|
|
45
49
|
clickAPITab(): Promise<void>;
|
|
46
50
|
clickCreateClientButton(): Promise<void>;
|
|
@@ -67,7 +71,7 @@ declare class ClusterDetailsPage {
|
|
|
67
71
|
deleteAlerts(): Promise<void>;
|
|
68
72
|
private doDelete;
|
|
69
73
|
assertComponentsHealth(components?: string[]): Promise<void>;
|
|
70
|
-
createAPIClientAndReturnVariables(name: string, setEnvVariables?: boolean): Promise<{
|
|
74
|
+
createAPIClientAndReturnVariables(name: string, setEnvVariables?: boolean, clusterType?: string): Promise<{
|
|
71
75
|
[key: string]: string;
|
|
72
76
|
}>;
|
|
73
77
|
createAPIClient(name: string): Promise<void>;
|
|
@@ -82,5 +86,9 @@ declare class ClusterDetailsPage {
|
|
|
82
86
|
checkOrchestrationClusterCheckbox(): Promise<void>;
|
|
83
87
|
clickReviewUpdateButton(): Promise<void>;
|
|
84
88
|
performClusterUpdate(): Promise<void>;
|
|
89
|
+
checkMcpSupportToggle(): Promise<void>;
|
|
90
|
+
clickMCPTab(): Promise<void>;
|
|
91
|
+
getMcpConfigurationText(): Promise<string>;
|
|
92
|
+
createMCPClientAndReturnVariables(name: string, setEnvVariables?: boolean): Promise<McpCredentials>;
|
|
85
93
|
}
|
|
86
94
|
export { ClusterDetailsPage };
|
|
@@ -47,6 +47,9 @@ class ClusterDetailsPage {
|
|
|
47
47
|
reviewUpdateButton;
|
|
48
48
|
updateAvailableDialog;
|
|
49
49
|
updateButton;
|
|
50
|
+
mcpSupportToggle;
|
|
51
|
+
mcpTab;
|
|
52
|
+
mcpTextarea;
|
|
50
53
|
constructor(page) {
|
|
51
54
|
this.page = page;
|
|
52
55
|
this.apiTab = page.getByRole('tab', { name: 'API' });
|
|
@@ -145,6 +148,11 @@ class ClusterDetailsPage {
|
|
|
145
148
|
this.updateButton = this.updateAvailableDialog.getByRole('button', {
|
|
146
149
|
name: 'Update',
|
|
147
150
|
});
|
|
151
|
+
this.mcpSupportToggle = page.getByRole('switch', {
|
|
152
|
+
name: /Enable MCP Support/i,
|
|
153
|
+
});
|
|
154
|
+
this.mcpTab = page.getByRole('tab', { name: 'MCP' });
|
|
155
|
+
this.mcpTextarea = page.getByRole('textbox', { name: 'Copy to clipboard' });
|
|
148
156
|
}
|
|
149
157
|
async clickAPITab() {
|
|
150
158
|
await (0, test_1.expect)(this.apiTab).toBeVisible({ timeout: 60000 });
|
|
@@ -372,7 +380,7 @@ class ClusterDetailsPage {
|
|
|
372
380
|
});
|
|
373
381
|
}
|
|
374
382
|
}
|
|
375
|
-
async createAPIClientAndReturnVariables(name, setEnvVariables = true) {
|
|
383
|
+
async createAPIClientAndReturnVariables(name, setEnvVariables = true, clusterType) {
|
|
376
384
|
await this.createAPIClient(name);
|
|
377
385
|
await this.clickEnvVarsButton();
|
|
378
386
|
const variables = {
|
|
@@ -384,13 +392,29 @@ class ClusterDetailsPage {
|
|
|
384
392
|
optimizeBaseUrl: await this.clientCredentialsText(/export CAMUNDA_OPTIMIZE_BASE_URL='([^']+)'/),
|
|
385
393
|
};
|
|
386
394
|
if (setEnvVariables) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
395
|
+
if (clusterType) {
|
|
396
|
+
// Use cluster-specific suffixed env vars
|
|
397
|
+
const suffix = clusterType.toUpperCase().replace(/[\s-]/g, '_');
|
|
398
|
+
process.env[`ZEEBE_API_CLIENT_ID_${suffix}`] = variables.zeebeClientId;
|
|
399
|
+
process.env[`ZEEBE_API_CLIENT_SECRET_${suffix}`] =
|
|
400
|
+
variables.zeebeClientSecret;
|
|
401
|
+
process.env[`ZEEBE_API_AUTH_URL_${suffix}`] = variables.zeebeAuthUrl;
|
|
402
|
+
process.env[`ZEEBE_API_URL_${suffix}`] = variables.zeebeUrl;
|
|
403
|
+
process.env[`ZEEBE_API_TOKEN_AUDIENCE_${suffix}`] =
|
|
404
|
+
variables.tokenAudience;
|
|
405
|
+
process.env[`CAMUNDA_OPTIMIZE_BASE_URL_${suffix}`] =
|
|
406
|
+
variables.optimizeBaseUrl;
|
|
407
|
+
console.log(`[ClusterDetailsPage] Set credentials for cluster type: ${clusterType}`);
|
|
408
|
+
}
|
|
409
|
+
else {
|
|
410
|
+
process.env.ZEEBE_API_CLIENT_ID = variables.zeebeClientId;
|
|
411
|
+
process.env.ZEEBE_API_CLIENT_SECRET = variables.zeebeClientSecret;
|
|
412
|
+
process.env.ZEEBE_API_AUTH_URL = variables.zeebeAuthUrl;
|
|
413
|
+
process.env.ZEEBE_API_URL = variables.zeebeUrl;
|
|
414
|
+
process.env.ZEEBE_API_TOKEN_AUDIENCE = variables.tokenAudience;
|
|
415
|
+
process.env.CAMUNDA_OPTIMIZE_BASE_URL = variables.optimizeBaseUrl;
|
|
416
|
+
process.env.OPTIMIZE_API_TOKEN_AUDIENCE = 'optimize.ultrawombat.com';
|
|
417
|
+
}
|
|
394
418
|
}
|
|
395
419
|
return variables;
|
|
396
420
|
}
|
|
@@ -500,5 +524,45 @@ class ClusterDetailsPage {
|
|
|
500
524
|
await (0, test_1.expect)(this.updateAvailableDialog).toBeVisible({ timeout: 30000 });
|
|
501
525
|
await this.updateButton.click({ timeout: 60000 });
|
|
502
526
|
}
|
|
527
|
+
async checkMcpSupportToggle() {
|
|
528
|
+
if (!(await this.mcpSupportToggle.isVisible())) {
|
|
529
|
+
throw new Error('MCP Support toggle is not visible');
|
|
530
|
+
}
|
|
531
|
+
// Only click if not already enabled to avoid disabling on reruns
|
|
532
|
+
if (!(await this.mcpSupportToggle.isChecked())) {
|
|
533
|
+
await this.mcpSupportToggle.click({ force: true });
|
|
534
|
+
}
|
|
535
|
+
await (0, test_1.expect)(this.mcpSupportToggle).toBeChecked();
|
|
536
|
+
}
|
|
537
|
+
async clickMCPTab() {
|
|
538
|
+
await (0, test_1.expect)(this.mcpTab).toBeVisible({ timeout: 60000 });
|
|
539
|
+
await this.mcpTab.click();
|
|
540
|
+
}
|
|
541
|
+
async getMcpConfigurationText() {
|
|
542
|
+
await (0, test_1.expect)(this.mcpTextarea).toBeVisible({ timeout: 60000 });
|
|
543
|
+
return await this.mcpTextarea.innerText();
|
|
544
|
+
}
|
|
545
|
+
async createMCPClientAndReturnVariables(name, setEnvVariables = true) {
|
|
546
|
+
await this.createAPIClient(name);
|
|
547
|
+
await this.clickMCPTab();
|
|
548
|
+
const mcpConfigText = await this.getMcpConfigurationText();
|
|
549
|
+
const mcpConfig = JSON.parse(mcpConfigText);
|
|
550
|
+
const env = Object.values(mcpConfig.servers)[0].env;
|
|
551
|
+
const credentials = {
|
|
552
|
+
baseURL: env.CAMUNDA_BASE_URL,
|
|
553
|
+
clientID: env.CAMUNDA_CLIENT_ID,
|
|
554
|
+
clientSecret: env.CAMUNDA_CLIENT_SECRET,
|
|
555
|
+
OauthURL: env.CAMUNDA_OAUTH_URL,
|
|
556
|
+
tokenAudience: env.CAMUNDA_TOKEN_AUDIENCE,
|
|
557
|
+
};
|
|
558
|
+
if (setEnvVariables) {
|
|
559
|
+
process.env.MCP_BASE_URL = credentials.baseURL;
|
|
560
|
+
process.env.MCP_CLIENT_ID = credentials.clientID;
|
|
561
|
+
process.env.MCP_CLIENT_SECRET = credentials.clientSecret;
|
|
562
|
+
process.env.MCP_OAUTH_URL = credentials.OauthURL;
|
|
563
|
+
process.env.MCP_TOKEN_AUDIENCE = credentials.tokenAudience;
|
|
564
|
+
}
|
|
565
|
+
return credentials;
|
|
566
|
+
}
|
|
503
567
|
}
|
|
504
568
|
exports.ClusterDetailsPage = ClusterDetailsPage;
|
|
@@ -119,6 +119,7 @@ declare class ModelerCreatePage {
|
|
|
119
119
|
clickViewProcessInstanceLink(): Promise<void>;
|
|
120
120
|
clickNameInput(): Promise<void>;
|
|
121
121
|
clickUserTask(id: string): Promise<void>;
|
|
122
|
+
clickCanvasElement(elementId: string): Promise<void>;
|
|
122
123
|
fillNameInput(name: string): Promise<void>;
|
|
123
124
|
clickJobTypeInput(): Promise<void>;
|
|
124
125
|
fillJobTypeInput(name: string): Promise<void>;
|
|
@@ -560,6 +560,12 @@ class ModelerCreatePage {
|
|
|
560
560
|
const priorityUserTask = this.page.locator(`[data-element-id="${id}"]`);
|
|
561
561
|
await priorityUserTask.click({ timeout: 60000 });
|
|
562
562
|
}
|
|
563
|
+
async clickCanvasElement(elementId) {
|
|
564
|
+
await this.page
|
|
565
|
+
.locator(`[data-element-id="${elementId}"]`)
|
|
566
|
+
.first()
|
|
567
|
+
.click({ timeout: 30000 });
|
|
568
|
+
}
|
|
563
569
|
async fillNameInput(name) {
|
|
564
570
|
await this.nameInput.fill(name);
|
|
565
571
|
}
|
|
@@ -65,6 +65,7 @@ class PlayPage {
|
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
async clickCompleteJobButton() {
|
|
68
|
+
await this.completeJobButton.waitFor({ state: 'visible', timeout: 30000 });
|
|
68
69
|
await this.completeJobButton.click();
|
|
69
70
|
}
|
|
70
71
|
async clickStartInstanceButton() {
|
|
@@ -72,6 +73,7 @@ class PlayPage {
|
|
|
72
73
|
let attempts = 0;
|
|
73
74
|
while (attempts < maxRetries) {
|
|
74
75
|
try {
|
|
76
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
75
77
|
await this.diagram.waitFor({ state: 'visible', timeout: 60000 });
|
|
76
78
|
await this.startInstanceButton
|
|
77
79
|
.or(this.startInstanceWithCachedButton)
|
|
@@ -86,7 +88,7 @@ class PlayPage {
|
|
|
86
88
|
catch (error) {
|
|
87
89
|
if (attempts >= maxRetries - 1)
|
|
88
90
|
throw error;
|
|
89
|
-
await
|
|
91
|
+
await this.page.waitForLoadState('load');
|
|
90
92
|
attempts++;
|
|
91
93
|
}
|
|
92
94
|
}
|
|
@@ -98,12 +100,21 @@ class PlayPage {
|
|
|
98
100
|
'Start new instance',
|
|
99
101
|
'Start instance',
|
|
100
102
|
];
|
|
101
|
-
for
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
103
|
+
// Wait for the page to settle before checking for modal buttons
|
|
104
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
105
|
+
const maxAttempts = 3;
|
|
106
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
107
|
+
for (const buttonName of buttonVariations) {
|
|
108
|
+
const button = this.page.getByRole('button', { name: buttonName });
|
|
109
|
+
const count = await button.count();
|
|
110
|
+
if (count > 0) {
|
|
111
|
+
await button.waitFor({ state: 'visible', timeout: 10000 });
|
|
112
|
+
await button.click();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (attempt < maxAttempts - 1) {
|
|
117
|
+
await this.page.waitForLoadState('load');
|
|
107
118
|
}
|
|
108
119
|
}
|
|
109
120
|
throw new Error('Could not find start instance button with any expected variation');
|
|
@@ -113,44 +124,24 @@ class PlayPage {
|
|
|
113
124
|
await this.startInstanceWithCachedButton.click({ timeout: 30000 });
|
|
114
125
|
}
|
|
115
126
|
async waitForInstanceDetailsToBeLoaded() {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
await (0, test_1.expect)(this.page.getByText(/This process instance has no variables/i)).toBeVisible({
|
|
124
|
-
timeout: maxWaitTimeSeconds,
|
|
125
|
-
});
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
if (attempts >= maxRetries - 1)
|
|
130
|
-
throw error;
|
|
131
|
-
await this.page.reload();
|
|
132
|
-
attempts++;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
127
|
+
// Do NOT use page.reload() — it destroys Play's embedded context.
|
|
128
|
+
await (0, test_1.expect)(this.page.getByText(/process instance key/i)).toBeVisible({
|
|
129
|
+
timeout: maxWaitTimeSeconds,
|
|
130
|
+
});
|
|
131
|
+
await (0, test_1.expect)(this.page.getByText(/This process instance has no variables/i)).toBeVisible({
|
|
132
|
+
timeout: maxWaitTimeSeconds,
|
|
133
|
+
});
|
|
135
134
|
}
|
|
136
135
|
async waitForNextElementToBeActive(historyItem) {
|
|
137
136
|
const locator = this.page.getByText(new RegExp(`^${historyItem}`, 'i'));
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
catch (e) {
|
|
145
|
-
if (attempt === maxRetries)
|
|
146
|
-
throw e;
|
|
147
|
-
await this.page.reload();
|
|
148
|
-
await this.diagram.waitFor({ state: 'visible', timeout: 30000 });
|
|
149
|
-
await this.page.waitForTimeout(5000);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
137
|
+
// Do NOT use page.reload() here — Play is embedded in the modeler and
|
|
138
|
+
// reloading destroys the Play instance context, making the diagram
|
|
139
|
+
// permanently invisible. Use a long timeout instead, consistent with
|
|
140
|
+
// waitForCompleteJobButtonToBeAvailable.
|
|
141
|
+
await (0, test_1.expect)(locator.first()).toBeVisible({ timeout: maxWaitTimeSeconds });
|
|
152
142
|
}
|
|
153
143
|
async waitForProcessToBeCompleted() {
|
|
144
|
+
// Do NOT use page.reload() — it destroys Play's embedded context.
|
|
154
145
|
await (0, test_1.expect)(this.page.getByText('Completed')).toBeVisible({
|
|
155
146
|
timeout: maxWaitTimeSeconds,
|
|
156
147
|
});
|
|
@@ -171,6 +162,7 @@ class PlayPage {
|
|
|
171
162
|
}
|
|
172
163
|
}
|
|
173
164
|
async clickViewScenarioButton() {
|
|
165
|
+
await this.viewScenarioButton.waitFor({ state: 'visible', timeout: 30000 });
|
|
174
166
|
await this.viewScenarioButton.click();
|
|
175
167
|
}
|
|
176
168
|
async enterScenarioName(scenarioName) {
|
|
@@ -192,6 +184,10 @@ class PlayPage {
|
|
|
192
184
|
await this.viewAllScenariosButton.click();
|
|
193
185
|
}
|
|
194
186
|
async confirmSaveScenario() {
|
|
187
|
+
await this.confirmSaveScenarioButton.waitFor({
|
|
188
|
+
state: 'visible',
|
|
189
|
+
timeout: 10000,
|
|
190
|
+
});
|
|
195
191
|
await this.confirmSaveScenarioButton.click();
|
|
196
192
|
}
|
|
197
193
|
async getDeleteIconForScenario(scenarioName) {
|
|
@@ -202,12 +198,21 @@ class PlayPage {
|
|
|
202
198
|
}
|
|
203
199
|
async deleteScenario(scenarioName) {
|
|
204
200
|
const deleteIcon = await this.getDeleteIconForScenario(scenarioName);
|
|
201
|
+
await deleteIcon.waitFor({ state: 'visible', timeout: 10000 });
|
|
205
202
|
await deleteIcon.click();
|
|
206
203
|
}
|
|
207
204
|
async confirmDeleteScenario() {
|
|
205
|
+
await this.confirmDeleteScenarioButton.waitFor({
|
|
206
|
+
state: 'visible',
|
|
207
|
+
timeout: 10000,
|
|
208
|
+
});
|
|
208
209
|
await this.confirmDeleteScenarioButton.click();
|
|
209
210
|
}
|
|
210
211
|
async clickRunAllScenariosButton() {
|
|
212
|
+
await this.runAllScenariosButton.waitFor({
|
|
213
|
+
state: 'visible',
|
|
214
|
+
timeout: 30000,
|
|
215
|
+
});
|
|
211
216
|
await this.runAllScenariosButton.click();
|
|
212
217
|
}
|
|
213
218
|
async clickmessagePublishButton() {
|
|
@@ -221,8 +226,9 @@ class PlayPage {
|
|
|
221
226
|
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.page
|
|
222
227
|
.locator('tr', { hasText: scenarioName })
|
|
223
228
|
.locator('text=Completed'), {
|
|
224
|
-
totalTimeout:
|
|
225
|
-
visibilityTimeout:
|
|
229
|
+
totalTimeout: 120000,
|
|
230
|
+
visibilityTimeout: 30000,
|
|
231
|
+
maxRetries: 5,
|
|
226
232
|
postAction: async () => {
|
|
227
233
|
if (await this.retryButton.isVisible()) {
|
|
228
234
|
await this.retryButton.click();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const _8_10_1 = require("../../../fixtures/8.10");
|
|
4
|
+
const UtilitiesPage_1 = require("../../../pages/8.10/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_10_1.test.describe.configure({ mode: 'parallel' });
|
|
13
|
+
_8_10_1.test.describe('Orchestration Cluster MCP Server - Cluster Tools @tasklistV2', () => {
|
|
14
|
+
const clusterName = 'Agentic Orchestration Cluster';
|
|
15
|
+
_8_10_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_10_1.test.beforeEach(async ({ page, loginPage }, testInfo) => {
|
|
24
|
+
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, testUser, (testInfo.workerIndex + 1) * 1000);
|
|
25
|
+
});
|
|
26
|
+
_8_10_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_10_1.test)(testCase.name, async ({ homePage, appsPage, operateHomePage, operateProcessesPage, operateProcessInstancePage, }) => {
|
|
55
|
+
_8_10_1.test.slow();
|
|
56
|
+
await _8_10_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_10_1.test.step(`Verify ${assertion.description}`, async () => {
|
|
70
|
+
await operateProcessInstancePage.assertProcessVariableContainsText(testCase.variable, assertion.text);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const _8_10_1 = require("../../../fixtures/8.10");
|
|
4
|
+
const UtilitiesPage_1 = require("../../../pages/8.10/UtilitiesPage");
|
|
5
|
+
const _setup_1 = require("../../../test-setup.js");
|
|
6
|
+
const apiHelpers_1 = require("../../../utils/apiHelpers");
|
|
7
|
+
const incidentHelpers_1 = require("../../../utils/incidentHelpers");
|
|
8
|
+
const users_1 = require("../../../utils/users");
|
|
9
|
+
const test_1 = require("@playwright/test");
|
|
10
|
+
const testUser = (0, users_1.getTestUser)('fifteenthUser');
|
|
11
|
+
let authToken;
|
|
12
|
+
let toolsInstanceKey;
|
|
13
|
+
_8_10_1.test.describe.configure({ mode: 'parallel' });
|
|
14
|
+
_8_10_1.test.describe('Orchestration Cluster MCP Server - Incident Tools @tasklistV2', () => {
|
|
15
|
+
const clusterName = 'Agentic Orchestration Cluster';
|
|
16
|
+
_8_10_1.test.beforeAll(async () => {
|
|
17
|
+
authToken = await (0, apiHelpers_1.authSaasAPI)(undefined, 'agentic_cluster');
|
|
18
|
+
const [testFileProcessKey, toolsProcessKey] = await Promise.all([
|
|
19
|
+
(0, apiHelpers_1.deployProcess)('./resources/mcp_server_saas/mcp_incident_test_file.bpmn', authToken, 'saas', 'agentic_cluster'),
|
|
20
|
+
(0, apiHelpers_1.deployProcess)('./resources/mcp_server_saas/mcp_incident_tools.bpmn', authToken, 'saas', 'agentic_cluster'),
|
|
21
|
+
]);
|
|
22
|
+
if (testFileProcessKey == null || toolsProcessKey == null) {
|
|
23
|
+
throw new Error('Failed to deploy incident tools processes');
|
|
24
|
+
}
|
|
25
|
+
// Create test instance — the call activity in the BPMN references a
|
|
26
|
+
// non-existent process, so Zeebe raises a CALLED_ELEMENT_ERROR incident
|
|
27
|
+
// immediately without needing a worker.
|
|
28
|
+
const testInstanceKey = await (0, apiHelpers_1.createProcessInstance)(String(testFileProcessKey), authToken, 'saas', 'agentic_cluster');
|
|
29
|
+
// Get the incident key created by the test instance (with retry logic)
|
|
30
|
+
const testIncidentKey = await (0, incidentHelpers_1.getIncidentKeyByProcessInstanceKey)(testInstanceKey, authToken, 'saas', 'agentic_cluster');
|
|
31
|
+
console.log('Creating tools instance with variables:', {
|
|
32
|
+
testFileProcessKey,
|
|
33
|
+
testIncidentKey,
|
|
34
|
+
});
|
|
35
|
+
// Create tools instance with required variables
|
|
36
|
+
toolsInstanceKey = await (0, apiHelpers_1.createProcessInstance)(String(toolsProcessKey), authToken, 'saas', 'agentic_cluster', { testFileProcessKey, testIncidentKey });
|
|
37
|
+
});
|
|
38
|
+
_8_10_1.test.beforeEach(async ({ page, loginPage }, testInfo) => {
|
|
39
|
+
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, testUser, (testInfo.workerIndex + 1) * 1000);
|
|
40
|
+
});
|
|
41
|
+
_8_10_1.test.afterEach(async ({ page }, testInfo) => {
|
|
42
|
+
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
43
|
+
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
44
|
+
});
|
|
45
|
+
const incidentToolTests = [
|
|
46
|
+
{
|
|
47
|
+
name: 'searchIncidents - search incidents with filters such as processDefinitionKey',
|
|
48
|
+
variable: 'mcpResultSearchIncidents',
|
|
49
|
+
assertions: [
|
|
50
|
+
{
|
|
51
|
+
text: 'totalItems',
|
|
52
|
+
description: 'search response contains totalItems field',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
text: 'incidentKey',
|
|
56
|
+
description: 'search response contains incidentKey field',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
text: 'processDefinitionKey',
|
|
60
|
+
description: 'search response contains processDefinitionKey field',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
text: 'state',
|
|
64
|
+
description: 'search response contains state field',
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'getIncident - retrieve an incident by key',
|
|
70
|
+
variable: 'mcpResultGetIncident',
|
|
71
|
+
assertions: [
|
|
72
|
+
{
|
|
73
|
+
text: 'incidentKey',
|
|
74
|
+
description: 'response contains incidentKey field',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
text: 'processInstanceKey',
|
|
78
|
+
description: 'response contains processInstanceKey field',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
text: 'errorType',
|
|
82
|
+
description: 'response contains errorType field',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
text: 'state',
|
|
86
|
+
description: 'response contains state field',
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'resolveIncident - resolve an incident by key',
|
|
92
|
+
variable: 'mcpResultResolveIncident',
|
|
93
|
+
assertions: [
|
|
94
|
+
{
|
|
95
|
+
text: 'resolved',
|
|
96
|
+
description: 'response confirms incident was resolved',
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
for (const testCase of incidentToolTests) {
|
|
102
|
+
(0, _8_10_1.test)(testCase.name, async ({ homePage, appsPage, operateHomePage, operateProcessesPage, operateProcessInstancePage, }) => {
|
|
103
|
+
_8_10_1.test.slow();
|
|
104
|
+
await _8_10_1.test.step('Navigate to completed process in Operate', async () => {
|
|
105
|
+
await homePage.clickClusters();
|
|
106
|
+
await appsPage.clickOperate(clusterName);
|
|
107
|
+
await (0, test_1.expect)(operateHomePage.operateBanner).toBeVisible({
|
|
108
|
+
timeout: 60000,
|
|
109
|
+
});
|
|
110
|
+
await operateHomePage.clickProcessesTab();
|
|
111
|
+
await operateProcessesPage.clickProcessCompletedCheckbox();
|
|
112
|
+
await operateProcessesPage.applyMoreFilters('Process Instance Key(s)', String(toolsInstanceKey));
|
|
113
|
+
await operateProcessesPage.clickProcessInstanceLink('MCP Incident Tools');
|
|
114
|
+
await operateProcessInstancePage.assertProcessCompleteStatusWithRetry();
|
|
115
|
+
});
|
|
116
|
+
for (const assertion of testCase.assertions) {
|
|
117
|
+
await _8_10_1.test.step(assertion.description, async () => {
|
|
118
|
+
await operateProcessInstancePage.assertProcessVariableContainsText(testCase.variable, assertion.text);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
@@ -4,6 +4,7 @@ const test_1 = require("@playwright/test");
|
|
|
4
4
|
const _8_10_1 = require("../../fixtures/8.10");
|
|
5
5
|
const _setup_1 = require("../../test-setup.js");
|
|
6
6
|
const connectorSecrets_1 = require("../../utils/connectorSecrets");
|
|
7
|
+
const mcpSecrets_1 = require("../../utils/mcpSecrets");
|
|
7
8
|
const UtilitiesPage_1 = require("../../pages/8.10/UtilitiesPage");
|
|
8
9
|
const users_1 = require("../../utils/users");
|
|
9
10
|
_8_10_1.test.describe.configure({ mode: 'parallel' });
|
|
@@ -44,6 +45,32 @@ _8_10_1.test.describe('Cluster Setup Tests', () => {
|
|
|
44
45
|
await clusterSecretsPage.createSetOfSecrets(clusterName, connectorSecrets_1.agentcoreSecretsValues);
|
|
45
46
|
}
|
|
46
47
|
});
|
|
48
|
+
(0, _8_10_1.test)('Create Agentic Orchestration Cluster', async ({ page, loginPage, homePage, clusterPage, clusterDetailsPage, clusterSecretsPage, }, testInfo) => {
|
|
49
|
+
_8_10_1.test.skip(process.env.IS_PROD === 'true', 'Skipping test because not required on PROD test org');
|
|
50
|
+
_8_10_1.test.skip(process.env.IS_AG === 'true', 'Skipping test because not required when IS_AG is true');
|
|
51
|
+
_8_10_1.test.slow();
|
|
52
|
+
const clusterName = 'Agentic Orchestration Cluster';
|
|
53
|
+
const apiClientName = 'Test_API_Client' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
54
|
+
const mcpClientName = 'MCP_Test_API_Client' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
55
|
+
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, users_1.testUsers.mainUser, (testInfo.workerIndex + 1) * 1000);
|
|
56
|
+
await homePage.clickClusters();
|
|
57
|
+
await clusterPage.createCluster(clusterName);
|
|
58
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(clusterName);
|
|
59
|
+
await clusterPage.clickClusterLink(clusterName);
|
|
60
|
+
await clusterDetailsPage.assertComponentsHealth();
|
|
61
|
+
await clusterDetailsPage.clickSettingsTab();
|
|
62
|
+
await clusterDetailsPage.checkMcpSupportToggle();
|
|
63
|
+
await homePage.clickClusters();
|
|
64
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(clusterName);
|
|
65
|
+
await clusterPage.clickClusterLink(clusterName);
|
|
66
|
+
await clusterDetailsPage.clickAPITab();
|
|
67
|
+
await clusterDetailsPage.createAPIClientAndReturnVariables(apiClientName, true, 'agentic_cluster');
|
|
68
|
+
await clusterDetailsPage.clickCloseModalButton();
|
|
69
|
+
const mcpCredentials = await clusterDetailsPage.createMCPClientAndReturnVariables(mcpClientName);
|
|
70
|
+
await clusterDetailsPage.clickCloseModalButton();
|
|
71
|
+
await clusterPage.clickConnectorSecretsTab(clusterName);
|
|
72
|
+
await clusterSecretsPage.createSetOfSecrets(clusterName, (0, mcpSecrets_1.mcpSecretsValues)(mcpCredentials));
|
|
73
|
+
});
|
|
47
74
|
(0, _8_10_1.test)('Create AWS Cluster', async ({ page, loginPage, homePage, clusterPage, clusterDetailsPage, clusterSecretsPage, }, testInfo) => {
|
|
48
75
|
_8_10_1.test.slow();
|
|
49
76
|
const clusterName = 'AWS Cluster';
|
|
@@ -4,6 +4,7 @@ const test_1 = require("@playwright/test");
|
|
|
4
4
|
const SM_8_10_1 = require("../../fixtures/SM-8.10");
|
|
5
5
|
const _setup_1 = require("../../test-setup.js");
|
|
6
6
|
const sleep_1 = require("../../utils/sleep");
|
|
7
|
+
const UtilitiesPage_1 = require("../../pages/SM-8.10/UtilitiesPage");
|
|
7
8
|
SM_8_10_1.test.describe.configure({ mode: 'parallel' });
|
|
8
9
|
SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
9
10
|
SM_8_10_1.test.beforeEach(async ({ navigationPage }, testInfo) => {
|
|
@@ -13,49 +14,15 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
13
14
|
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
14
15
|
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
15
16
|
});
|
|
16
|
-
(0, SM_8_10_1.test)('User Tasks and Service Task', async ({ modelerHomePage, modelerCreatePage, playPage, }) => {
|
|
17
|
+
(0, SM_8_10_1.test)('User Tasks and Service Task', async ({ page, modelerHomePage, modelerCreatePage, playPage, }) => {
|
|
17
18
|
SM_8_10_1.test.slow();
|
|
18
19
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
19
20
|
const processName = 'Play_Test_Process' + randomString;
|
|
20
21
|
await SM_8_10_1.test.step('Open Cross Component Test Project', async () => {
|
|
21
22
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
22
23
|
});
|
|
23
|
-
await SM_8_10_1.test.step('Add A BPMN Template To The Project', async () => {
|
|
24
|
-
await modelerHomePage.clickDiagramTypeDropdown();
|
|
25
|
-
await modelerHomePage.clickBpmnTemplateOption();
|
|
26
|
-
});
|
|
27
24
|
await SM_8_10_1.test.step('Create a BPMN Diagram with user tasks and service task', async () => {
|
|
28
|
-
await (0,
|
|
29
|
-
timeout: 120000,
|
|
30
|
-
});
|
|
31
|
-
await modelerCreatePage.enterDiagramName(processName);
|
|
32
|
-
await (0, sleep_1.sleep)(2000);
|
|
33
|
-
// Add a user task with Zeebe user task implementation
|
|
34
|
-
await modelerCreatePage.clickAppendElementButton();
|
|
35
|
-
await modelerCreatePage.clickAppendTaskButton();
|
|
36
|
-
await modelerCreatePage.clickChangeTypeButton();
|
|
37
|
-
await modelerCreatePage.clickUserTaskOption();
|
|
38
|
-
await modelerCreatePage.chooseImplementationOption('zeebeUserTask');
|
|
39
|
-
await modelerCreatePage.clickGeneralPropertiesPanel();
|
|
40
|
-
await modelerCreatePage.clickElemendIdInput();
|
|
41
|
-
await modelerCreatePage.fillElementIdInput('zeebe-user-task' + randomString);
|
|
42
|
-
await (0, sleep_1.sleep)(1000);
|
|
43
|
-
// Add a service task
|
|
44
|
-
await modelerCreatePage.clickAppendElementButton();
|
|
45
|
-
await modelerCreatePage.clickAppendTaskButton();
|
|
46
|
-
await modelerCreatePage.clickChangeTypeButton();
|
|
47
|
-
await modelerCreatePage.clickServiceTaskOption();
|
|
48
|
-
await modelerCreatePage.clickGeneralPropertiesPanel();
|
|
49
|
-
await modelerCreatePage.clickElemendIdInput();
|
|
50
|
-
await modelerCreatePage.fillElementIdInput('service-task' + randomString);
|
|
51
|
-
await modelerCreatePage.clickTaskDefinitionPropertiesPanel();
|
|
52
|
-
await modelerCreatePage.clickJobTypeInput();
|
|
53
|
-
await modelerCreatePage.fillJobTypeInput('someJob' + randomString);
|
|
54
|
-
await (0, sleep_1.sleep)(1000);
|
|
55
|
-
// Add end event
|
|
56
|
-
await modelerCreatePage.clickAppendElementButton();
|
|
57
|
-
await modelerCreatePage.clickAppendEndEventButton();
|
|
58
|
-
await (0, sleep_1.sleep)(2000);
|
|
25
|
+
await (0, UtilitiesPage_1.modelDiagramFromFile)(page, modelerHomePage, modelerCreatePage, processName, 'Play_Test_User_Service_Task');
|
|
59
26
|
});
|
|
60
27
|
await SM_8_10_1.test.step('Open Play', async () => {
|
|
61
28
|
await modelerCreatePage.switchToPlay();
|
|
@@ -65,10 +32,10 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
65
32
|
await playPage.dismissStartModal();
|
|
66
33
|
await playPage.clickStartInstanceButton();
|
|
67
34
|
await playPage.waitForInstanceDetailsToBeLoaded();
|
|
68
|
-
await playPage.waitForNextElementToBeActive('
|
|
35
|
+
await playPage.waitForNextElementToBeActive('play-user-task');
|
|
69
36
|
await playPage.waitForCompleteJobButtonToBeAvailable();
|
|
70
37
|
await playPage.clickCompleteJobButton();
|
|
71
|
-
await playPage.waitForNextElementToBeActive('service-task'
|
|
38
|
+
await playPage.waitForNextElementToBeActive('play-service-task');
|
|
72
39
|
await playPage.waitForCompleteJobButtonToBeAvailable();
|
|
73
40
|
await playPage.clickCompleteJobButton();
|
|
74
41
|
await playPage.waitForProcessToBeCompleted();
|
|
@@ -96,7 +63,11 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
96
63
|
await modelerCreatePage.clickSecondPlacedGateway();
|
|
97
64
|
await modelerCreatePage.clickAppendElementButton();
|
|
98
65
|
await modelerCreatePage.clickAppendEndEventButton('parallelGateway');
|
|
99
|
-
await (0,
|
|
66
|
+
await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({
|
|
67
|
+
timeout: 30000,
|
|
68
|
+
});
|
|
69
|
+
// Wait for modeler background auto-save to complete
|
|
70
|
+
await (0, sleep_1.sleep)(2000);
|
|
100
71
|
});
|
|
101
72
|
await SM_8_10_1.test.step('Open Play', async () => {
|
|
102
73
|
await modelerCreatePage.switchToPlay();
|
|
@@ -113,17 +84,23 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
113
84
|
await playPage.clickSaveScenarioButton();
|
|
114
85
|
await playPage.enterScenarioName(scenarioName);
|
|
115
86
|
await playPage.confirmSaveScenario();
|
|
116
|
-
await (0,
|
|
87
|
+
await (0, test_1.expect)(playPage.saveScenarioModal).toBeHidden({ timeout: 10000 });
|
|
117
88
|
});
|
|
118
89
|
await SM_8_10_1.test.step('Update the saved scenario', async () => {
|
|
119
90
|
await modelerCreatePage.switchToImplementTab();
|
|
120
|
-
await (0,
|
|
91
|
+
await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({
|
|
92
|
+
timeout: 30000,
|
|
93
|
+
});
|
|
121
94
|
await modelerCreatePage.clickFirstPlacedGateway();
|
|
122
95
|
await modelerCreatePage.clickAppendElementButton();
|
|
123
96
|
await modelerCreatePage.clickAppendTaskButton();
|
|
124
97
|
await modelerCreatePage.clickConnectToOtherElementButton();
|
|
125
98
|
await modelerCreatePage.clickSecondPlacedGateway();
|
|
126
|
-
await (0,
|
|
99
|
+
await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({
|
|
100
|
+
timeout: 30000,
|
|
101
|
+
});
|
|
102
|
+
// Wait for modeler background auto-save to complete
|
|
103
|
+
await (0, sleep_1.sleep)(2000);
|
|
127
104
|
await modelerCreatePage.switchToPlay();
|
|
128
105
|
// After diagram modification, Play may show a "Continue" button
|
|
129
106
|
// to redeploy, or it may show the diagram directly. Try clicking
|
|
@@ -153,7 +130,9 @@ SM_8_10_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
153
130
|
await SM_8_10_1.test.step('Delete test scenario', async () => {
|
|
154
131
|
await playPage.deleteScenario(scenarioName);
|
|
155
132
|
await playPage.confirmDeleteScenario();
|
|
156
|
-
await (0, test_1.expect)(playPage.getScenarioRow(scenarioName)).toHaveCount(0
|
|
133
|
+
await (0, test_1.expect)(playPage.getScenarioRow(scenarioName)).toHaveCount(0, {
|
|
134
|
+
timeout: 10000,
|
|
135
|
+
});
|
|
157
136
|
});
|
|
158
137
|
});
|
|
159
138
|
});
|
package/package.json
CHANGED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:zeebe="http://camunda.org/schema/zeebe/1.0" xmlns:modeler="http://camunda.org/schema/modeler/1.0" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Web Modeler" exporterVersion="ff1274a" modeler:executionPlatform="Camunda Cloud" modeler:executionPlatformVersion="8.10.0">
|
|
3
|
+
<bpmn:process id="Play_Test_User_Service_Task" name="Play_Test_User_Service_Task" isExecutable="true">
|
|
4
|
+
<bpmn:startEvent id="StartEvent_1">
|
|
5
|
+
<bpmn:outgoing>Flow_1</bpmn:outgoing>
|
|
6
|
+
</bpmn:startEvent>
|
|
7
|
+
<bpmn:sequenceFlow id="Flow_1" sourceRef="StartEvent_1" targetRef="play-user-task" />
|
|
8
|
+
<bpmn:userTask id="play-user-task" name="play-user-task">
|
|
9
|
+
<bpmn:extensionElements>
|
|
10
|
+
<zeebe:userTask />
|
|
11
|
+
</bpmn:extensionElements>
|
|
12
|
+
<bpmn:incoming>Flow_1</bpmn:incoming>
|
|
13
|
+
<bpmn:outgoing>Flow_2</bpmn:outgoing>
|
|
14
|
+
</bpmn:userTask>
|
|
15
|
+
<bpmn:sequenceFlow id="Flow_2" sourceRef="play-user-task" targetRef="play-service-task" />
|
|
16
|
+
<bpmn:serviceTask id="play-service-task" name="play-service-task">
|
|
17
|
+
<bpmn:extensionElements>
|
|
18
|
+
<zeebe:taskDefinition type="play-job-type" />
|
|
19
|
+
</bpmn:extensionElements>
|
|
20
|
+
<bpmn:incoming>Flow_2</bpmn:incoming>
|
|
21
|
+
<bpmn:outgoing>Flow_3</bpmn:outgoing>
|
|
22
|
+
</bpmn:serviceTask>
|
|
23
|
+
<bpmn:endEvent id="EndEvent_1">
|
|
24
|
+
<bpmn:incoming>Flow_3</bpmn:incoming>
|
|
25
|
+
</bpmn:endEvent>
|
|
26
|
+
<bpmn:sequenceFlow id="Flow_3" sourceRef="play-service-task" targetRef="EndEvent_1" />
|
|
27
|
+
</bpmn:process>
|
|
28
|
+
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
|
29
|
+
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Play_Test_User_Service_Task">
|
|
30
|
+
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
|
31
|
+
<dc:Bounds x="150" y="100" width="36" height="36" />
|
|
32
|
+
</bpmndi:BPMNShape>
|
|
33
|
+
<bpmndi:BPMNShape id="Activity_UserTask_di" bpmnElement="play-user-task">
|
|
34
|
+
<dc:Bounds x="240" y="78" width="100" height="80" />
|
|
35
|
+
</bpmndi:BPMNShape>
|
|
36
|
+
<bpmndi:BPMNShape id="Activity_ServiceTask_di" bpmnElement="play-service-task">
|
|
37
|
+
<dc:Bounds x="400" y="78" width="100" height="80" />
|
|
38
|
+
</bpmndi:BPMNShape>
|
|
39
|
+
<bpmndi:BPMNShape id="Event_EndEvent_di" bpmnElement="EndEvent_1">
|
|
40
|
+
<dc:Bounds x="562" y="100" width="36" height="36" />
|
|
41
|
+
</bpmndi:BPMNShape>
|
|
42
|
+
<bpmndi:BPMNEdge id="Flow_1_di" bpmnElement="Flow_1">
|
|
43
|
+
<di:waypoint x="186" y="118" />
|
|
44
|
+
<di:waypoint x="240" y="118" />
|
|
45
|
+
</bpmndi:BPMNEdge>
|
|
46
|
+
<bpmndi:BPMNEdge id="Flow_2_di" bpmnElement="Flow_2">
|
|
47
|
+
<di:waypoint x="340" y="118" />
|
|
48
|
+
<di:waypoint x="400" y="118" />
|
|
49
|
+
</bpmndi:BPMNEdge>
|
|
50
|
+
<bpmndi:BPMNEdge id="Flow_3_di" bpmnElement="Flow_3">
|
|
51
|
+
<di:waypoint x="500" y="118" />
|
|
52
|
+
<di:waypoint x="562" y="118" />
|
|
53
|
+
</bpmndi:BPMNEdge>
|
|
54
|
+
</bpmndi:BPMNPlane>
|
|
55
|
+
</bpmndi:BPMNDiagram>
|
|
56
|
+
</bpmn:definitions>
|