@camunda/e2e-test-suite 0.0.1176 → 0.0.1178
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/ConsoleOrganizationPage.js +6 -2
- package/dist/pages/SM-8.10/OCIdentityRolesPage.js +9 -6
- package/dist/tests/8.10/test-setup.spec.js +4 -0
- package/dist/tests/8.10/web-modeler-user-flows.spec.js +39 -3
- package/dist/utils/consoleApiHelpers.d.ts +2 -0
- package/dist/utils/consoleApiHelpers.js +47 -1
- package/package.json +1 -1
|
@@ -256,8 +256,12 @@ class ConsoleOrganizationPage {
|
|
|
256
256
|
});
|
|
257
257
|
const alphaFeature = this.rows.filter({ hasText: name }).first();
|
|
258
258
|
if ((await alphaFeature.count()) < 1) {
|
|
259
|
-
|
|
260
|
-
|
|
259
|
+
// Returning here used to report the feature as enabled while nothing
|
|
260
|
+
// had been enabled at all, so the org silently stayed opted out and
|
|
261
|
+
// every dependent spec failed later on a missing UI affordance.
|
|
262
|
+
// Throw instead: the surrounding loop reloads and retries, and a
|
|
263
|
+
// genuinely absent row fails this step where the cause is visible.
|
|
264
|
+
throw new Error(`No alpha feature(${name}) is found.`);
|
|
261
265
|
}
|
|
262
266
|
//Opt-in The Alpha Feature
|
|
263
267
|
const alphaFeatureOptInButton = alphaFeature.getByRole('button', {
|
|
@@ -64,14 +64,17 @@ class OCIdentityRolesPage {
|
|
|
64
64
|
name: SEARCH_MAPPING_RULE_LABEL,
|
|
65
65
|
}))
|
|
66
66
|
.first();
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
// popover
|
|
72
|
-
//
|
|
67
|
+
// The current design-system modal renders the cmdk <input cmdk-input> inline
|
|
68
|
+
// inside the dialog (data-slot="command-input", role="combobox"), so the
|
|
69
|
+
// trigger and the editable field are the same element - match that input
|
|
70
|
+
// scoped to the dialog. Older builds render a MultiSelect whose trigger div
|
|
71
|
+
// opens a Radix popover that portals to <body> as a sibling of the dialog,
|
|
72
|
+
// with the editable cmdk <input> inside it; that popover input is outside
|
|
73
|
+
// the dialog subtree, so match it page-wide. Pre-design-system builds render
|
|
74
|
+
// a dialog-scoped searchbox instead of either - fall back to that last.
|
|
73
75
|
this.mappingSearchBox = page
|
|
74
76
|
.locator('[data-slot="multi-select-content"] input[cmdk-input]')
|
|
77
|
+
.or(this.assignMappingModal.locator('input[cmdk-input]'))
|
|
75
78
|
.or(this.assignMappingModal.getByRole('searchbox', {
|
|
76
79
|
name: SEARCH_MAPPING_RULE_LABEL,
|
|
77
80
|
}))
|
|
@@ -25,6 +25,10 @@ _8_10_1.test.describe('Cluster Setup Tests', () => {
|
|
|
25
25
|
await homePage.clickOrganization();
|
|
26
26
|
await (0, UtilitiesPage_1.assertLocatorVisibleWithRetry)(page, consoleOrganizationsPage.settingsTab, 'settings tab', 60000, false, 2);
|
|
27
27
|
await consoleOrganizationsPage.enableAlphaFeature('AI-powered features');
|
|
28
|
+
// Confirm the opt-in against Accounts rather than trusting the Console
|
|
29
|
+
// toggle: the AI specs depend on this flag, and a setup that passes without
|
|
30
|
+
// it leaves them failing on a button Web Modeler never renders.
|
|
31
|
+
await (0, consoleApiHelpers_1.waitForAiFeaturesEnabledViaApi)(page);
|
|
28
32
|
});
|
|
29
33
|
(0, _8_10_1.test)('Create Default Cluster', async ({ page, loginPage, homePage, clusterPage, clusterDetailsPage, clusterSecretsPage, }, testInfo) => {
|
|
30
34
|
_8_10_1.test.slow();
|
|
@@ -11,6 +11,7 @@ const OptimizeDashboardPage_1 = require("../../pages/8.10/OptimizeDashboardPage"
|
|
|
11
11
|
const fileUpload_1 = require("../../utils/fileUpload");
|
|
12
12
|
const _setup_1 = require("../../test-setup.js");
|
|
13
13
|
const UtilitiesPage_1 = require("../../pages/8.10/UtilitiesPage");
|
|
14
|
+
const consoleApiHelpers_1 = require("../../utils/consoleApiHelpers");
|
|
14
15
|
const deleteOrg_1 = require("../../utils/deleteOrg");
|
|
15
16
|
const sleep_1 = require("../../utils/sleep");
|
|
16
17
|
const mailSlurpClient_1 = require("../../utils/mailSlurpClient");
|
|
@@ -34,11 +35,25 @@ _8_10_1.test.describe('Web Modeler User Flow Tests', () => {
|
|
|
34
35
|
await (0, mailSlurpClient_1.deleteInbox)(inboxes[testInfo.title]);
|
|
35
36
|
}
|
|
36
37
|
});
|
|
37
|
-
(0, _8_10_1.test)('Form.js Integration with User Task and AI Generated Form @ai-external', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, }) => {
|
|
38
|
+
(0, _8_10_1.test)('Form.js Integration with User Task and AI Generated Form @ai-external', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, consoleOrganizationsPage, }) => {
|
|
38
39
|
_8_10_1.test.slow();
|
|
39
40
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
40
41
|
const processName = 'User_Task_Process_With_AI_Form' + randomString;
|
|
41
42
|
const formName = 'New form' + randomString;
|
|
43
|
+
// Web Modeler renders the AI Form Generator only while the org carries the
|
|
44
|
+
// 'aifeatures' early-access flag, which the 'Enable Alpha Features' setup
|
|
45
|
+
// test is responsible for. When that opt-in does not take, the palette
|
|
46
|
+
// button is simply absent and this test times out on it with nothing
|
|
47
|
+
// pointing at the org. Confirm the prerequisite here, and opt in when it is
|
|
48
|
+
// missing, so the flow no longer depends on setup having succeeded silently.
|
|
49
|
+
await _8_10_1.test.step('Ensure AI Features Are Enabled For The Organization', async () => {
|
|
50
|
+
if (await (0, consoleApiHelpers_1.areAiFeaturesEnabledViaApi)(page)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
await homePage.clickOrganization();
|
|
54
|
+
await consoleOrganizationsPage.enableAlphaFeature('AI-powered features');
|
|
55
|
+
await (0, consoleApiHelpers_1.waitForAiFeaturesEnabledViaApi)(page);
|
|
56
|
+
});
|
|
42
57
|
await _8_10_1.test.step('Navigate to Web Modeler', async () => {
|
|
43
58
|
await (0, test_1.expect)(homePage.camundaComponentsButton).toBeVisible({
|
|
44
59
|
timeout: 120000,
|
|
@@ -70,12 +85,27 @@ _8_10_1.test.describe('Web Modeler User Flow Tests', () => {
|
|
|
70
85
|
await (0, test_1.expect)(modelerCreatePage.viewProcessInstanceLink).toBeVisible({
|
|
71
86
|
timeout: 180000,
|
|
72
87
|
});
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
// Latch the Operate instance deep link on the CONTEXT before the click.
|
|
89
|
+
// Playwright raises `popup` only once the new tab's initial response has
|
|
90
|
+
// started loading, and a session-less Operate tab's auth redirect chain
|
|
91
|
+
// drops the instance path before anything commits -- so no listener
|
|
92
|
+
// attached to the popup afterwards ever sees that URL. Without it
|
|
93
|
+
// `waitForInstanceLocator` has nothing to re-open and can only poll
|
|
94
|
+
// whatever the tab was left on, where the instance page can never
|
|
95
|
+
// render: "Assertion of Instance History panel in Operate timed out
|
|
96
|
+
// after 480000ms (instance header not rendered,
|
|
97
|
+
// url=<cluster>/operate?continue, instance deep link never captured)".
|
|
98
|
+
// `openAppTabWithRetry` also registers the popup wait BEFORE the click,
|
|
99
|
+
// which `waitForEvent` after the click cannot, and re-clicks a click
|
|
100
|
+
// that resolved without opening a tab. Same pattern as
|
|
101
|
+
// tests/8.10/connectors-user-flows.spec.ts and smoke-tests.spec.ts.
|
|
102
|
+
const watchedInstanceUrl = (0, OperateProcessInstancePage_1.watchOperateInstanceUrl)(page.context());
|
|
103
|
+
const operateTab = await (0, UtilitiesPage_1.openAppTabWithRetry)(page, modelerCreatePage.viewProcessInstanceLink);
|
|
75
104
|
const operateTabAppsPage = new AppsPage_1.AppsPage(operateTab);
|
|
76
105
|
const operateTabOperateProcessInstancePage = new OperateProcessInstancePage_1.OperateProcessInstancePage(operateTab);
|
|
77
106
|
const operateTabTaskPanelPage = new TaskPanelPage_1.TaskPanelPage(operateTab);
|
|
78
107
|
const operateTabTaskDetailsPage = new TaskDetailsPage_1.TaskDetailsPage(operateTab);
|
|
108
|
+
await operateTabOperateProcessInstancePage.rememberInstanceUrl(60000, watchedInstanceUrl);
|
|
79
109
|
await operateTabOperateProcessInstancePage.closePopOverIfVisible();
|
|
80
110
|
await (0, test_1.expect)(operateTabOperateProcessInstancePage.activeIcon).toBeVisible({ timeout: 180000 });
|
|
81
111
|
await operateTabAppsPage.clickCamundaApps();
|
|
@@ -85,6 +115,12 @@ _8_10_1.test.describe('Web Modeler User Flow Tests', () => {
|
|
|
85
115
|
await (0, test_1.expect)(operateTabTaskDetailsPage.assignedToMeText).toBeVisible({
|
|
86
116
|
timeout: 60000,
|
|
87
117
|
});
|
|
118
|
+
// Tasklist mounts the embedded form asynchronously once the task is
|
|
119
|
+
// assigned, so the task pane is briefly empty. fillName() inherits the
|
|
120
|
+
// 10s global actionTimeout, which the form does not always beat -- wait
|
|
121
|
+
// for its first field (reloading between attempts, since a form that
|
|
122
|
+
// failed to mount stays empty) instead of racing it.
|
|
123
|
+
await (0, UtilitiesPage_1.assertLocatorVisibleWithRetry)(operateTab, operateTabTaskDetailsPage.nameInput, 'AI generated form name field', 60000, false, 3);
|
|
88
124
|
await operateTabTaskDetailsPage.fillName('test user');
|
|
89
125
|
await operateTabTaskDetailsPage.checkCheckbox();
|
|
90
126
|
await operateTabTaskDetailsPage.fillDate('11/11/1999');
|
|
@@ -6,3 +6,5 @@ export declare function ensureTasklistV2Enabled(page: Page, clusterUuid: string)
|
|
|
6
6
|
export declare function ensureClientAuditLoggingViaApi(page: Page, clusterUuid: string): Promise<void>;
|
|
7
7
|
export declare function waitForClusterHealthyViaApi(page: Page, clusterUuid: string, timeoutMs?: number): Promise<void>;
|
|
8
8
|
export declare function waitForClusterRestartHealthyViaApi(page: Page, clusterUuid: string, timeoutMs?: number): Promise<void>;
|
|
9
|
+
export declare function areAiFeaturesEnabledViaApi(page: Page): Promise<boolean>;
|
|
10
|
+
export declare function waitForAiFeaturesEnabledViaApi(page: Page, 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.ensureClientAuditLoggingViaApi = exports.ensureTasklistV2Enabled = exports.ensureClusterViaApi = exports.createClusterViaApi = exports.deleteClusterViaApi = void 0;
|
|
3
|
+
exports.waitForAiFeaturesEnabledViaApi = exports.areAiFeaturesEnabledViaApi = 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';
|
|
@@ -552,3 +552,49 @@ async function waitForClusterRestartHealthyViaApi(page, clusterUuid, timeoutMs =
|
|
|
552
552
|
}).toPass({ timeout: timeoutMs, intervals: [30000, 60000] });
|
|
553
553
|
}
|
|
554
554
|
exports.waitForClusterRestartHealthyViaApi = waitForClusterRestartHealthyViaApi;
|
|
555
|
+
// Web Modeler only mounts the AI form assistant -- and with it the
|
|
556
|
+
// "AI Form Generator" palette button -- when the organization has accepted the
|
|
557
|
+
// alpha/AI terms AND carries the 'aifeatures' early-access flag. camunda-hub
|
|
558
|
+
// gates the whole module on that pair in
|
|
559
|
+
// frontend/apps/hub/src/experiments/ai-features/utils/are-ai-features-enabled.saas.ts.
|
|
560
|
+
// The 'Enable Alpha Features' setup test drives the opt-in through Console, but
|
|
561
|
+
// it can finish green without the opt-in having taken (see
|
|
562
|
+
// ConsoleOrganizationPage.enableAlphaFeature), and then every AI spec in that
|
|
563
|
+
// org fails on a button that is simply never rendered. Reading the flag back
|
|
564
|
+
// from Accounts turns that invisible state into an assertable one.
|
|
565
|
+
const AI_EARLY_ACCESS_FEATURE = 'aifeatures';
|
|
566
|
+
function getAccountsBaseUrl() {
|
|
567
|
+
if (process.env.IS_PROD === 'true') {
|
|
568
|
+
return 'https://accounts.cloud.camunda.io';
|
|
569
|
+
}
|
|
570
|
+
const uiUrl = process.env.PLAYWRIGHT_BASE_URL ?? 'https://console.ultrawombat.com';
|
|
571
|
+
return uiUrl
|
|
572
|
+
.replace('console.ultrawombat.com', 'accounts.cloud.ultrawombat.com')
|
|
573
|
+
.replace('console.camunda.io', 'accounts.cloud.camunda.io');
|
|
574
|
+
}
|
|
575
|
+
async function areAiFeaturesEnabledViaApi(page) {
|
|
576
|
+
const response = await clusterApiRequest(page, 'GET', `${getAccountsBaseUrl()}/api/organizations/${getOrgId()}`);
|
|
577
|
+
if (!response.ok()) {
|
|
578
|
+
throw new Error(`Failed to read organization info: HTTP ${response.status()} ` +
|
|
579
|
+
`${await response.text()}`);
|
|
580
|
+
}
|
|
581
|
+
const organization = (await response.json());
|
|
582
|
+
return (organization.hasAcceptedBetaTerms === true &&
|
|
583
|
+
(organization.earlyAccessFeatures ?? []).includes(AI_EARLY_ACCESS_FEATURE));
|
|
584
|
+
}
|
|
585
|
+
exports.areAiFeaturesEnabledViaApi = areAiFeaturesEnabledViaApi;
|
|
586
|
+
// Console reports the opt-in as done before Accounts serves the updated
|
|
587
|
+
// organization record, so poll rather than reading once.
|
|
588
|
+
async function waitForAiFeaturesEnabledViaApi(page, timeoutMs = 180000) {
|
|
589
|
+
await test_1.expect
|
|
590
|
+
.poll(async () => await areAiFeaturesEnabledViaApi(page), {
|
|
591
|
+
timeout: timeoutMs,
|
|
592
|
+
intervals: [5000],
|
|
593
|
+
message: `Organization ${getOrgId()} does not have the ` +
|
|
594
|
+
`'${AI_EARLY_ACCESS_FEATURE}' early-access feature enabled, so Web ` +
|
|
595
|
+
'Modeler will not render the AI Form Generator. The alpha/AI terms ' +
|
|
596
|
+
'opt-in in organization settings did not take.',
|
|
597
|
+
})
|
|
598
|
+
.toBe(true);
|
|
599
|
+
}
|
|
600
|
+
exports.waitForAiFeaturesEnabledViaApi = waitForAiFeaturesEnabledViaApi;
|