@camunda/e2e-test-suite 0.0.1018 → 0.0.1020
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/AuditLogPage.js +5 -0
- package/dist/pages/8.9/ModelerHomePage.d.ts +2 -0
- package/dist/pages/8.9/ModelerHomePage.js +27 -0
- package/dist/pages/8.9/OCIdentityRolesPage.js +7 -2
- package/dist/tests/8.10/test-setup.spec.js +4 -3
- package/dist/tests/8.9/idp-user-flows.spec.js +15 -12
- package/dist/utils/consoleApiHelpers.d.ts +1 -0
- package/dist/utils/consoleApiHelpers.js +37 -1
- package/dist/utils/constants.js +7 -8
- package/package.json +1 -1
|
@@ -38,6 +38,11 @@ class AuditLogPage {
|
|
|
38
38
|
await (0, test_1.expect)(checkbox).toBeChecked();
|
|
39
39
|
return true;
|
|
40
40
|
}
|
|
41
|
+
// Not used by cluster setup: Console re-seeds this panel's checkbox state
|
|
42
|
+
// from the cluster on every background refresh, so selections made before
|
|
43
|
+
// "Update" is pressed can be dropped and only some categories get saved. Use
|
|
44
|
+
// ensureClientAuditLoggingViaApi (utils/consoleApiHelpers) to configure a
|
|
45
|
+
// cluster; drive this only when the UI itself is what is under test.
|
|
41
46
|
async enableClientOperationLogging() {
|
|
42
47
|
const categories = [
|
|
43
48
|
'Administration',
|
|
@@ -23,6 +23,7 @@ declare class ModelerHomePage {
|
|
|
23
23
|
readonly uploadFilesButton: Locator;
|
|
24
24
|
readonly messageBanner: Locator;
|
|
25
25
|
readonly idpTemplateOption: Locator;
|
|
26
|
+
readonly idpEmptyStateButton: Locator;
|
|
26
27
|
readonly idpApplicationNameInput: Locator;
|
|
27
28
|
readonly createIdpApplicationButton: Locator;
|
|
28
29
|
readonly dialog: Locator;
|
|
@@ -40,6 +41,7 @@ declare class ModelerHomePage {
|
|
|
40
41
|
clickProcessDiagram(name: string): Promise<void>;
|
|
41
42
|
clickDiagramTypeDropdown(): Promise<void>;
|
|
42
43
|
clickWorkspaceDiagramTypeDropdown(): Promise<void>;
|
|
44
|
+
startIdpApplicationCreation(): Promise<void>;
|
|
43
45
|
clickBpmnTemplateOption(): Promise<void>;
|
|
44
46
|
clickFormOption(): Promise<void>;
|
|
45
47
|
enterFormName(name: string): Promise<void>;
|
|
@@ -40,6 +40,7 @@ class ModelerHomePage {
|
|
|
40
40
|
uploadFilesButton;
|
|
41
41
|
messageBanner;
|
|
42
42
|
idpTemplateOption;
|
|
43
|
+
idpEmptyStateButton;
|
|
43
44
|
idpApplicationNameInput;
|
|
44
45
|
createIdpApplicationButton;
|
|
45
46
|
dialog;
|
|
@@ -68,6 +69,12 @@ class ModelerHomePage {
|
|
|
68
69
|
this.idpTemplateOption = page
|
|
69
70
|
.locator('[data-test="create-idp-application"]')
|
|
70
71
|
.getByText('IDP Application');
|
|
72
|
+
// Empty workspace root: a plain button in hub's EmptyStateActionButtons,
|
|
73
|
+
// next to the "Create process application" CTA that ProcessApplicationPage
|
|
74
|
+
// already reaches for. .first() defensively only, matching that locator.
|
|
75
|
+
this.idpEmptyStateButton = page
|
|
76
|
+
.getByRole('button', { name: 'Create IDP application' })
|
|
77
|
+
.first();
|
|
71
78
|
this.diagramTypeDropdown = page.locator('[data-test="diagram-dropdown"]');
|
|
72
79
|
// Matched on the test id alone: hub's design-system variant of the create
|
|
73
80
|
// menu renders "BPMN diagram" (lowercase d), so a text filter breaks the
|
|
@@ -189,6 +196,26 @@ class ModelerHomePage {
|
|
|
189
196
|
});
|
|
190
197
|
await this.diagramTypeDropdown.click();
|
|
191
198
|
}
|
|
199
|
+
// Starts an IDP application from the workspace root. Which control exists
|
|
200
|
+
// there depends on whether the workspace holds anything: hub's EntityTable
|
|
201
|
+
// renders either the toolbar -- whose "Create new" menu carries the IDP item
|
|
202
|
+
// -- or the empty state, whose CTA is a plain button, never both. A fresh
|
|
203
|
+
// org lands on the empty state, so waiting on the menu alone finds no
|
|
204
|
+
// element at all. Race both and use whichever rendered; same shape as
|
|
205
|
+
// clickCreateProcessApplication, which already covers this for the sibling
|
|
206
|
+
// resource type.
|
|
207
|
+
async startIdpApplicationCreation() {
|
|
208
|
+
const rootLoaded = await this.becameVisible(this.idpEmptyStateButton.or(this.diagramTypeDropdown).first(), 60000);
|
|
209
|
+
if (!rootLoaded) {
|
|
210
|
+
await this.page.reload();
|
|
211
|
+
}
|
|
212
|
+
if (await this.becameVisible(this.idpEmptyStateButton, 5000)) {
|
|
213
|
+
await this.idpEmptyStateButton.click({ timeout: 60000 });
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
await this.clickWorkspaceDiagramTypeDropdown();
|
|
217
|
+
await this.clickIdpApplicationTemplateOption();
|
|
218
|
+
}
|
|
192
219
|
async clickBpmnTemplateOption() {
|
|
193
220
|
await (0, test_1.expect)(this.bpmnTemplateOption).toBeVisible({
|
|
194
221
|
timeout: 15000,
|
|
@@ -4,6 +4,7 @@ exports.OCIdentityRolesPage = void 0;
|
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
6
6
|
const expectLocatorWithPagination_1 = require("../../utils/assertionHelpers/expectLocatorWithPagination");
|
|
7
|
+
const submitModalWithRetry_1 = require("../../utils/assertionHelpers/submitModalWithRetry");
|
|
7
8
|
class OCIdentityRolesPage {
|
|
8
9
|
page;
|
|
9
10
|
selectResourceTypeTab;
|
|
@@ -128,8 +129,12 @@ class OCIdentityRolesPage {
|
|
|
128
129
|
await (0, test_1.expect)(this.createRoleModal).toBeVisible({ timeout: 30000 });
|
|
129
130
|
await this.createIdField.fill(role.id);
|
|
130
131
|
await this.createNameField.fill(role.name);
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
// POST /v2/roles intermittently answers 503 UNAVAILABLE ("connection error
|
|
133
|
+
// with one of the brokers") while a freshly created org's orchestration
|
|
134
|
+
// cluster settles. The modal then stays open with the form still valid, so
|
|
135
|
+
// re-submitting recovers; the close assertion itself is unchanged, and a
|
|
136
|
+
// persistent failure still fails the test.
|
|
137
|
+
await (0, submitModalWithRetry_1.submitModalWithRetry)(this.createRoleModalCreateButton, this.createRoleModal, { closeTimeout: 30000 });
|
|
133
138
|
await (0, expectLocatorWithPagination_1.expectLocatorWithPagination)(this.page, this.rolesList
|
|
134
139
|
.getByRole('cell', {
|
|
135
140
|
name: role.name,
|
|
@@ -55,7 +55,7 @@ _8_10_1.test.describe('Cluster Setup Tests', () => {
|
|
|
55
55
|
await clusterSecretsPage.createSetOfSecrets(clusterName, connectorSecrets_1.bedrockCodeInterpreterSecretsValues);
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
|
-
(0, _8_10_1.test)('Create Agentic Orchestration Cluster', async ({ page, loginPage, homePage, clusterPage, clusterDetailsPage, clusterSecretsPage,
|
|
58
|
+
(0, _8_10_1.test)('Create Agentic Orchestration Cluster', async ({ page, loginPage, homePage, clusterPage, clusterDetailsPage, clusterSecretsPage, }, testInfo) => {
|
|
59
59
|
_8_10_1.test.skip(process.env.IS_PROD === 'true', 'Skipping test because not required on PROD test org');
|
|
60
60
|
_8_10_1.test.skip(process.env.IS_AG === 'true', 'Skipping test because not required when IS_AG is true');
|
|
61
61
|
_8_10_1.test.slow();
|
|
@@ -69,8 +69,9 @@ _8_10_1.test.describe('Cluster Setup Tests', () => {
|
|
|
69
69
|
await homePage.clickClusters();
|
|
70
70
|
await clusterPage.clickClusterLink(clusterName);
|
|
71
71
|
await clusterDetailsPage.assertComponentsHealth();
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
// Must happen before the MCP toggle: the restart that toggle triggers is
|
|
73
|
+
// what makes the new audit-log configuration live on the cluster.
|
|
74
|
+
await (0, consoleApiHelpers_1.ensureClientAuditLoggingViaApi)(page, clusterUuid);
|
|
74
75
|
await clusterDetailsPage.clickSettingsTab();
|
|
75
76
|
await clusterDetailsPage.checkMcpSupportToggle();
|
|
76
77
|
// Enabling MCP support restarts the cluster (Console shows a "Restart
|
|
@@ -94,10 +94,11 @@ _8_9_1.test.describe('IDP User Flow Tests', () => {
|
|
|
94
94
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
95
95
|
});
|
|
96
96
|
await _8_9_1.test.step('Add an IDP application to the project', async () => {
|
|
97
|
-
// Workspace
|
|
98
|
-
// workspace root, never inside a process application.
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
// Workspace level: an IDP application can only be created at
|
|
98
|
+
// workspace root, never inside a process application. The control
|
|
99
|
+
// there is the empty-state CTA or the "Create new" menu item,
|
|
100
|
+
// depending on whether the workspace already holds anything.
|
|
101
|
+
await modelerHomePage.startIdpApplicationCreation();
|
|
101
102
|
});
|
|
102
103
|
await _8_9_1.test.step('Creates a document extraction template', async () => {
|
|
103
104
|
await modelerHomePage.enterIdpApplicationName(idpApplicationName);
|
|
@@ -168,10 +169,11 @@ _8_9_1.test.describe('IDP User Flow Tests', () => {
|
|
|
168
169
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
169
170
|
});
|
|
170
171
|
await _8_9_1.test.step('Add an IDP application to the project', async () => {
|
|
171
|
-
// Workspace
|
|
172
|
-
// workspace root, never inside a process application.
|
|
173
|
-
|
|
174
|
-
|
|
172
|
+
// Workspace level: an IDP application can only be created at
|
|
173
|
+
// workspace root, never inside a process application. The control
|
|
174
|
+
// there is the empty-state CTA or the "Create new" menu item,
|
|
175
|
+
// depending on whether the workspace already holds anything.
|
|
176
|
+
await modelerHomePage.startIdpApplicationCreation();
|
|
175
177
|
});
|
|
176
178
|
await _8_9_1.test.step('Creates a document extraction template', async () => {
|
|
177
179
|
await modelerHomePage.enterIdpApplicationName(idpApplicationName);
|
|
@@ -250,10 +252,11 @@ _8_9_1.test.describe('IDP User Flow Tests', () => {
|
|
|
250
252
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
251
253
|
});
|
|
252
254
|
await _8_9_1.test.step('Add an IDP application to the project', async () => {
|
|
253
|
-
// Workspace
|
|
254
|
-
// workspace root, never inside a process application.
|
|
255
|
-
|
|
256
|
-
|
|
255
|
+
// Workspace level: an IDP application can only be created at
|
|
256
|
+
// workspace root, never inside a process application. The control
|
|
257
|
+
// there is the empty-state CTA or the "Create new" menu item,
|
|
258
|
+
// depending on whether the workspace already holds anything.
|
|
259
|
+
await modelerHomePage.startIdpApplicationCreation();
|
|
257
260
|
});
|
|
258
261
|
await _8_9_1.test.step('Creates a classification template', async () => {
|
|
259
262
|
await modelerHomePage.enterIdpApplicationName(idpApplicationName);
|
|
@@ -3,5 +3,6 @@ export declare function deleteClusterViaApi(page: Page, clusterName: string): Pr
|
|
|
3
3
|
export declare function createClusterViaApi(page: Page, clusterName: string, region?: string, tasklistV2Enabled?: boolean): Promise<string>;
|
|
4
4
|
export declare function ensureClusterViaApi(page: Page, clusterName: string, region?: string, tasklistV2Enabled?: boolean): Promise<string>;
|
|
5
5
|
export declare function ensureTasklistV2Enabled(page: Page, clusterUuid: string): Promise<void>;
|
|
6
|
+
export declare function ensureClientAuditLoggingViaApi(page: Page, clusterUuid: string): Promise<void>;
|
|
6
7
|
export declare function waitForClusterHealthyViaApi(page: Page, clusterUuid: string, timeoutMs?: number): Promise<void>;
|
|
7
8
|
export declare function waitForClusterRestartHealthyViaApi(page: Page, clusterUuid: string, timeoutMs?: number): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.waitForClusterRestartHealthyViaApi = exports.waitForClusterHealthyViaApi = exports.ensureTasklistV2Enabled = exports.ensureClusterViaApi = exports.createClusterViaApi = exports.deleteClusterViaApi = void 0;
|
|
3
|
+
exports.waitForClusterRestartHealthyViaApi = exports.waitForClusterHealthyViaApi = exports.ensureClientAuditLoggingViaApi = exports.ensureTasklistV2Enabled = exports.ensureClusterViaApi = exports.createClusterViaApi = exports.deleteClusterViaApi = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const sleep_1 = require("./sleep");
|
|
6
6
|
const PLAN_TYPE_ID = '574cde5f-54ae-43c1-851a-e6fb4f03423a';
|
|
@@ -401,6 +401,42 @@ async function ensureTasklistV2Enabled(page, clusterUuid) {
|
|
|
401
401
|
}
|
|
402
402
|
}
|
|
403
403
|
exports.ensureTasklistV2Enabled = ensureTasklistV2Enabled;
|
|
404
|
+
// Client operation logging is opt-in: a fresh cluster carries no audit-log
|
|
405
|
+
// config at all, which Console renders as "all user categories, no client
|
|
406
|
+
// categories". The MCP audit-log specs assert on CLIENT-actor PROCESS_INSTANCE
|
|
407
|
+
// entries, and the engine only records those when the DEPLOYED_RESOURCES client
|
|
408
|
+
// category is enabled.
|
|
409
|
+
//
|
|
410
|
+
// Driving the Audit log tab's checkboxes cannot set this reliably: the panel
|
|
411
|
+
// re-seeds its checkbox state from the cluster every time Console refreshes it
|
|
412
|
+
// in the background, silently dropping selections made before "Update" is
|
|
413
|
+
// pressed. The 2026-08-26/27 nightlies persisted only the last category clicked
|
|
414
|
+
// ("USER_TASKS"), so DEPLOYED_RESOURCES stayed off and every SC-AUD spec polled
|
|
415
|
+
// an audit log that would never receive an entry. Call the same endpoint the
|
|
416
|
+
// Update button calls, then read the config back until it is really persisted.
|
|
417
|
+
const AUDIT_LOG_CATEGORIES = ['ADMIN', 'DEPLOYED_RESOURCES', 'USER_TASKS'];
|
|
418
|
+
async function ensureClientAuditLoggingViaApi(page, clusterUuid) {
|
|
419
|
+
const orgId = getOrgId();
|
|
420
|
+
const url = `${getConsoleBaseUrl()}/api/orgs/${orgId}/clusters/${clusterUuid}`;
|
|
421
|
+
const response = await clusterApiRequest(page, 'PATCH', url, {
|
|
422
|
+
auditLogEnabled: true,
|
|
423
|
+
auditLogUserCategories: AUDIT_LOG_CATEGORIES,
|
|
424
|
+
auditLogClientCategories: AUDIT_LOG_CATEGORIES,
|
|
425
|
+
});
|
|
426
|
+
if (response.status() !== 200 && response.status() !== 204) {
|
|
427
|
+
throw new Error(`Failed to enable client audit logging on cluster "${clusterUuid}": ` +
|
|
428
|
+
`HTTP ${response.status()} - ${await response.text()}`);
|
|
429
|
+
}
|
|
430
|
+
await (0, test_1.expect)(async () => {
|
|
431
|
+
const readBack = await clusterApiRequest(page, 'GET', url);
|
|
432
|
+
(0, test_1.expect)(readBack.status()).toBe(200);
|
|
433
|
+
const body = await readBack.json();
|
|
434
|
+
const auditLog = (body.data ?? body)?.externalMetadata?.auditLog;
|
|
435
|
+
(0, test_1.expect)(auditLog?.enabled).toBe(true);
|
|
436
|
+
(0, test_1.expect)([...(auditLog?.clientCategories ?? [])].sort()).toEqual([...AUDIT_LOG_CATEGORIES].sort());
|
|
437
|
+
}).toPass({ timeout: 120000, intervals: [2000, 5000, 10000] });
|
|
438
|
+
}
|
|
439
|
+
exports.ensureClientAuditLoggingViaApi = ensureClientAuditLoggingViaApi;
|
|
404
440
|
async function waitForClusterHealthyViaApi(page, clusterUuid, timeoutMs = 1500000) {
|
|
405
441
|
const orgId = getOrgId();
|
|
406
442
|
const url = `${getConsoleBaseUrl()}/api/orgs/${orgId}/clusters/${clusterUuid}`;
|
package/dist/utils/constants.js
CHANGED
|
@@ -14,14 +14,13 @@ exports.deletionAssertionOptions = {
|
|
|
14
14
|
intervals: [5000, 10000, 15000, 30000],
|
|
15
15
|
timeout: 60000,
|
|
16
16
|
};
|
|
17
|
-
// Longest options for audit-log assertions
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
24
|
-
// leaves headroom inside the 12-minute test timeout after the ~60s beforeAll.
|
|
17
|
+
// Longest options for audit-log assertions. Measured on the nightly, a
|
|
18
|
+
// CLIENT-actor PROCESS_INSTANCE CREATE entry surfaces within ~10s whenever the
|
|
19
|
+
// cluster has the DEPLOYED_RESOURCES client category enabled — the earlier 90s
|
|
20
|
+
// and 180s budgets were raised against runs where that category was never
|
|
21
|
+
// persisted at all, so no budget could have helped. Keep a generous 360s so a
|
|
22
|
+
// genuinely slow export still passes; it fits inside the 12-minute test timeout
|
|
23
|
+
// after the ~60s beforeAll.
|
|
25
24
|
exports.auditLogAssertionOptions = {
|
|
26
25
|
intervals: [5000, 10000, 15000, 20000, 30000],
|
|
27
26
|
timeout: 360000,
|