@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
- await clusterDetailsPage.assertComponentsHealth();
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 page.goBack();
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 page.goBack();
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 page.goBack();
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({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1053",
3
+ "version": "0.0.1055",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",