@camunda/e2e-test-suite 0.0.1168 → 0.0.1169
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.
|
@@ -217,7 +217,7 @@ declare class ModelerCreatePage {
|
|
|
217
217
|
clickJobTypeInput(): Promise<void>;
|
|
218
218
|
fillJobTypeInput(name: string): Promise<void>;
|
|
219
219
|
private suppressTestModeAnnouncement;
|
|
220
|
-
switchToPlay(): Promise<void>;
|
|
220
|
+
switchToPlay(afterNavigation?: boolean): Promise<void>;
|
|
221
221
|
completePlayConfiguration(clusterName: string): Promise<void>;
|
|
222
222
|
embedForm(formName: string): Promise<void>;
|
|
223
223
|
openDetailsPanelIfCollapsed(): Promise<void>;
|
|
@@ -1420,7 +1420,11 @@ class ModelerCreatePage {
|
|
|
1420
1420
|
localStorage.setItem('play-testAnnouncementSeen', 'true');
|
|
1421
1421
|
});
|
|
1422
1422
|
}
|
|
1423
|
-
|
|
1423
|
+
// `afterNavigation` marks the call sites that land here straight off a
|
|
1424
|
+
// page load (ensureStageCluster's goto() detour, the legacy retry's
|
|
1425
|
+
// reload()) rather than off an already-rendered diagram. Only those recover
|
|
1426
|
+
// by reloading -- see below.
|
|
1427
|
+
async switchToPlay(afterNavigation = false) {
|
|
1424
1428
|
await this.suppressTestModeAnnouncement();
|
|
1425
1429
|
// completePlayConfiguration re-enters Play after ensureStageCluster's
|
|
1426
1430
|
// goto() detour, and the diagram page keeps rendering well past the point
|
|
@@ -1428,7 +1432,34 @@ class ModelerCreatePage {
|
|
|
1428
1432
|
// 10s after it returned, so the click burned the whole global
|
|
1429
1433
|
// actionTimeout on a page that was merely still booting. Wait for the tab
|
|
1430
1434
|
// on its own, longer budget first, then click within the normal one.
|
|
1431
|
-
|
|
1435
|
+
//
|
|
1436
|
+
// Waiting longer is not enough on its own for the post-navigation call,
|
|
1437
|
+
// because the tabs' absence there is not always transient. Hub renders the
|
|
1438
|
+
// modes tablist only when `isCurrentDiagramValid && isBPMN &&
|
|
1439
|
+
// allowedViewModes.length > 0`, and `currentDiagramStore.isValid` stays
|
|
1440
|
+
// false until the diagram content has been fetched AND sanitised
|
|
1441
|
+
// (`healthState.isValid && hasBeenValidated`). A diagram fetch that fails
|
|
1442
|
+
// on that fresh load therefore renders an action bar with no mode tabs at
|
|
1443
|
+
// all, permanently -- so the single-shot 90s wait could only ever expire on
|
|
1444
|
+
// it. Re-navigate between attempts instead: the reload re-runs the fetch
|
|
1445
|
+
// that did not land. Gated on `afterNavigation` so the in-place call from
|
|
1446
|
+
// the spec, made on a diagram whose tabs have been on screen throughout
|
|
1447
|
+
// modelling, can never reload mid-edit.
|
|
1448
|
+
if (afterNavigation) {
|
|
1449
|
+
await (0, test_1.expect)(async () => {
|
|
1450
|
+
const visible = await this.playTab
|
|
1451
|
+
.waitFor({ state: 'visible', timeout: 45000 })
|
|
1452
|
+
.then(() => true)
|
|
1453
|
+
.catch(() => false);
|
|
1454
|
+
if (!visible) {
|
|
1455
|
+
await this.page.reload({ waitUntil: 'domcontentloaded' });
|
|
1456
|
+
await this.playTab.waitFor({ state: 'visible', timeout: 45000 });
|
|
1457
|
+
}
|
|
1458
|
+
}).toPass({ timeout: 150000 });
|
|
1459
|
+
}
|
|
1460
|
+
else {
|
|
1461
|
+
await this.playTab.waitFor({ state: 'visible', timeout: 90000 });
|
|
1462
|
+
}
|
|
1432
1463
|
await this.playTab.click();
|
|
1433
1464
|
}
|
|
1434
1465
|
async completePlayConfiguration(clusterName) {
|
|
@@ -1440,7 +1471,7 @@ class ModelerCreatePage {
|
|
|
1440
1471
|
// which cluster the test plays on.
|
|
1441
1472
|
const reboundStageCluster = await this.processApplicationPage.ensureStageCluster(clusterName);
|
|
1442
1473
|
if (reboundStageCluster) {
|
|
1443
|
-
await this.switchToPlay();
|
|
1474
|
+
await this.switchToPlay(true);
|
|
1444
1475
|
}
|
|
1445
1476
|
const timeout = 30000;
|
|
1446
1477
|
// New flow (8.10+): "Setup environment" panel with three steps:
|
|
@@ -1458,17 +1489,32 @@ class ModelerCreatePage {
|
|
|
1458
1489
|
// data-testid is unchanged between the old overlay and the new panel, so
|
|
1459
1490
|
// anchor on it instead.
|
|
1460
1491
|
const setupDeployButton = this.page.getByTestId('test-configuration-deploy-button');
|
|
1461
|
-
//
|
|
1462
|
-
//
|
|
1463
|
-
//
|
|
1492
|
+
// "Deploy reported success" has moved twice. 8b42269 dropped the
|
|
1493
|
+
// "Process has been successfully deployed." sentence in favour of a
|
|
1494
|
+
// `deploy-success-badge` element, and camunda-hub d2fd90227c ("remove
|
|
1495
|
+
// non-process-application deploy logic from test studio", #28585,
|
|
1496
|
+
// 2026-09-11) then deleted that badge outright along with the rest of the
|
|
1497
|
+
// non-process-application deploy path -- so neither locator matches
|
|
1498
|
+
// anything on a current modeler build and this wait could only ever time
|
|
1499
|
+
// out, even though the deploy itself succeeds.
|
|
1500
|
+
//
|
|
1501
|
+
// The surviving indicator is the accordion step icon: DeployStepIcon
|
|
1502
|
+
// renders a check carrying `aria-label="Deployment complete"` exactly when
|
|
1503
|
+
// `isDeployStepComplete` is true, which is the same `isTestEnvironmentReady`
|
|
1504
|
+
// flag that opens step 3. Match it by attribute rather than getByLabel:
|
|
1505
|
+
// TestConfigurationPanel wraps the icon in an `aria-hidden` span, so it is
|
|
1506
|
+
// deliberately outside the accessibility tree. The sibling error state has
|
|
1507
|
+
// its own label ("Deployment failed"), so a failed deploy still surfaces as
|
|
1508
|
+
// a timeout here instead of passing. Keep both older locators for
|
|
1509
|
+
// pre-d2fd902 modeler builds.
|
|
1464
1510
|
//
|
|
1465
|
-
// Probed by ATTACHMENT, never visibility: the
|
|
1466
|
-
//
|
|
1467
|
-
//
|
|
1468
|
-
//
|
|
1469
|
-
// frame of appearing, and a toBeVisible() wait on it can never pass.
|
|
1511
|
+
// Probed by ATTACHMENT, never visibility: the panel reacts to the same
|
|
1512
|
+
// completion state by hiding the setup overlay and collapsing the deploy
|
|
1513
|
+
// accordion item, so the indicator can be present-but-hidden within a frame
|
|
1514
|
+
// of appearing and a toBeVisible() wait on it can never pass.
|
|
1470
1515
|
const deploySuccessBadge = this.page
|
|
1471
|
-
.
|
|
1516
|
+
.locator('[aria-label="Deployment complete"]')
|
|
1517
|
+
.or(this.page.getByTestId('deploy-success-badge'))
|
|
1472
1518
|
.or(this.page.getByText('Process has been successfully deployed'))
|
|
1473
1519
|
.first();
|
|
1474
1520
|
const isDeployReported = async () => (await deploySuccessBadge.count()) > 0;
|
|
@@ -1669,8 +1715,10 @@ class ModelerCreatePage {
|
|
|
1669
1715
|
const maxRetries = 2;
|
|
1670
1716
|
while (attempts < maxRetries) {
|
|
1671
1717
|
try {
|
|
1718
|
+
// Call switchToPlay on subsequent attempts, i.e. after the reload at
|
|
1719
|
+
// the bottom of this loop.
|
|
1672
1720
|
if (attempts > 0)
|
|
1673
|
-
await this.switchToPlay();
|
|
1721
|
+
await this.switchToPlay(true);
|
|
1674
1722
|
await this.selectCluster(clusterName);
|
|
1675
1723
|
await this.continueToPlayButton.click({ timeout });
|
|
1676
1724
|
await (0, test_1.expect)(this.page.getByText('Play environment is ready')).toBeVisible({ timeout: 90000 });
|
|
@@ -225,10 +225,9 @@ class ProcessApplicationPage {
|
|
|
225
225
|
}
|
|
226
226
|
const returnTo = this.page.url();
|
|
227
227
|
const paUrl = container.url.replace(/[?#].*$/, '').replace(/\/$/, '');
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
await this.openStageDefinition();
|
|
228
|
+
const deepLink = `${paUrl}/connected-clusters`;
|
|
229
|
+
await this.page.goto(deepLink, { waitUntil: 'domcontentloaded' });
|
|
230
|
+
await this.openStageDefinition(deepLink);
|
|
232
231
|
await this.defineDevelopmentStage(clusterName);
|
|
233
232
|
container.developmentCluster = clusterName;
|
|
234
233
|
await this.page.goto(returnTo, { waitUntil: 'domcontentloaded' });
|
|
@@ -240,7 +239,7 @@ class ProcessApplicationPage {
|
|
|
240
239
|
// the affordances hub offers before failing with exactly what was looked for.
|
|
241
240
|
// Worth the noise: an unbound cluster otherwise surfaces as a deploy dialog
|
|
242
241
|
// that silently offers nothing, which says nothing about its own cause.
|
|
243
|
-
async openStageDefinition() {
|
|
242
|
+
async openStageDefinition(deepLink) {
|
|
244
243
|
// Page-scoped .first(): hub renders one such control on this page, and a
|
|
245
244
|
// second placement must not turn every rebinding test into a strict-mode
|
|
246
245
|
// violation.
|
|
@@ -254,7 +253,30 @@ class ProcessApplicationPage {
|
|
|
254
253
|
// dialog it was meant to open is already on screen. Re-probing for the
|
|
255
254
|
// dialog at the top of every attempt settles that: whichever route got it
|
|
256
255
|
// there, the next pass sees it and returns.
|
|
256
|
+
//
|
|
257
|
+
// Re-navigating between attempts is what makes that retry able to recover
|
|
258
|
+
// at all. Hub renders the "Configure" control and MOUNTS DefineStagesModal
|
|
259
|
+
// in the same component -- ConnectedClusters, inside the process
|
|
260
|
+
// application's right column -- and gates it on `isAdmin || isEditor`,
|
|
261
|
+
// i.e. on projectStore having loaded. processApplicationStore.init()
|
|
262
|
+
// swallows a failed fetch (it only toasts "Yikes! Couldn't retrieve your
|
|
263
|
+
// project" and clears its loading flag), so one transient 5xx on the
|
|
264
|
+
// freshly created application leaves a fully rendered page that has no
|
|
265
|
+
// card: no control to click, and the deep link's own auto-open never fires
|
|
266
|
+
// either, because useConnectedClustersDeepLink only calls open() when that
|
|
267
|
+
// same `canSee` is true. Re-probing and re-clicking cannot bring back a
|
|
268
|
+
// component that was never mounted -- only a reload, which re-runs the
|
|
269
|
+
// store init, can. Without it every attempt burned its two waits on
|
|
270
|
+
// elements that could not appear and the whole budget expired on a page
|
|
271
|
+
// that one navigation would have fixed.
|
|
272
|
+
let attempt = 0;
|
|
257
273
|
await (0, test_1.expect)(async () => {
|
|
274
|
+
if (attempt++ > 0) {
|
|
275
|
+
await this.page.goto(deepLink, { waitUntil: 'domcontentloaded' });
|
|
276
|
+
// Proof the process application page itself came back, so a failure
|
|
277
|
+
// here still names the missing dialog rather than a blank page.
|
|
278
|
+
await this.waitForProcessApplication(60000);
|
|
279
|
+
}
|
|
258
280
|
const opened = await this.defineStagesDialog
|
|
259
281
|
.waitFor({ state: 'visible', timeout: 15000 })
|
|
260
282
|
.then(() => true)
|
|
@@ -265,7 +287,7 @@ class ProcessApplicationPage {
|
|
|
265
287
|
await reopen.waitFor({ state: 'visible', timeout: 10000 });
|
|
266
288
|
await reopen.click({ timeout: 15000 });
|
|
267
289
|
await (0, test_1.expect)(this.defineStagesDialog).toBeVisible({ timeout: 15000 });
|
|
268
|
-
}).toPass({ timeout:
|
|
290
|
+
}).toPass({ timeout: 180000 });
|
|
269
291
|
}
|
|
270
292
|
async openByName(name) {
|
|
271
293
|
const processApplication = this.page
|