@camunda/e2e-test-suite 0.0.1122 → 0.0.1124
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.
|
@@ -1364,6 +1364,37 @@ class ModelerCreatePage {
|
|
|
1364
1364
|
const isDeployComplete = async () => (await deployCompleteIcon.isVisible().catch(() => false)) ||
|
|
1365
1365
|
(await deploySuccessBadge.isVisible().catch(() => false)) ||
|
|
1366
1366
|
(await configureTestPanel.isVisible().catch(() => false));
|
|
1367
|
+
// A deploy that FAILED looks, to the probe above, exactly like a deploy
|
|
1368
|
+
// that has not been triggered yet. DeployStepContent renders a
|
|
1369
|
+
// "Deployment failed" badge (or "Missing permissions to deploy" for a
|
|
1370
|
+
// 403) and relabels the very same `test-configuration-deploy-button` to
|
|
1371
|
+
// "Retry" -- still visible, still enabled -- so the loop below happily
|
|
1372
|
+
// re-clicks an action the backend is rejecting and finally reports
|
|
1373
|
+
// `Expected: true Received: false`, which names neither the failure nor
|
|
1374
|
+
// its cause. Read the panel's own verdict instead and put it in the
|
|
1375
|
+
// assertion message, and expand the "Show details" disclosure so the
|
|
1376
|
+
// server message lands in the afterEach screenshot and the trace.
|
|
1377
|
+
const deployErrorBadge = this.page
|
|
1378
|
+
.getByText('Deployment failed', { exact: true })
|
|
1379
|
+
.or(this.page.getByText('Missing permissions to deploy'))
|
|
1380
|
+
.first();
|
|
1381
|
+
const deployErrorDetailsToggle = this.page.locator('[data-test="test-studio-configuration-toggle-details"]');
|
|
1382
|
+
const readDeployError = async () => {
|
|
1383
|
+
const failed = await deployErrorBadge.isVisible().catch(() => false);
|
|
1384
|
+
if (!failed) {
|
|
1385
|
+
return undefined;
|
|
1386
|
+
}
|
|
1387
|
+
const hasDetails = await deployErrorDetailsToggle
|
|
1388
|
+
.isVisible()
|
|
1389
|
+
.catch(() => false);
|
|
1390
|
+
const isExpanded = hasDetails &&
|
|
1391
|
+
(await deployErrorDetailsToggle.getAttribute('aria-expanded')) ===
|
|
1392
|
+
'true';
|
|
1393
|
+
if (hasDetails && !isExpanded) {
|
|
1394
|
+
await deployErrorDetailsToggle.click({ timeout: 5000 });
|
|
1395
|
+
}
|
|
1396
|
+
return deployErrorBadge.innerText();
|
|
1397
|
+
};
|
|
1367
1398
|
if (!(await isDeployComplete())) {
|
|
1368
1399
|
// The Deploy button lives inside the "Deploy process" accordion item,
|
|
1369
1400
|
// which expands itself once the cluster step completes. Nudge the
|
|
@@ -1389,19 +1420,50 @@ class ModelerCreatePage {
|
|
|
1389
1420
|
// ("element is not visible", 58 retries, in the click call log). A
|
|
1390
1421
|
// re-click can only happen while the deploy is provably still
|
|
1391
1422
|
// incomplete AND the button is enabled -- a deploy in flight disables
|
|
1392
|
-
// it
|
|
1393
|
-
//
|
|
1423
|
+
// it (or replaces it with the "Deploying..." loader), so this cannot
|
|
1424
|
+
// pile up requests. If the deploy never completes the loop still
|
|
1425
|
+
// fails, now naming the panel's own error when there is one.
|
|
1426
|
+
//
|
|
1427
|
+
// The budget is 4 minutes, not the 2 it used to be: a process
|
|
1428
|
+
// application deploy on SaaS serialises deployProcessApplication(),
|
|
1429
|
+
// fetchLinkedStartForm() and the connector-secret fetch before
|
|
1430
|
+
// TestConfigurationPanel reports the step complete, and the previous
|
|
1431
|
+
// budget expired while that chain was still in flight. The test is
|
|
1432
|
+
// test.slow() (36 min), so the extra headroom is affordable.
|
|
1433
|
+
//
|
|
1434
|
+
// One stall shape is invisible to the re-click above: while the deploy
|
|
1435
|
+
// request is in flight the panel keeps `status === 'deploying-files'`,
|
|
1436
|
+
// which renders the button `disabled` (camunda-hub test-studio
|
|
1437
|
+
// DeployStepContent), so a request that never settles leaves the loop
|
|
1438
|
+
// with nothing clickable and no error badge to report -- it just polls
|
|
1439
|
+
// until the budget expires and reports the bare "never reported
|
|
1440
|
+
// completion". Remount the panel once when that happens: on a fresh
|
|
1441
|
+
// Play mount useSetupEnvironmentStep re-runs
|
|
1442
|
+
// testEnvironmentStore.checkExistingDeployment(), which marks the step
|
|
1443
|
+
// complete when the deployment actually landed, and otherwise leaves an
|
|
1444
|
+
// enabled Deploy button for this loop to click -- i.e. a real retry
|
|
1445
|
+
// either way, not a masked failure.
|
|
1446
|
+
let hasRemountedAfterStall = false;
|
|
1447
|
+
const stallDeadline = Date.now() + 120000;
|
|
1394
1448
|
await (0, test_1.expect)(async () => {
|
|
1395
1449
|
if (await isDeployComplete()) {
|
|
1396
1450
|
return;
|
|
1397
1451
|
}
|
|
1452
|
+
const deployError = await readDeployError();
|
|
1398
1453
|
const canClick = (await setupDeployButton.isVisible().catch(() => false)) &&
|
|
1399
1454
|
(await setupDeployButton.isEnabled().catch(() => false));
|
|
1400
1455
|
if (canClick) {
|
|
1401
1456
|
await setupDeployButton.click({ timeout });
|
|
1402
1457
|
}
|
|
1403
|
-
(
|
|
1404
|
-
|
|
1458
|
+
else if (!hasRemountedAfterStall && Date.now() > stallDeadline) {
|
|
1459
|
+
hasRemountedAfterStall = true;
|
|
1460
|
+
await this.page.reload();
|
|
1461
|
+
await this.switchToPlay();
|
|
1462
|
+
}
|
|
1463
|
+
(0, test_1.expect)(await isDeployComplete(), deployError === undefined
|
|
1464
|
+
? 'Play "Deploy process" step never reported completion'
|
|
1465
|
+
: `Play "Deploy process" step reported: ${deployError}`).toBe(true);
|
|
1466
|
+
}).toPass({ timeout: 300000, intervals: [1000, 2000, 5000] });
|
|
1405
1467
|
}
|
|
1406
1468
|
// Step 3: the configure-test-case step opens on its own once the deploy
|
|
1407
1469
|
// step completes (TestConfigurationPanel hides the setup overlay in an
|
|
@@ -59,6 +59,7 @@ declare class ModelerHomePage {
|
|
|
59
59
|
returnToResourceContainer(): Promise<void>;
|
|
60
60
|
startBlankBpmnDiagram(): Promise<void>;
|
|
61
61
|
private becameVisible;
|
|
62
|
+
isModelerPageBannerVisible(timeout: number): Promise<boolean>;
|
|
62
63
|
clickHomeBreadcrumb(): Promise<void>;
|
|
63
64
|
clickOpenOrganizationsButton(): Promise<void>;
|
|
64
65
|
clickCrossComponentProjectFolder(): Promise<void>;
|
|
@@ -426,6 +426,11 @@ class ModelerHomePage {
|
|
|
426
426
|
.then(() => true)
|
|
427
427
|
.catch(() => false);
|
|
428
428
|
}
|
|
429
|
+
// Boolean form of the modeler-banner assertion, so a caller can re-open
|
|
430
|
+
// Modeler instead of failing outright when the app shell never mounts.
|
|
431
|
+
async isModelerPageBannerVisible(timeout) {
|
|
432
|
+
return this.becameVisible(this.modelerPageBanner, timeout);
|
|
433
|
+
}
|
|
429
434
|
async clickHomeBreadcrumb() {
|
|
430
435
|
try {
|
|
431
436
|
await this.homeBreadcrumb.click();
|
|
@@ -48,7 +48,20 @@ class PlayPage {
|
|
|
48
48
|
});
|
|
49
49
|
}
|
|
50
50
|
async clickCompleteJobButton() {
|
|
51
|
-
|
|
51
|
+
// The complete-job action is a bpmn-js canvas overlay pinned to the active
|
|
52
|
+
// element, so it is re-laid-out (and briefly detached) whenever the diagram
|
|
53
|
+
// re-renders -- which it does on every job/instance update arriving from
|
|
54
|
+
// the cluster. A bare click that lands in that window silently resolves
|
|
55
|
+
// against a stale node, the job is never completed, and the failure only
|
|
56
|
+
// surfaces two calls later as "waitForNextElementToBeActive" timing out on
|
|
57
|
+
// the next element that consequently never became active. Retry the click
|
|
58
|
+
// against a fresh visibility + clickability check instead.
|
|
59
|
+
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.completeJobButton, {
|
|
60
|
+
totalTimeout: 120000,
|
|
61
|
+
visibilityTimeout: 30000,
|
|
62
|
+
maxRetries: 3,
|
|
63
|
+
retryDelayMs: 3000,
|
|
64
|
+
});
|
|
52
65
|
}
|
|
53
66
|
async clickStartInstanceButton() {
|
|
54
67
|
// The Modeler Play UI has two surfaces that can hold the start trigger:
|
|
@@ -133,8 +146,36 @@ class PlayPage {
|
|
|
133
146
|
});
|
|
134
147
|
}
|
|
135
148
|
async waitForProcessToBeCompleted() {
|
|
136
|
-
|
|
149
|
+
// "Completed" is the bpmn-js overlay Modeler pins to the end event once the
|
|
150
|
+
// instance reaches COMPLETED (camunda-hub test-studio DiagramOverlay ->
|
|
151
|
+
// CompletedOverlay), so it can only render after the LAST job has actually
|
|
152
|
+
// been completed. That makes this the only place where a silently
|
|
153
|
+
// ineffective final complete-job click can surface: the two earlier tasks
|
|
154
|
+
// are each followed by waitForNextElementToBeActive, which catches a lost
|
|
155
|
+
// click, but nothing follows the third one -- so a click that resolved
|
|
156
|
+
// against a re-laid-out (briefly detached) overlay leaves the service-task
|
|
157
|
+
// job pending and the sole symptom is this locator timing out with
|
|
158
|
+
// "element(s) not found", exactly the nightly failure.
|
|
159
|
+
//
|
|
160
|
+
// While the overlay is absent AND a complete-job overlay button is still on
|
|
161
|
+
// the canvas, the job demonstrably was not completed, so re-issue it rather
|
|
162
|
+
// than waiting out the whole budget on a job nothing will complete. The
|
|
163
|
+
// assertion itself is unchanged: the step still only passes on a visible
|
|
164
|
+
// "Completed" overlay.
|
|
165
|
+
const completedOverlay = this.page.getByText('Completed').first();
|
|
166
|
+
await (0, test_1.expect)(async () => {
|
|
167
|
+
const isCompleted = await completedOverlay.isVisible().catch(() => false);
|
|
168
|
+
if (!isCompleted) {
|
|
169
|
+
const isJobStillPending = (await this.completeJobButton.isVisible().catch(() => false)) &&
|
|
170
|
+
(await this.completeJobButton.isEnabled().catch(() => false));
|
|
171
|
+
if (isJobStillPending) {
|
|
172
|
+
await this.completeJobButton.click({ timeout: 30000 });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
await (0, test_1.expect)(completedOverlay).toBeVisible({ timeout: 15000 });
|
|
176
|
+
}).toPass({
|
|
137
177
|
timeout: maxWaitTimeSeconds,
|
|
178
|
+
intervals: [2000, 5000, 10000],
|
|
138
179
|
});
|
|
139
180
|
}
|
|
140
181
|
}
|
|
@@ -27,9 +27,18 @@ _8_7_1.test.describe('Deploy and run a process in Play', () => {
|
|
|
27
27
|
});
|
|
28
28
|
await appsPage.clickCamundaApps();
|
|
29
29
|
await appsPage.clickModeler();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
// Following the Modeler link occasionally leaves the browser on the
|
|
31
|
+
// Console shell with the Modeler app never mounting, so the banner never
|
|
32
|
+
// renders and the whole flow dies before it has done anything. The link
|
|
33
|
+
// click itself succeeded, so AppsPage's own retry loop does not fire --
|
|
34
|
+
// re-open Modeler from the apps menu here instead.
|
|
35
|
+
if (!(await modelerHomePage.isModelerPageBannerVisible(120000))) {
|
|
36
|
+
await appsPage.clickCamundaApps();
|
|
37
|
+
await appsPage.clickModeler();
|
|
38
|
+
await (0, test_1.expect)(modelerHomePage.modelerPageBanner).toBeVisible({
|
|
39
|
+
timeout: 120000,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
33
42
|
});
|
|
34
43
|
await _8_7_1.test.step('Open Cross Component Test Project', async () => {
|
|
35
44
|
await modelerHomePage.clickCrossComponentProjectFolder();
|