@camunda/e2e-test-suite 0.0.439 → 0.0.441
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/SM-8.8/IdentityTenantPage.d.ts +1 -0
- package/dist/pages/SM-8.8/IdentityTenantPage.js +25 -3
- package/dist/pages/SM-8.8/KeycloakUtils.d.ts +2 -1
- package/dist/pages/SM-8.8/KeycloakUtils.js +10 -1
- package/dist/pages/SM-8.8/ManagementIdentityPage.js +4 -1
- package/dist/tests/8.9/orchestration-cluster-mcp-server/mcp-variable-tools.spec.d.ts +1 -0
- package/dist/tests/8.9/orchestration-cluster-mcp-server/mcp-variable-tools.spec.js +119 -0
- package/dist/tests/SM-8.8/smoke-tests.spec.js +2 -2
- package/dist/utils/variableHelpers.d.ts +1 -0
- package/dist/utils/variableHelpers.js +44 -0
- package/package.json +1 -1
|
@@ -21,6 +21,7 @@ declare class IdentityTenantPage {
|
|
|
21
21
|
readonly cancelButton: Locator;
|
|
22
22
|
readonly dialog: Locator;
|
|
23
23
|
readonly row: (name: string) => Locator;
|
|
24
|
+
readonly usersTab: Locator;
|
|
24
25
|
constructor(page: Page);
|
|
25
26
|
clickCreateTenantMainButton(): Promise<void>;
|
|
26
27
|
clickCreateTenantSubButton(): Promise<void>;
|
|
@@ -26,11 +26,13 @@ class IdentityTenantPage {
|
|
|
26
26
|
cancelButton;
|
|
27
27
|
dialog;
|
|
28
28
|
row;
|
|
29
|
+
usersTab;
|
|
29
30
|
constructor(page) {
|
|
30
31
|
this.page = page;
|
|
31
32
|
this.createTenantMainButton = page.getByRole('button', {
|
|
32
33
|
name: 'Create Tenant',
|
|
33
34
|
});
|
|
35
|
+
this.usersTab = page.getByRole('tab', { name: 'Users' });
|
|
34
36
|
this.enterTenantNameInput = page.getByPlaceholder('Enter tenant name');
|
|
35
37
|
this.enterTenantIdInput = page.getByPlaceholder('Enter tenant ID');
|
|
36
38
|
this.createTenantSubButton = page.getByRole('button', {
|
|
@@ -144,9 +146,25 @@ class IdentityTenantPage {
|
|
|
144
146
|
await (0, sleep_1.sleep)(30000);
|
|
145
147
|
}
|
|
146
148
|
async clickTenant(tenantName) {
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
149
|
+
const maxRetries = 5;
|
|
150
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
151
|
+
try {
|
|
152
|
+
await this.page.waitForLoadState('domcontentloaded').catch(() => { });
|
|
153
|
+
const tenantRow = this.row(tenantName);
|
|
154
|
+
await (0, UtilitiesPage_1.assertLocatorVisibleWithPaginated)(this.page, tenantRow, `Tenant with name ${tenantName} not found`);
|
|
155
|
+
await tenantRow.locator('td').first().click({ timeout: 30000 });
|
|
156
|
+
await this.usersTab.waitFor({ state: 'visible', timeout: 30000 });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
console.warn(`Attempt ${attempt} to click tenant '${tenantName}' failed. Retrying...`, error);
|
|
161
|
+
if (attempt === maxRetries) {
|
|
162
|
+
throw new Error(`Failed to click tenant '${tenantName}' after ${maxRetries} attempts.`);
|
|
163
|
+
}
|
|
164
|
+
await this.page.reload({ timeout: 30000 }).catch(() => { });
|
|
165
|
+
await (0, sleep_1.sleep)(3000);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
150
168
|
}
|
|
151
169
|
async isRowVisible(name) {
|
|
152
170
|
await (0, sleep_1.sleep)(1000);
|
|
@@ -187,12 +205,16 @@ class IdentityTenantPage {
|
|
|
187
205
|
}
|
|
188
206
|
async assignClientToTenant(clientName) {
|
|
189
207
|
await this.clickAssignedApplicationsTab();
|
|
208
|
+
await (0, sleep_1.sleep)(3000);
|
|
190
209
|
if (await this.isRowVisible(clientName)) {
|
|
191
210
|
return;
|
|
192
211
|
}
|
|
193
212
|
await this.clickAssignApplicationsButton();
|
|
194
213
|
await this.clickSearchApplicationsInput();
|
|
195
214
|
await this.fillSearchApplicationsInput(clientName);
|
|
215
|
+
await (0, test_1.expect)(this.page.getByText(clientName, { exact: true })).toBeVisible({
|
|
216
|
+
timeout: 15000,
|
|
217
|
+
});
|
|
196
218
|
await this.page.getByText(clientName, { exact: true }).click();
|
|
197
219
|
await this.clickAssignApplicationsFinalButton();
|
|
198
220
|
await (0, test_1.expect)(this.page.getByText('Applications assigned').first()).toBeVisible({
|
|
@@ -4,11 +4,12 @@ import { KeycloakLoginPage } from '../SM-8.8/KeycloakLoginPage';
|
|
|
4
4
|
import { KeycloakAdminPage } from '../SM-8.8/KeycloakAdminPage';
|
|
5
5
|
import { OCIdentityHomePage } from './OCIdentityHomePage';
|
|
6
6
|
import { OCIdentityRolesPage } from './OCIdentityRolesPage';
|
|
7
|
+
import { IdentityTenantPage } from './IdentityTenantPage';
|
|
7
8
|
export declare const keycloakAdminCredentials: () => {
|
|
8
9
|
username: string;
|
|
9
10
|
password: string;
|
|
10
11
|
};
|
|
11
|
-
export declare const setupKeycloakUser: (navigationPage: NavigationPage, identityPage: ManagementIdentityPage, keycloakLoginPage: KeycloakLoginPage, keycloakAdminPage: KeycloakAdminPage, ocIdentityHomePage: OCIdentityHomePage, ocIdentityRolesPage: OCIdentityRolesPage) => Promise<{
|
|
12
|
+
export declare const setupKeycloakUser: (navigationPage: NavigationPage, identityPage: ManagementIdentityPage, keycloakLoginPage: KeycloakLoginPage, keycloakAdminPage: KeycloakAdminPage, ocIdentityHomePage: OCIdentityHomePage, ocIdentityRolesPage: OCIdentityRolesPage, assignToDefaultTenant?: boolean, managementIdentityTenantPage?: IdentityTenantPage) => Promise<{
|
|
12
13
|
testUsername: string;
|
|
13
14
|
testPassword: string;
|
|
14
15
|
}>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createKeycloakUser = exports.createUser = exports.setupKeycloakUser = exports.keycloakAdminCredentials = void 0;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
4
5
|
const keycloakAdminCredentials = () => {
|
|
5
6
|
return {
|
|
6
7
|
username: 'admin',
|
|
@@ -8,13 +9,21 @@ const keycloakAdminCredentials = () => {
|
|
|
8
9
|
};
|
|
9
10
|
};
|
|
10
11
|
exports.keycloakAdminCredentials = keycloakAdminCredentials;
|
|
11
|
-
const setupKeycloakUser = async (navigationPage, identityPage, keycloakLoginPage, keycloakAdminPage, ocIdentityHomePage, ocIdentityRolesPage) => {
|
|
12
|
+
const setupKeycloakUser = async (navigationPage, identityPage, keycloakLoginPage, keycloakAdminPage, ocIdentityHomePage, ocIdentityRolesPage, assignToDefaultTenant = false, managementIdentityTenantPage) => {
|
|
12
13
|
const testUsername = `test-user-${new Date().getTime()}-${Math.random()
|
|
13
14
|
.toString(36)
|
|
14
15
|
.substring(7)}`;
|
|
15
16
|
const testPassword = 'test-password';
|
|
16
17
|
await createKeycloakUser(navigationPage, keycloakLoginPage, keycloakAdminPage, testUsername, testPassword);
|
|
17
18
|
await createIdentityUser(navigationPage, identityPage, testUsername);
|
|
19
|
+
if (assignToDefaultTenant && managementIdentityTenantPage) {
|
|
20
|
+
const userEmail = `qacamunda+${testUsername}@gmail.com`;
|
|
21
|
+
await navigationPage.goToManagementIdentity();
|
|
22
|
+
await (0, test_1.expect)(identityPage.usersLink).toBeVisible({ timeout: 10000 });
|
|
23
|
+
if (await identityPage.tenantTab.isVisible()) {
|
|
24
|
+
await managementIdentityTenantPage.assignUserToTenant('Default', testUsername, userEmail);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
18
27
|
await createOCUser(navigationPage, ocIdentityHomePage, ocIdentityRolesPage, testUsername);
|
|
19
28
|
return { testUsername, testPassword };
|
|
20
29
|
};
|
|
@@ -32,7 +32,10 @@ class ManagementIdentityPage {
|
|
|
32
32
|
name: 'Camunda logo Management Identity',
|
|
33
33
|
});
|
|
34
34
|
this.usersLink = page.locator('a').filter({ hasText: 'Users' });
|
|
35
|
-
this.tenantTab = page
|
|
35
|
+
this.tenantTab = page
|
|
36
|
+
.getByRole('link', { name: 'Tenants' })
|
|
37
|
+
.or(page.locator('a').filter({ hasText: 'Tenants' }))
|
|
38
|
+
.first();
|
|
36
39
|
this.assignedRolesTab = page.getByRole('tab', { name: 'Assigned roles' });
|
|
37
40
|
this.demoUser = page.getByRole('cell', { name: 'demo' }).first();
|
|
38
41
|
this.confirmDeleteButton = page.getByRole('button', {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
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 variableHelpers_1 = require("../../../utils/variableHelpers");
|
|
8
|
+
const users_1 = require("../../../utils/users");
|
|
9
|
+
const test_1 = require("@playwright/test");
|
|
10
|
+
const testUser = (0, users_1.getTestUser)('sixteenthUser');
|
|
11
|
+
let authToken;
|
|
12
|
+
let toolsInstanceKey;
|
|
13
|
+
_8_9_1.test.describe.configure({ mode: 'parallel' });
|
|
14
|
+
_8_9_1.test.describe('Orchestration Cluster MCP Server - Variable Tools @tasklistV2', () => {
|
|
15
|
+
const clusterName = 'Agentic Orchestration Cluster';
|
|
16
|
+
_8_9_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_variable_test_file.bpmn', authToken, 'saas', 'agentic_cluster'),
|
|
20
|
+
(0, apiHelpers_1.deployProcess)('./resources/mcp_server_saas/mcp_variable_tools.bpmn', authToken, 'saas', 'agentic_cluster'),
|
|
21
|
+
]);
|
|
22
|
+
if (testFileProcessKey == null || toolsProcessKey == null) {
|
|
23
|
+
throw new Error('Failed to deploy variable tools processes');
|
|
24
|
+
}
|
|
25
|
+
// Create test instance which will create variables
|
|
26
|
+
const testInstanceKey = await (0, apiHelpers_1.createProcessInstance)(String(testFileProcessKey), authToken, 'saas', 'agentic_cluster', { testVariable1: 'test_value_1', testVariable2: 'test_value_2' });
|
|
27
|
+
// Get a variable key created by the test instance (with retry logic)
|
|
28
|
+
const testVariableKey = await (0, variableHelpers_1.getVariableKeyByProcessInstanceKey)(testInstanceKey, 'testVariable1', authToken, 'saas', 'agentic_cluster');
|
|
29
|
+
console.log('Creating tools instance with variables:', {
|
|
30
|
+
testFileProcessKey,
|
|
31
|
+
testVariableKey,
|
|
32
|
+
});
|
|
33
|
+
// Create tools instance with required variables
|
|
34
|
+
toolsInstanceKey = await (0, apiHelpers_1.createProcessInstance)(String(toolsProcessKey), authToken, 'saas', 'agentic_cluster', { testFileProcessKey, testVariableKey });
|
|
35
|
+
});
|
|
36
|
+
_8_9_1.test.beforeEach(async ({ page, loginPage }, testInfo) => {
|
|
37
|
+
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, testUser, (testInfo.workerIndex + 1) * 1000);
|
|
38
|
+
});
|
|
39
|
+
_8_9_1.test.afterEach(async ({ page }, testInfo) => {
|
|
40
|
+
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
41
|
+
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
42
|
+
});
|
|
43
|
+
const variableToolTests = [
|
|
44
|
+
{
|
|
45
|
+
name: 'searchVariables - search variables with filters',
|
|
46
|
+
variable: 'mcpResultSearchVariables',
|
|
47
|
+
assertions: [
|
|
48
|
+
{
|
|
49
|
+
text: 'items',
|
|
50
|
+
description: 'search response contains items field',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
text: 'variableKey',
|
|
54
|
+
description: 'search response contains variableKey field',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
text: 'name',
|
|
58
|
+
description: 'search response contains name field',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
text: 'value',
|
|
62
|
+
description: 'search response contains value field',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
text: 'processInstanceKey',
|
|
66
|
+
description: 'search response contains processInstanceKey field',
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'getVariable - retrieve a variable by key',
|
|
72
|
+
variable: 'mcpResultGetVariable',
|
|
73
|
+
assertions: [
|
|
74
|
+
{
|
|
75
|
+
text: 'variableKey',
|
|
76
|
+
description: 'response contains variableKey field',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
text: 'name',
|
|
80
|
+
description: 'response contains name field',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
text: 'value',
|
|
84
|
+
description: 'response contains value field',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
text: 'processInstanceKey',
|
|
88
|
+
description: 'response contains processInstanceKey field',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
text: 'scopeKey',
|
|
92
|
+
description: 'response contains scopeKey field',
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
for (const testCase of variableToolTests) {
|
|
98
|
+
(0, _8_9_1.test)(testCase.name, async ({ homePage, appsPage, operateHomePage, operateProcessesPage, operateProcessInstancePage, }) => {
|
|
99
|
+
_8_9_1.test.slow();
|
|
100
|
+
await _8_9_1.test.step('Navigate to completed process in Operate', async () => {
|
|
101
|
+
await homePage.clickClusters();
|
|
102
|
+
await appsPage.clickOperate(clusterName);
|
|
103
|
+
await (0, test_1.expect)(operateHomePage.operateBanner).toBeVisible({
|
|
104
|
+
timeout: 60000,
|
|
105
|
+
});
|
|
106
|
+
await operateHomePage.clickProcessesTab();
|
|
107
|
+
await operateProcessesPage.clickProcessCompletedCheckbox();
|
|
108
|
+
await operateProcessesPage.applyMoreFilters('Process Instance Key(s)', String(toolsInstanceKey));
|
|
109
|
+
await operateProcessesPage.clickProcessInstanceLink('MCP Variable Tools');
|
|
110
|
+
await operateProcessInstancePage.assertProcessCompleteStatusWithRetry();
|
|
111
|
+
});
|
|
112
|
+
for (const assertion of testCase.assertions) {
|
|
113
|
+
await _8_9_1.test.step(assertion.description, async () => {
|
|
114
|
+
await operateProcessInstancePage.assertProcessVariableContainsText(testCase.variable, assertion.text);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
@@ -9,14 +9,14 @@ const loggingUtils_1 = require("../../utils/loggingUtils");
|
|
|
9
9
|
const resetSession_1 = require("../../utils/resetSession");
|
|
10
10
|
const KeycloakUtils_1 = require("../../pages/SM-8.8/KeycloakUtils");
|
|
11
11
|
SM_8_8_1.test.describe.parallel('Smoke Tests', () => {
|
|
12
|
-
SM_8_8_1.test.beforeEach(async ({ navigationPage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, page, browser, loginPage, ocIdentityHomePage, ocIdentityRolesPage, }, testInfo) => {
|
|
12
|
+
SM_8_8_1.test.beforeEach(async ({ navigationPage, managementIdentityPage, managementIdentityTenantPage, keycloakLoginPage, keycloakAdminPage, page, browser, loginPage, ocIdentityHomePage, ocIdentityRolesPage, }, testInfo) => {
|
|
13
13
|
if (process.env.IS_MIGRATION === 'true') {
|
|
14
14
|
await navigationPage.goToOCIdentity((testInfo.workerIndex + 1) * 1000);
|
|
15
15
|
}
|
|
16
16
|
else {
|
|
17
17
|
console.log(`BeforeEach start: timeout = ${testInfo.timeout}`);
|
|
18
18
|
(0, loggingUtils_1.setupTestLogging)(testInfo);
|
|
19
|
-
const { testUsername, testPassword } = await (0, KeycloakUtils_1.setupKeycloakUser)(navigationPage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, ocIdentityHomePage, ocIdentityRolesPage);
|
|
19
|
+
const { testUsername, testPassword } = await (0, KeycloakUtils_1.setupKeycloakUser)(navigationPage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, ocIdentityHomePage, ocIdentityRolesPage, process.env.IS_MT === 'true', managementIdentityTenantPage);
|
|
20
20
|
console.log(`BeforeEach end: timeout = ${testInfo.timeout}`);
|
|
21
21
|
await (0, resetSession_1.resetSession)(browser, page);
|
|
22
22
|
await loginPage.login(testUsername, testPassword);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getVariableKeyByProcessInstanceKey(processInstanceKey: string, variableName: string, authToken?: string, environment?: 'saas' | 'sm', clusterType?: string, maxRetries?: number, retryDelayMs?: number): Promise<string>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getVariableKeyByProcessInstanceKey = void 0;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
const apiHelpers_1 = require("./apiHelpers");
|
|
6
|
+
const sleep_1 = require("./sleep");
|
|
7
|
+
async function getVariableKeyByProcessInstanceKey(processInstanceKey, variableName, authToken, environment, clusterType, maxRetries = 10, retryDelayMs = 2000) {
|
|
8
|
+
const apiRequestContext = await (0, apiHelpers_1.getApiRequestContext)();
|
|
9
|
+
const url = (0, apiHelpers_1.buildZeebeApiUrl)('/v2/variables/search', environment, clusterType);
|
|
10
|
+
let lastError = null;
|
|
11
|
+
// Retry logic to wait for variable to be created and indexed
|
|
12
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
13
|
+
try {
|
|
14
|
+
const response = await apiRequestContext.post(url, {
|
|
15
|
+
headers: { Authorization: authToken ?? '' },
|
|
16
|
+
data: {
|
|
17
|
+
filter: {
|
|
18
|
+
processInstanceKey: String(processInstanceKey),
|
|
19
|
+
name: variableName,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
(0, test_1.expect)(response.status()).toBe(200);
|
|
24
|
+
const responseBody = await response.json();
|
|
25
|
+
if (responseBody?.items && responseBody.items.length > 0) {
|
|
26
|
+
const variableKey = responseBody.items[0]?.variableKey;
|
|
27
|
+
if (variableKey != null) {
|
|
28
|
+
console.log(`Found variable key ${variableKey} for ${variableName} on attempt ${attempt}`);
|
|
29
|
+
return String(variableKey);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
lastError = new Error(`No variable ${variableName} found for processInstanceKey: ${processInstanceKey}`);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
lastError = error;
|
|
36
|
+
}
|
|
37
|
+
if (attempt < maxRetries) {
|
|
38
|
+
console.log(`Variable ${variableName} not found yet, retrying in ${retryDelayMs}ms (${attempt}/${maxRetries})...`);
|
|
39
|
+
await (0, sleep_1.sleep)(retryDelayMs);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
throw new Error(`Failed to find variable ${variableName} after ${maxRetries} attempts: ${lastError?.message}`);
|
|
43
|
+
}
|
|
44
|
+
exports.getVariableKeyByProcessInstanceKey = getVariableKeyByProcessInstanceKey;
|