@camunda/e2e-test-suite 0.0.1053 → 0.0.1055
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.
|
@@ -79,7 +79,8 @@ declare class ClusterDetailsPage {
|
|
|
79
79
|
clickCreateAlertButton(): Promise<void>;
|
|
80
80
|
deleteAlerts(): Promise<void>;
|
|
81
81
|
private doDelete;
|
|
82
|
-
assertComponentsHealth(components?: string[]): Promise<void>;
|
|
82
|
+
assertComponentsHealth(components?: string[], recoverSession?: () => Promise<void>): Promise<void>;
|
|
83
|
+
private isSessionLost;
|
|
83
84
|
createAPIClientAndReturnVariables(name: string, setEnvVariables?: boolean, clusterType?: string): Promise<{
|
|
84
85
|
[key: string]: string;
|
|
85
86
|
}>;
|
|
@@ -455,24 +455,48 @@ class ClusterDetailsPage {
|
|
|
455
455
|
console.error(`Error during ${text} deletion: `, error);
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
|
+
// This poll reloads the cluster-details page for minutes on end, which is a
|
|
459
|
+
// prime window for the Console SPA to drop its own session: auth0-spa-js
|
|
460
|
+
// calls `/v2/logout` when a silent token renewal fails, and the tab then
|
|
461
|
+
// lands on the identity provider's login form. From that point on every
|
|
462
|
+
// reload only re-renders that form, so the component status can never
|
|
463
|
+
// appear again and all 7 attempts are spent on a login page.
|
|
464
|
+
// `recoverSession` is supplied by the caller (which knows the credentials);
|
|
465
|
+
// it re-authenticates and returns the tab to this cluster's details page so
|
|
466
|
+
// the health assertion itself is retried unchanged.
|
|
458
467
|
async assertComponentsHealth(components = [
|
|
459
468
|
'Zeebe',
|
|
460
469
|
'Tasklist',
|
|
461
470
|
'Operate',
|
|
462
471
|
'Optimize',
|
|
463
472
|
'Admin',
|
|
464
|
-
]) {
|
|
473
|
+
], recoverSession) {
|
|
465
474
|
for (const component of components) {
|
|
466
475
|
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.page.getByText(`${component}Healthy`, { exact: true }), {
|
|
467
476
|
visibilityTimeout: 60000,
|
|
468
477
|
totalTimeout: 400000,
|
|
469
478
|
maxRetries: 7,
|
|
470
479
|
preAction: async () => {
|
|
480
|
+
if (recoverSession && this.isSessionLost()) {
|
|
481
|
+
await recoverSession();
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
471
484
|
await this.page.reload();
|
|
472
485
|
},
|
|
473
486
|
});
|
|
474
487
|
}
|
|
475
488
|
}
|
|
489
|
+
// True when the tab has been bounced to the identity provider
|
|
490
|
+
// (`weblogin.` / `login.` / `auth.` hosts), i.e. the Console session is
|
|
491
|
+
// gone and no amount of reloading will bring the cluster page back.
|
|
492
|
+
isSessionLost() {
|
|
493
|
+
try {
|
|
494
|
+
return /^(weblogin|login|auth)\./.test(new URL(this.page.url()).host);
|
|
495
|
+
}
|
|
496
|
+
catch {
|
|
497
|
+
return false;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
476
500
|
async createAPIClientAndReturnVariables(name, setEnvVariables = true, clusterType) {
|
|
477
501
|
await this.createAPIClient(name);
|
|
478
502
|
await this.clickEnvVarsButton();
|
|
@@ -38,6 +38,7 @@ export declare function runMultipleProcesses(clusterName: string, page: Page, mo
|
|
|
38
38
|
processName?: string;
|
|
39
39
|
uploadFromFile?: string;
|
|
40
40
|
}): Promise<void>;
|
|
41
|
+
export declare function goBackWithRetry(page: Page, maxRetries?: number): Promise<void>;
|
|
41
42
|
export declare function disableRBA(clusterName: string, homePage: HomePage, clusterPage: ClusterPage, clusterDetailsPage: ClusterDetailsPage, appsPage: AppsPage): Promise<void>;
|
|
42
43
|
export declare function enableAuthorizations(clusterName: string, homePage: HomePage, clusterPage: ClusterPage, clusterDetailsPage: ClusterDetailsPage, appsPage: AppsPage): Promise<void>;
|
|
43
44
|
export declare function clickInvitationLinkInEmail(page: Page, id: string): Promise<void>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.waitForLoadingToFinish = exports.assertTestUsesCorrectOrganizationFromModeler = exports.expectCountToBeOneOf = exports.createAPIClient = exports.modelAndRunConnectorsTimerEventDiagram = exports.modelAndRunConnectorsDocHandlingDiagram = exports.deleteCluster = exports.deleteAllUserGroups = exports.assertTestUsesCorrectOrganization = exports.assertLatestAlertEmail = exports.clickInvitationLinkInEmail = exports.enableAuthorizations = exports.disableRBA = exports.runMultipleProcesses = exports.runProcess = exports.completeTaskWithRetry = exports.assertPageTextWithRetry = exports.openAppTabWithRetry = exports.assertLocatorVisibleWithRetry = exports.modelRestConnector = exports.modelDiagramFromFile = exports.withSessionRecovery = exports.isSignedOut = exports.loginWithRetry = void 0;
|
|
3
|
+
exports.waitForLoadingToFinish = exports.assertTestUsesCorrectOrganizationFromModeler = exports.expectCountToBeOneOf = exports.createAPIClient = exports.modelAndRunConnectorsTimerEventDiagram = exports.modelAndRunConnectorsDocHandlingDiagram = exports.deleteCluster = exports.deleteAllUserGroups = exports.assertTestUsesCorrectOrganization = exports.assertLatestAlertEmail = exports.clickInvitationLinkInEmail = exports.enableAuthorizations = exports.disableRBA = exports.goBackWithRetry = exports.runMultipleProcesses = exports.runProcess = exports.completeTaskWithRetry = exports.assertPageTextWithRetry = exports.openAppTabWithRetry = exports.assertLocatorVisibleWithRetry = exports.modelRestConnector = exports.modelDiagramFromFile = exports.withSessionRecovery = exports.isSignedOut = exports.loginWithRetry = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const ModelerHomePage_1 = require("./ModelerHomePage");
|
|
6
6
|
const HomePage_1 = require("./HomePage");
|
|
7
7
|
const sleep_1 = require("../../utils/sleep");
|
|
8
8
|
const randomSleep_1 = require("../../utils/randomSleep");
|
|
9
|
+
const LoginPage_1 = require("./LoginPage");
|
|
9
10
|
const fileUpload_1 = require("../../utils/fileUpload");
|
|
10
11
|
const mailSlurpClient_1 = require("../../utils/mailSlurpClient");
|
|
11
12
|
async function clearWebStorage(page) {
|
|
@@ -529,6 +530,59 @@ async function runMultipleProcesses(clusterName, page, modelerHomePage, modelerC
|
|
|
529
530
|
}
|
|
530
531
|
}
|
|
531
532
|
exports.runMultipleProcesses = runMultipleProcesses;
|
|
533
|
+
// The Console SPA drops its own session when auth0-spa-js fails a silent
|
|
534
|
+
// token renewal: it calls `/v2/logout` and the tab is bounced to the identity
|
|
535
|
+
// provider's login form. That happens mid-flight during the minutes-long
|
|
536
|
+
// component-health poll below, after which reloading only ever re-renders the
|
|
537
|
+
// login form. Re-authenticate as the console user and return to the page that
|
|
538
|
+
// was being polled, so the health assertion carries on unchanged.
|
|
539
|
+
function consoleSessionRecovery(page, clusterUrl) {
|
|
540
|
+
return async () => {
|
|
541
|
+
console.warn(`Console session lost while polling component health on ${clusterUrl}; re-authenticating.`);
|
|
542
|
+
await loginWithRetry(page, new LoginPage_1.LoginPage(page), {
|
|
543
|
+
username: process.env.C8_USERNAME,
|
|
544
|
+
password: process.env.C8_PASSWORD,
|
|
545
|
+
}, 0, 3);
|
|
546
|
+
await page.goto(clusterUrl, {
|
|
547
|
+
waitUntil: 'domcontentloaded',
|
|
548
|
+
timeout: 60000,
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
// `page.goBack()` rejects with `net::ERR_ABORTED` when the page it returns to
|
|
553
|
+
// immediately issues a navigation of its own (Console re-runs its auth
|
|
554
|
+
// redirect on entry): the history entry is superseded, not failed, and the
|
|
555
|
+
// browser still ends up on a usable shell -- sometimes after briefly leaving
|
|
556
|
+
// the tab blank. Judge the outcome by what actually rendered rather than by
|
|
557
|
+
// the rejection, and re-request Console directly if no app shell came back.
|
|
558
|
+
async function goBackWithRetry(page, maxRetries = 3) {
|
|
559
|
+
const homePage = new HomePage_1.HomePage(page);
|
|
560
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
561
|
+
try {
|
|
562
|
+
await page.goBack({ waitUntil: 'domcontentloaded', timeout: 60000 });
|
|
563
|
+
}
|
|
564
|
+
catch (error) {
|
|
565
|
+
console.warn(`goBack attempt ${attempt} failed: ${error}`);
|
|
566
|
+
}
|
|
567
|
+
await page
|
|
568
|
+
.waitForLoadState('domcontentloaded', { timeout: 60000 })
|
|
569
|
+
.catch(() => { });
|
|
570
|
+
if (await homePage.camundaComponentsButton
|
|
571
|
+
.first()
|
|
572
|
+
.isVisible({ timeout: 15000 })
|
|
573
|
+
.catch(() => false)) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
await (0, sleep_1.sleep)(2000);
|
|
577
|
+
}
|
|
578
|
+
await page
|
|
579
|
+
.goto('/', { waitUntil: 'domcontentloaded', timeout: 60000 })
|
|
580
|
+
.catch(() => { });
|
|
581
|
+
await (0, test_1.expect)(homePage.camundaComponentsButton.first()).toBeVisible({
|
|
582
|
+
timeout: 60000,
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
exports.goBackWithRetry = goBackWithRetry;
|
|
532
586
|
async function disableRBA(clusterName, homePage, clusterPage, clusterDetailsPage, appsPage) {
|
|
533
587
|
await appsPage.clickCamundaApps();
|
|
534
588
|
await appsPage.clickConsoleLink();
|
|
@@ -546,7 +600,8 @@ async function disableRBA(clusterName, homePage, clusterPage, clusterDetailsPage
|
|
|
546
600
|
await (0, test_1.expect)(clusterDetailsPage.rbaEnabledMessage.first()).not.toBeVisible({
|
|
547
601
|
timeout: 30000,
|
|
548
602
|
});
|
|
549
|
-
|
|
603
|
+
const detailsPage = clusterDetailsPage.settingsTab.page();
|
|
604
|
+
await clusterDetailsPage.assertComponentsHealth(undefined, consoleSessionRecovery(detailsPage, detailsPage.url()));
|
|
550
605
|
}
|
|
551
606
|
exports.disableRBA = disableRBA;
|
|
552
607
|
async function enableAuthorizations(clusterName, homePage, clusterPage, clusterDetailsPage, appsPage) {
|
|
@@ -577,7 +632,7 @@ async function enableAuthorizations(clusterName, homePage, clusterPage, clusterD
|
|
|
577
632
|
await homePage.clickClusters();
|
|
578
633
|
await clusterPage.assertClusterHealthyStatusWithRetry(clusterName, 120000, 600000);
|
|
579
634
|
await clusterPage.clickClusterLink(clusterName);
|
|
580
|
-
await clusterDetailsPage.assertComponentsHealth();
|
|
635
|
+
await clusterDetailsPage.assertComponentsHealth(undefined, consoleSessionRecovery(cdPage, cdPage.url()));
|
|
581
636
|
}
|
|
582
637
|
exports.enableAuthorizations = enableAuthorizations;
|
|
583
638
|
async function clickInvitationLinkInEmail(page, id) {
|
|
@@ -268,7 +268,7 @@ _8_10_1.test.describe('User Roles User Flow', () => {
|
|
|
268
268
|
});
|
|
269
269
|
});
|
|
270
270
|
await _8_10_1.test.step('Navigate to Tasklist and Ensure Tasklist is Accessible', async () => {
|
|
271
|
-
await
|
|
271
|
+
await (0, UtilitiesPage_1.goBackWithRetry)(page);
|
|
272
272
|
await appsPage.clickCamundaApps();
|
|
273
273
|
await appsPage.clickTasklist(clusterName);
|
|
274
274
|
await (0, test_1.expect)(taskPanelPage.taskListPageBanner).toBeVisible({
|
|
@@ -276,7 +276,7 @@ _8_10_1.test.describe('User Roles User Flow', () => {
|
|
|
276
276
|
});
|
|
277
277
|
});
|
|
278
278
|
await _8_10_1.test.step('Navigate to Identity and Ensure Identity is Accessible', async () => {
|
|
279
|
-
await
|
|
279
|
+
await (0, UtilitiesPage_1.goBackWithRetry)(page);
|
|
280
280
|
await appsPage.clickCamundaApps();
|
|
281
281
|
await appsPage.clickAdmin(clusterName);
|
|
282
282
|
await (0, test_1.expect)(ocIdentityHomePage.adminBanner).toBeVisible({
|
|
@@ -287,7 +287,7 @@ _8_10_1.test.describe('User Roles User Flow', () => {
|
|
|
287
287
|
});
|
|
288
288
|
});
|
|
289
289
|
await _8_10_1.test.step('Navigate to Optimize and Ensure Optimize is Accessible', async () => {
|
|
290
|
-
await
|
|
290
|
+
await (0, UtilitiesPage_1.goBackWithRetry)(page);
|
|
291
291
|
await appsPage.clickCamundaApps();
|
|
292
292
|
await appsPage.clickOptimize(clusterName);
|
|
293
293
|
await (0, test_1.expect)(optimizeHomePage.optimizeBanner).toBeVisible({
|