@camunda/e2e-test-suite 0.0.254 → 0.0.256
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.7/PlayPage.js +2 -0
- package/dist/pages/SM-8.9/ModelerCreatePage.js +2 -1
- package/dist/pages/SM-8.9/PlayPage.js +2 -0
- package/dist/tests/SM-8.9/smoke-tests.spec.js +0 -1
- package/dist/tests/c8Run-8.9/mcp-connector-authentication.spec.d.ts +1 -0
- package/dist/tests/c8Run-8.9/mcp-connector-authentication.spec.js +73 -0
- package/dist/utils/keycloakHelpers.d.ts +17 -0
- package/dist/utils/keycloakHelpers.js +78 -0
- package/package.json +1 -1
|
@@ -66,6 +66,8 @@ class PlayPage {
|
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
async clickCompleteJobButton() {
|
|
69
|
+
await (0, test_1.expect)(this.completeJobButton).toBeVisible({ timeout: 30000 });
|
|
70
|
+
await (0, test_1.expect)(this.completeJobButton).toBeEnabled({ timeout: 30000 });
|
|
69
71
|
await this.completeJobButton.click();
|
|
70
72
|
}
|
|
71
73
|
async clickStartInstanceButton() {
|
|
@@ -135,7 +135,7 @@ class ModelerCreatePage {
|
|
|
135
135
|
this.diagramBreadcrumb = page.locator('[data-test="breadcrumb-diagram"]');
|
|
136
136
|
this.renameDiagramNameButton = page.getByText('Rename');
|
|
137
137
|
this.diagramNameInput = page.locator('[data-test="editable-input"]');
|
|
138
|
-
this.variableInput = page.
|
|
138
|
+
this.variableInput = page.locator('[id="variables-json"]');
|
|
139
139
|
this.embedFormButton = page.getByRole('button', { name: 'Link form' });
|
|
140
140
|
this.embedButton = page.locator('[data-test="confirm-move"]');
|
|
141
141
|
this.newForm = page.locator('[data-test="item-New form"]');
|
|
@@ -349,6 +349,7 @@ class ModelerCreatePage {
|
|
|
349
349
|
await this.fillTenantIdInput(tenant);
|
|
350
350
|
}
|
|
351
351
|
await this.clickDeployAndRunSubButton();
|
|
352
|
+
await (0, test_1.expect)(this.dialog).not.toBeVisible();
|
|
352
353
|
await this.instanceStartedAssertion();
|
|
353
354
|
return;
|
|
354
355
|
}
|
|
@@ -65,6 +65,8 @@ class PlayPage {
|
|
|
65
65
|
});
|
|
66
66
|
}
|
|
67
67
|
async clickCompleteJobButton() {
|
|
68
|
+
await (0, test_1.expect)(this.completeJobButton).toBeVisible({ timeout: 30000 });
|
|
69
|
+
await (0, test_1.expect)(this.completeJobButton).toBeEnabled({ timeout: 30000 });
|
|
68
70
|
await this.completeJobButton.click();
|
|
69
71
|
}
|
|
70
72
|
async clickStartInstanceButton() {
|
|
@@ -9,7 +9,6 @@ const loggingUtils_1 = require("../../utils/loggingUtils");
|
|
|
9
9
|
const resetSession_1 = require("../../utils/resetSession");
|
|
10
10
|
const KeycloakUtils_1 = require("../../pages/SM-8.9/KeycloakUtils");
|
|
11
11
|
SM_8_9_1.test.describe.parallel('Smoke Tests', () => {
|
|
12
|
-
SM_8_9_1.test.skip(true, 'Skipped due to Identity/admin change, will check and re-enable once the changes are in place');
|
|
13
12
|
SM_8_9_1.test.beforeEach(async ({ navigationPage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, page, browser, loginPage, ocIdentityHomePage, ocIdentityRolesPage, }, testInfo) => {
|
|
14
13
|
if (process.env.IS_MIGRATION === 'true') {
|
|
15
14
|
await navigationPage.goToOCIdentity((testInfo.workerIndex + 1) * 1000);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const c8Run_8_9_1 = require("../../fixtures/c8Run-8.9");
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
const UtilitiesPage_1 = require("../../pages/c8Run-8.9/UtilitiesPage");
|
|
6
|
+
const _setup_1 = require("../../test-setup.js");
|
|
7
|
+
const apiHelpers_1 = require("../../utils/apiHelpers");
|
|
8
|
+
const keycloakHelpers_1 = require("../../utils/keycloakHelpers");
|
|
9
|
+
const zeebeClient_1 = require("../../utils/zeebeClient");
|
|
10
|
+
const sleep_1 = require("../../utils/sleep");
|
|
11
|
+
let bearerToken;
|
|
12
|
+
const authMethods = [
|
|
13
|
+
{
|
|
14
|
+
name: 'Basic Auth',
|
|
15
|
+
processId: 'mcp_remote_client_basic_auth',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: 'Bearer Token',
|
|
19
|
+
processId: 'mcp_remote_client_bearer_auth',
|
|
20
|
+
getVariables: () => ({ bearerToken }),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'OAuth Client Credentials',
|
|
24
|
+
processId: 'mcp_remote_client_oauth_auth',
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
c8Run_8_9_1.test.beforeAll(async () => {
|
|
28
|
+
if (process.env.MCP_SERVER_AVAILABLE !== 'true') {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
await (0, apiHelpers_1.validateMcpServerHealth)('http://127.0.0.1:12001'); // No auth
|
|
32
|
+
await (0, apiHelpers_1.validateMcpServerHealth)('http://127.0.0.1:12002'); // Basic auth
|
|
33
|
+
await (0, apiHelpers_1.validateMcpServerHealth)('http://127.0.0.1:12004'); // OAuth
|
|
34
|
+
await (0, keycloakHelpers_1.validateKeycloakHealth)();
|
|
35
|
+
bearerToken = await (0, keycloakHelpers_1.getAccessToken)();
|
|
36
|
+
await (0, zeebeClient_1.deploy)([
|
|
37
|
+
'./resources/mcp_server/mcp_remote_client_basic_auth.bpmn',
|
|
38
|
+
'./resources/mcp_server/mcp_remote_client_bearer_auth.bpmn',
|
|
39
|
+
'./resources/mcp_server/mcp_remote_client_oauth_auth.bpmn',
|
|
40
|
+
]);
|
|
41
|
+
});
|
|
42
|
+
c8Run_8_9_1.test.describe('@tasklistV2 MCP Client connector authentication tests', () => {
|
|
43
|
+
c8Run_8_9_1.test.skip(process.env.MCP_SERVER_AVAILABLE !== 'true', 'MCP authentication servers require Docker and are only available on Linux CI runners');
|
|
44
|
+
c8Run_8_9_1.test.beforeEach(async ({ page, operateLoginPage, operateHomePage }) => {
|
|
45
|
+
await (0, UtilitiesPage_1.navigateToApp)(page, 'operate');
|
|
46
|
+
await operateLoginPage.login('demo', 'demo');
|
|
47
|
+
await operateHomePage.operateBannerIsVisible();
|
|
48
|
+
});
|
|
49
|
+
c8Run_8_9_1.test.afterEach(async ({ page }, testInfo) => {
|
|
50
|
+
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
51
|
+
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
52
|
+
});
|
|
53
|
+
for (const { name, processId, getVariables } of authMethods) {
|
|
54
|
+
(0, c8Run_8_9_1.test)(`As a user I can authenticate using ${name} and list tools`, async ({ operateHomePage, operateProcessesPage, operateProcessInstancePage, }) => {
|
|
55
|
+
await (0, zeebeClient_1.createInstances)(processId, 1, 1, getVariables?.());
|
|
56
|
+
await (0, sleep_1.sleep)(2000);
|
|
57
|
+
await c8Run_8_9_1.test.step('Navigate to completed process instance', async () => {
|
|
58
|
+
await operateHomePage.clickProcessesTab();
|
|
59
|
+
await operateProcessesPage.clickProcessCompletedCheckbox();
|
|
60
|
+
await operateProcessesPage.clickProcessInstanceLink(processId);
|
|
61
|
+
await operateProcessInstancePage.completedIconAssertion();
|
|
62
|
+
});
|
|
63
|
+
await c8Run_8_9_1.test.step(`Verify ${name} successfully listed tools`, async () => {
|
|
64
|
+
await operateProcessInstancePage.verifyVariableJsonContent('listToolsResult', (value) => {
|
|
65
|
+
const data = value;
|
|
66
|
+
(0, test_1.expect)(data.toolDefinitions).toBeDefined();
|
|
67
|
+
(0, test_1.expect)(data.toolDefinitions.length).toBeGreaterThan(0);
|
|
68
|
+
(0, test_1.expect)(data.toolDefinitions.some((tool) => tool.name)).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helper functions for interacting with Keycloak OAuth2 server
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Fetches an OAuth2 access token from Keycloak using client credentials flow
|
|
6
|
+
* @param realm - Keycloak realm name
|
|
7
|
+
* @param clientId - OAuth2 client ID
|
|
8
|
+
* @param clientSecret - OAuth2 client secret
|
|
9
|
+
* @param keycloakUrl - Base URL of Keycloak server
|
|
10
|
+
* @returns Access token string
|
|
11
|
+
*/
|
|
12
|
+
export declare function getAccessToken(realm?: string, clientId?: string, clientSecret?: string, keycloakUrl?: string): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* Validates that Keycloak server is healthy and accessible
|
|
15
|
+
* @param keycloakUrl - Base URL of Keycloak server
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateKeycloakHealth(keycloakUrl?: string): Promise<void>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Helper functions for interacting with Keycloak OAuth2 server
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.validateKeycloakHealth = exports.getAccessToken = void 0;
|
|
7
|
+
const DEFAULT_KEYCLOAK_URL = process.env.KEYCLOAK_URL || 'http://127.0.0.1:18080';
|
|
8
|
+
const DEFAULT_REALM = 'camunda-platform';
|
|
9
|
+
const DEFAULT_CLIENT_ID = 'zeebe';
|
|
10
|
+
const DEFAULT_CLIENT_SECRET = 'zecobe-secret';
|
|
11
|
+
/**
|
|
12
|
+
* Fetches an OAuth2 access token from Keycloak using client credentials flow
|
|
13
|
+
* @param realm - Keycloak realm name
|
|
14
|
+
* @param clientId - OAuth2 client ID
|
|
15
|
+
* @param clientSecret - OAuth2 client secret
|
|
16
|
+
* @param keycloakUrl - Base URL of Keycloak server
|
|
17
|
+
* @returns Access token string
|
|
18
|
+
*/
|
|
19
|
+
async function getAccessToken(realm = DEFAULT_REALM, clientId = DEFAULT_CLIENT_ID, clientSecret = DEFAULT_CLIENT_SECRET, keycloakUrl = DEFAULT_KEYCLOAK_URL) {
|
|
20
|
+
const tokenEndpoint = `${keycloakUrl}/realms/${realm}/protocol/openid-connect/token`;
|
|
21
|
+
const params = new URLSearchParams();
|
|
22
|
+
params.append('grant_type', 'client_credentials');
|
|
23
|
+
params.append('client_id', clientId);
|
|
24
|
+
params.append('client_secret', clientSecret);
|
|
25
|
+
try {
|
|
26
|
+
const response = await fetch(tokenEndpoint, {
|
|
27
|
+
method: 'POST',
|
|
28
|
+
headers: {
|
|
29
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
30
|
+
},
|
|
31
|
+
body: params.toString(),
|
|
32
|
+
});
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
const errorText = await response.text();
|
|
35
|
+
throw new Error(`Failed to fetch access token from Keycloak: ${response.status} ${response.statusText}\n${errorText}`);
|
|
36
|
+
}
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
if (!data.access_token) {
|
|
39
|
+
throw new Error('Access token not found in Keycloak response: ' + JSON.stringify(data));
|
|
40
|
+
}
|
|
41
|
+
return data.access_token;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (error instanceof Error) {
|
|
45
|
+
throw new Error(`Error fetching Keycloak access token: ${error.message}`);
|
|
46
|
+
}
|
|
47
|
+
throw error;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.getAccessToken = getAccessToken;
|
|
51
|
+
/**
|
|
52
|
+
* Validates that Keycloak server is healthy and accessible
|
|
53
|
+
* @param keycloakUrl - Base URL of Keycloak server
|
|
54
|
+
*/
|
|
55
|
+
async function validateKeycloakHealth(keycloakUrl = DEFAULT_KEYCLOAK_URL) {
|
|
56
|
+
// Check if the camunda-platform realm is accessible instead of health endpoint
|
|
57
|
+
// since Keycloak 23+ may not expose health endpoints by default
|
|
58
|
+
const realmEndpoint = `${keycloakUrl}/realms/camunda-platform`;
|
|
59
|
+
try {
|
|
60
|
+
const response = await fetch(realmEndpoint, {
|
|
61
|
+
method: 'GET',
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
throw new Error(`Keycloak realm check failed: ${response.status} ${response.statusText}`);
|
|
65
|
+
}
|
|
66
|
+
console.log(`Keycloak server is healthy at ${keycloakUrl}`);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error instanceof Error) {
|
|
70
|
+
throw new Error(`Keycloak server is not available at ${keycloakUrl}: ${error.message}\n` +
|
|
71
|
+
'Make sure Keycloak is running with: docker run -d --name keycloak -p 18080:8080 ' +
|
|
72
|
+
'-e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin ' +
|
|
73
|
+
'quay.io/keycloak/keycloak:23.0 start-dev');
|
|
74
|
+
}
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.validateKeycloakHealth = validateKeycloakHealth;
|