@camunda/e2e-test-suite 0.0.1425 → 0.0.1426
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.
|
@@ -20,6 +20,7 @@ declare class ClusterPage {
|
|
|
20
20
|
readonly dangerDeleteButton: Locator;
|
|
21
21
|
readonly testClusterLink: Locator;
|
|
22
22
|
readonly connectorSecretsTab: Locator;
|
|
23
|
+
readonly connectorSecretsTabSelected: Locator;
|
|
23
24
|
readonly createAClusterButton: Locator;
|
|
24
25
|
readonly clusterVersionOption: Locator;
|
|
25
26
|
readonly generationSearchInput: Locator;
|
|
@@ -25,6 +25,7 @@ class ClusterPage {
|
|
|
25
25
|
dangerDeleteButton;
|
|
26
26
|
testClusterLink;
|
|
27
27
|
connectorSecretsTab;
|
|
28
|
+
connectorSecretsTabSelected;
|
|
28
29
|
createAClusterButton;
|
|
29
30
|
clusterVersionOption;
|
|
30
31
|
generationSearchInput;
|
|
@@ -80,6 +81,13 @@ class ClusterPage {
|
|
|
80
81
|
.or(page.getByRole('tab', {
|
|
81
82
|
name: 'Connector Secrets',
|
|
82
83
|
}));
|
|
84
|
+
// Same tab, but only when it is the active one. Hub renders the cluster
|
|
85
|
+
// tabs as Radix triggers whose active tab is controlled React state, so a
|
|
86
|
+
// visually successful click is not proof the panel switched -- see
|
|
87
|
+
// clickConnectorSecretsTab.
|
|
88
|
+
this.connectorSecretsTabSelected = page
|
|
89
|
+
.getByRole('tab', { name: 'Cluster secrets', selected: true })
|
|
90
|
+
.or(page.getByRole('tab', { name: 'Connector Secrets', selected: true }));
|
|
83
91
|
// Camunda Hub's create-cluster form replaced the Carbon tiles (a
|
|
84
92
|
// <label> per option) and tabs with design-system choice cards and toggle
|
|
85
93
|
// groups, all exposed as role="radio" named by their title. Each locator
|
|
@@ -441,12 +449,41 @@ class ClusterPage {
|
|
|
441
449
|
});
|
|
442
450
|
}
|
|
443
451
|
async clickConnectorSecretsTab(clusterName) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
452
|
+
// Hub's cluster tabs are Radix triggers whose active tab is controlled
|
|
453
|
+
// React state. A background refetch landing right after the click can
|
|
454
|
+
// reset that state back to the default Overview tab, so a single
|
|
455
|
+
// successful click sometimes leaves the panel on Overview and the secrets
|
|
456
|
+
// Import button never mounts (AlwaysGreen run 38259225730: the tab was
|
|
457
|
+
// clicked on a visible/enabled/stable element yet Overview stayed
|
|
458
|
+
// selected for the full 30s Import-button wait). Click, confirm the
|
|
459
|
+
// secrets tab actually became selected, and re-click until it does.
|
|
460
|
+
const maxAttempts = 3;
|
|
461
|
+
const importButton = this.page.getByRole('button', {
|
|
462
|
+
name: 'Import',
|
|
463
|
+
exact: true,
|
|
464
|
+
});
|
|
465
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
466
|
+
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.connectorSecretsTab, {
|
|
467
|
+
postAction: async () => {
|
|
468
|
+
await this.clickClusterBanner();
|
|
469
|
+
await this.clickClusterLink(clusterName);
|
|
470
|
+
},
|
|
471
|
+
});
|
|
472
|
+
const activated = await importButton
|
|
473
|
+
.waitFor({ state: 'visible', timeout: 10000 })
|
|
474
|
+
.then(() => this.connectorSecretsTabSelected.isVisible())
|
|
475
|
+
.catch(() => false);
|
|
476
|
+
if (activated) {
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
// Still on Overview after re-clicking: fail loudly rather than proceeding
|
|
481
|
+
// to a secrets panel that never mounted -- this keeps a genuinely broken
|
|
482
|
+
// panel red instead of masking it.
|
|
483
|
+
await (0, test_1.expect)(this.connectorSecretsTabSelected).toBeVisible({
|
|
484
|
+
timeout: 10000,
|
|
449
485
|
});
|
|
486
|
+
await (0, test_1.expect)(importButton).toBeVisible({ timeout: 10000 });
|
|
450
487
|
}
|
|
451
488
|
async clickLatestStableForMinorVersion() {
|
|
452
489
|
const minorVersion = process.env.MINOR_VERSION;
|
|
@@ -19,6 +19,7 @@ declare class ClusterSecretsPage {
|
|
|
19
19
|
readonly clusterBanner: Locator;
|
|
20
20
|
readonly clusterLink: (name: string) => Locator;
|
|
21
21
|
readonly clusterSecretTab: Locator;
|
|
22
|
+
readonly secretsFetchErrorReloadButton: Locator;
|
|
22
23
|
readonly confirmDeleteInput: Locator;
|
|
23
24
|
constructor(page: Page);
|
|
24
25
|
deleteConnectorSecretsIfExist(): Promise<void>;
|
|
@@ -44,5 +45,6 @@ declare class ClusterSecretsPage {
|
|
|
44
45
|
name: string;
|
|
45
46
|
value: string;
|
|
46
47
|
}[]): Promise<void>;
|
|
48
|
+
private restoreClusterPageIfSignedOut;
|
|
47
49
|
}
|
|
48
50
|
export { ClusterSecretsPage };
|
|
@@ -4,6 +4,7 @@ exports.ClusterSecretsPage = void 0;
|
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const sleep_1 = require("../../utils/sleep");
|
|
6
6
|
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
7
|
+
const sessionRecovery_1 = require("../../utils/sessionRecovery");
|
|
7
8
|
class ClusterSecretsPage {
|
|
8
9
|
page;
|
|
9
10
|
createNewSecretButton;
|
|
@@ -24,6 +25,7 @@ class ClusterSecretsPage {
|
|
|
24
25
|
clusterBanner;
|
|
25
26
|
clusterLink;
|
|
26
27
|
clusterSecretTab;
|
|
28
|
+
secretsFetchErrorReloadButton;
|
|
27
29
|
confirmDeleteInput;
|
|
28
30
|
constructor(page) {
|
|
29
31
|
this.page = page;
|
|
@@ -112,6 +114,11 @@ class ClusterSecretsPage {
|
|
|
112
114
|
this.clusterSecretTab = this.page
|
|
113
115
|
.getByRole('tab', { name: 'Cluster secrets' })
|
|
114
116
|
.or(this.page.getByRole('tab', { name: 'Connector Secrets' }));
|
|
117
|
+
// c4's secrets tab replaces the list with an "Oops ... something went
|
|
118
|
+
// wrong." card when its GET of the secrets fails; this button refetches.
|
|
119
|
+
this.secretsFetchErrorReloadButton = page
|
|
120
|
+
.getByRole('tabpanel', { name: /^(Cluster secrets|Connector Secrets)$/ })
|
|
121
|
+
.getByRole('button', { name: 'Reload', exact: true });
|
|
115
122
|
this.confirmDeleteInput = page.getByRole('textbox', {
|
|
116
123
|
name: 'Type the word DELETE to confirm',
|
|
117
124
|
});
|
|
@@ -390,6 +397,7 @@ class ClusterSecretsPage {
|
|
|
390
397
|
await (0, test_1.expect)(this.createNewSecretButton).toBeVisible({
|
|
391
398
|
timeout: 60000,
|
|
392
399
|
});
|
|
400
|
+
const clusterUrl = this.page.url();
|
|
393
401
|
await this.page.reload();
|
|
394
402
|
// Hub keeps the selected cluster tab out of the URL, so the reload lands
|
|
395
403
|
// on Overview, where assertSecretsOrCreate finds no search box and tries
|
|
@@ -397,10 +405,32 @@ class ClusterSecretsPage {
|
|
|
397
405
|
// The cluster page can still be hydrating after the reload and snap back
|
|
398
406
|
// to Overview after the click lands (CI trace: click succeeded, the
|
|
399
407
|
// screenshot still showed Overview), so re-click until the panel renders.
|
|
408
|
+
// Re-clicking the already selected tab does not refetch a failed secrets
|
|
409
|
+
// list, so use the error card's own Reload button for that case.
|
|
400
410
|
await (0, test_1.expect)(async () => {
|
|
401
|
-
await this.
|
|
411
|
+
await this.restoreClusterPageIfSignedOut(clusterUrl);
|
|
412
|
+
if (await this.secretsFetchErrorReloadButton.isVisible()) {
|
|
413
|
+
await this.secretsFetchErrorReloadButton.click({ timeout: 15000 });
|
|
414
|
+
}
|
|
415
|
+
else {
|
|
416
|
+
await this.clusterSecretTab.first().click({ timeout: 15000 });
|
|
417
|
+
}
|
|
402
418
|
await (0, test_1.expect)(this.createNewSecretButton).toBeVisible({ timeout: 10000 });
|
|
403
|
-
}).toPass({ timeout:
|
|
419
|
+
}).toPass({ timeout: 180000 });
|
|
420
|
+
}
|
|
421
|
+
// A reload is a full Hub navigation through Auth0 and /login-callback. When
|
|
422
|
+
// Hub's session hand-off fails it calls Auth0 logout, which parks the tab on
|
|
423
|
+
// the identity provider's login form (PR run 38354316061). Sign back in as
|
|
424
|
+
// the same user, then open the cluster with a fresh goto: the callback code
|
|
425
|
+
// is single use, so that URL cannot be reloaded.
|
|
426
|
+
async restoreClusterPageIfSignedOut(clusterUrl) {
|
|
427
|
+
if (!(0, sessionRecovery_1.isAtIdentityProvider)(this.page) ||
|
|
428
|
+
!(await (0, sessionRecovery_1.restoreSessionIfLoggedOut)(this.page))) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
await this.page.goto(clusterUrl, { waitUntil: 'domcontentloaded' });
|
|
432
|
+
await this.page.waitForURL((url) => url.host === new URL(clusterUrl).host &&
|
|
433
|
+
!/^\/login(-callback)?\/?$/.test(url.pathname), { timeout: 120000 });
|
|
404
434
|
}
|
|
405
435
|
}
|
|
406
436
|
exports.ClusterSecretsPage = ClusterSecretsPage;
|
|
@@ -10,7 +10,7 @@ const resetSession_1 = require("../../utils/resetSession");
|
|
|
10
10
|
const KeycloakUtils_1 = require("../../pages/SM-8.10/KeycloakUtils");
|
|
11
11
|
const constants_1 = require("../../utils/constants");
|
|
12
12
|
SM_8_10_1.test.describe.parallel('Smoke Tests', () => {
|
|
13
|
-
SM_8_10_1.test.beforeEach(async ({ navigationPage, managementIdentityPage, managementIdentityTenantPage, keycloakLoginPage, keycloakAdminPage, page, browser,
|
|
13
|
+
SM_8_10_1.test.beforeEach(async ({ navigationPage, managementIdentityPage, managementIdentityTenantPage, keycloakLoginPage, keycloakAdminPage, page, browser, ocIdentityHomePage, ocIdentityRolesPage, }, testInfo) => {
|
|
14
14
|
if (process.env.IS_MIGRATION === 'true') {
|
|
15
15
|
await navigationPage.goToOCAdmin((testInfo.workerIndex + 1) * 1000);
|
|
16
16
|
}
|
|
@@ -20,7 +20,14 @@ SM_8_10_1.test.describe.parallel('Smoke Tests', () => {
|
|
|
20
20
|
const { testUsername, testPassword } = await (0, KeycloakUtils_1.setupKeycloakUser)(navigationPage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, ocIdentityHomePage, ocIdentityRolesPage, process.env.IS_MT === 'true', managementIdentityTenantPage);
|
|
21
21
|
console.log(`BeforeEach end: timeout = ${testInfo.timeout}`);
|
|
22
22
|
await (0, resetSession_1.resetSession)(browser, page);
|
|
23
|
-
|
|
23
|
+
// Not loginPage.login() on the page resetSession leaves us on: where
|
|
24
|
+
// "/" serves Console it never redirects to Keycloak, so login()
|
|
25
|
+
// returned false unnoticed and later goTo() calls fell back to the
|
|
26
|
+
// first user (an org admin) instead of this test user.
|
|
27
|
+
await navigationPage.goToManagementIdentity(undefined, {
|
|
28
|
+
username: testUsername,
|
|
29
|
+
password: testPassword,
|
|
30
|
+
});
|
|
24
31
|
}
|
|
25
32
|
});
|
|
26
33
|
SM_8_10_1.test.afterEach(async ({ page }, testInfo) => {
|
|
@@ -64,7 +71,7 @@ SM_8_10_1.test.describe.parallel('Smoke Tests', () => {
|
|
|
64
71
|
}
|
|
65
72
|
console.log(`[${testInfo.title}] Test end: timeout = ${testInfo.timeout}`);
|
|
66
73
|
});
|
|
67
|
-
(0, SM_8_10_1.test)('Most Common Flow User Flow With All Apps', async ({ page, modelerHomePage, navigationPage, modelerCreatePage, operateHomePage, operateProcessesPage, operateProcessInstancePage, optimizeHomePage, optimizeCollectionsPage, optimizeReportPage, taskDetailsPage, taskPanelPage, }, testInfo) => {
|
|
74
|
+
(0, SM_8_10_1.test)('Most Common Flow User Flow With All Apps', async ({ page, browser, modelerHomePage, navigationPage, modelerCreatePage, operateHomePage, operateProcessesPage, operateProcessInstancePage, optimizeHomePage, optimizeCollectionsPage, optimizeReportPage, taskDetailsPage, taskPanelPage, }, testInfo) => {
|
|
68
75
|
console.log(`[${testInfo.title}] Test start: timeout = ${testInfo.timeout}`);
|
|
69
76
|
const randomName = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
70
77
|
const processName = 'Zeebe_User_Task_Process' + randomName;
|
|
@@ -72,6 +79,7 @@ SM_8_10_1.test.describe.parallel('Smoke Tests', () => {
|
|
|
72
79
|
await SM_8_10_1.test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
|
|
73
80
|
await navigationPage.goToModeler();
|
|
74
81
|
await modelerHomePage.createCrossComponentProjectFolder();
|
|
82
|
+
await modelerHomePage.assignWorkspaceEnvironmentAsOrgAdmin(browser);
|
|
75
83
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
76
84
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
77
85
|
});
|