@camunda/e2e-test-suite 0.0.376 → 0.0.377
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.
- package/dist/pages/SM-8.7/IdentityPage.js +17 -2
- package/dist/pages/SM-8.7/KeycloakAdminPage.js +30 -17
- package/dist/pages/SM-8.7/ModelerCreatePage.js +18 -4
- package/dist/pages/SM-8.7/OperateProcessesPage.js +5 -1
- package/dist/pages/SM-8.7/PlayPage.js +15 -9
- package/dist/utils/assertionHelpers/clickLocatorWithRetry.d.ts +1 -0
- package/dist/utils/assertionHelpers/clickLocatorWithRetry.js +26 -8
- package/package.json +1 -1
|
@@ -130,8 +130,23 @@ class IdentityPage {
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
async clickAssignedRolesTab() {
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
const maxRetries = 3;
|
|
134
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
135
|
+
try {
|
|
136
|
+
await (0, test_1.expect)(this.assignedRolesTab).toBeVisible({ timeout: 60000 });
|
|
137
|
+
await this.assignedRolesTab.click();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
if (attempt === maxRetries) {
|
|
142
|
+
throw error;
|
|
143
|
+
}
|
|
144
|
+
console.warn(`clickAssignedRolesTab attempt ${attempt} failed: ${error}. Retrying...`);
|
|
145
|
+
await this.page.reload().catch((reloadErr) => {
|
|
146
|
+
console.warn(`clickAssignedRolesTab: page.reload error (ignored): ${reloadErr}`);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
135
150
|
}
|
|
136
151
|
async clickDemoUser() {
|
|
137
152
|
await (0, test_1.expect)(this.demoUser).toBeVisible({ timeout: 60000 });
|
|
@@ -22,22 +22,35 @@ class KeycloakAdminPage {
|
|
|
22
22
|
await (0, test_1.expect)(this.keycloakBanner).toBeVisible({ timeout: 10000 });
|
|
23
23
|
}
|
|
24
24
|
async switchToCamundaPlatform() {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
25
|
+
const maxRetries = 3;
|
|
26
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
27
|
+
try {
|
|
28
|
+
const realmSelector = this.page.getByTestId('nav-item-realms');
|
|
29
|
+
await realmSelector.click();
|
|
30
|
+
const searchField = this.page.getByTestId('selectRealminput');
|
|
31
|
+
await (0, test_1.expect)(searchField).toBeVisible({ timeout: 30000 });
|
|
32
|
+
await searchField.click();
|
|
33
|
+
await this.page
|
|
34
|
+
.getByPlaceholder('Search')
|
|
35
|
+
.fill(process.env.KEYCLOAK_REALM || 'camunda-platform');
|
|
36
|
+
await this.page
|
|
37
|
+
.locator('[data-ouia-component-id="OUIA-Generated-Button-control-1"]')
|
|
38
|
+
.click();
|
|
39
|
+
await this.page
|
|
40
|
+
.getByText(process.env.KEYCLOAK_REALM || 'camunda-platform')
|
|
41
|
+
.click();
|
|
42
|
+
const mainLocator = this.page.locator('#kc-main-content-page-container');
|
|
43
|
+
await (0, test_1.expect)(mainLocator).toBeVisible();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
if (attempt === maxRetries) {
|
|
48
|
+
throw new Error(`switchToCamundaPlatform failed after ${maxRetries} attempts: ${error}`);
|
|
49
|
+
}
|
|
50
|
+
console.warn(`switchToCamundaPlatform attempt ${attempt} failed: ${error}. Retrying...`);
|
|
51
|
+
await (0, sleep_1.sleep)(3000);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
41
54
|
}
|
|
42
55
|
async clickUsersTab() {
|
|
43
56
|
await this.page.click('[id="nav-item-users"]');
|
|
@@ -57,7 +70,7 @@ class KeycloakAdminPage {
|
|
|
57
70
|
async fillPassword(password) {
|
|
58
71
|
await (0, test_1.expect)(this.credentialsTab).toBeVisible();
|
|
59
72
|
await this.credentialsTab.click();
|
|
60
|
-
await (0, test_1.expect)(this.noCredentialsEmptyAction).toBeVisible({ timeout:
|
|
73
|
+
await (0, test_1.expect)(this.noCredentialsEmptyAction).toBeVisible({ timeout: 60000 });
|
|
61
74
|
await this.noCredentialsEmptyAction.click();
|
|
62
75
|
await (0, test_1.expect)(this.passwordField).toBeVisible();
|
|
63
76
|
await this.passwordField.fill(password);
|
|
@@ -468,20 +468,34 @@ class ModelerCreatePage {
|
|
|
468
468
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
469
469
|
try {
|
|
470
470
|
if (attempt > 1) {
|
|
471
|
-
await this.page
|
|
471
|
+
await this.page
|
|
472
|
+
.reload({ waitUntil: 'domcontentloaded' })
|
|
473
|
+
.catch((reloadErr) => {
|
|
474
|
+
console.warn(`clickStartInstanceMainButton: page.reload error (ignored): ${reloadErr}`);
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
if (this.page.isClosed()) {
|
|
478
|
+
throw new Error('Target page, context or browser has been closed');
|
|
472
479
|
}
|
|
473
|
-
if (await this.startInstanceMainButton.isVisible({ timeout:
|
|
474
|
-
await this.startInstanceMainButton.click({ timeout:
|
|
480
|
+
if (await this.startInstanceMainButton.isVisible({ timeout: 30000 })) {
|
|
481
|
+
await this.startInstanceMainButton.click({ timeout: 30000 });
|
|
475
482
|
}
|
|
476
483
|
else {
|
|
477
|
-
await this.deployAndRunMainButton.click({ timeout:
|
|
484
|
+
await this.deployAndRunMainButton.click({ timeout: 30000 }); //will be available from alpha7
|
|
478
485
|
}
|
|
479
486
|
return;
|
|
480
487
|
}
|
|
481
488
|
catch (error) {
|
|
489
|
+
const errorMsg = String(error);
|
|
490
|
+
if (errorMsg.includes('Target page, context or browser has been closed') ||
|
|
491
|
+
errorMsg.includes('page has been closed') ||
|
|
492
|
+
errorMsg.includes('Target closed')) {
|
|
493
|
+
throw error;
|
|
494
|
+
}
|
|
482
495
|
if (attempt === maxRetries) {
|
|
483
496
|
throw new Error(`Failed to click start process after ${maxRetries} attempts: ${error}`);
|
|
484
497
|
}
|
|
498
|
+
console.warn(`clickStartInstanceMainButton attempt ${attempt} failed: ${error}`);
|
|
485
499
|
}
|
|
486
500
|
}
|
|
487
501
|
}
|
|
@@ -151,7 +151,11 @@ class OperateProcessesPage {
|
|
|
151
151
|
if (attempt === MAX_ATTEMPTS) {
|
|
152
152
|
throw new Error(`Failed to open instance "${processName}" after ${MAX_ATTEMPTS} attempts. Last error: ${String(err)}`);
|
|
153
153
|
}
|
|
154
|
-
await this.page
|
|
154
|
+
await this.page
|
|
155
|
+
.reload({ waitUntil: 'domcontentloaded' })
|
|
156
|
+
.catch((reloadErr) => {
|
|
157
|
+
console.warn(`clickProcessInstanceLink: page.reload error (ignored): ${reloadErr}`);
|
|
158
|
+
});
|
|
155
159
|
await (0, sleep_1.sleep)(5000);
|
|
156
160
|
}
|
|
157
161
|
}
|
|
@@ -38,25 +38,27 @@ class PlayPage {
|
|
|
38
38
|
name: 'Run all scenarios',
|
|
39
39
|
});
|
|
40
40
|
this.dialog = page.getByRole('dialog');
|
|
41
|
-
this.confirmSaveScenarioButton = page
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
this.confirmSaveScenarioButton = page.getByRole('button', {
|
|
42
|
+
name: 'Save',
|
|
43
|
+
exact: true,
|
|
44
|
+
});
|
|
44
45
|
this.enterScenarioNameInput = page
|
|
45
46
|
.getByTestId('save-scenario-modal')
|
|
47
|
+
.first()
|
|
46
48
|
.locator('input#scenario-name')
|
|
47
49
|
.first();
|
|
48
50
|
this.confirmDeleteScenarioButton = page.getByRole('button', {
|
|
49
51
|
name: 'danger Delete',
|
|
50
52
|
});
|
|
51
|
-
this.viewAllScenariosButton = page
|
|
52
|
-
name: '(View all)'
|
|
53
|
-
|
|
53
|
+
this.viewAllScenariosButton = page
|
|
54
|
+
.getByRole('button', { name: '(View all)' })
|
|
55
|
+
.first();
|
|
54
56
|
this.getScenarioRowByName = (scenarioName) => page.locator('tr', { hasText: scenarioName });
|
|
55
57
|
this.getScenarioRow = (scenarioName) => page.locator('tr', { hasText: scenarioName });
|
|
56
58
|
this.diagram = page.getByTestId('diagram');
|
|
57
59
|
this.startInstanceButton = page.getByTestId('undefined-Start instance');
|
|
58
60
|
this.notifications = page.locator('.cds--toast-notification');
|
|
59
|
-
this.saveScenarioModal = page.getByTestId('save-scenario-modal');
|
|
61
|
+
this.saveScenarioModal = page.getByTestId('save-scenario-modal').first();
|
|
60
62
|
this.loadingInstanceDetailsText = this.page.getByText('Loading instance details...');
|
|
61
63
|
this.retryButton = this.page.getByRole('button', { name: 'Retry' });
|
|
62
64
|
this.restartProcess = this.page.getByRole('button', {
|
|
@@ -201,10 +203,14 @@ class PlayPage {
|
|
|
201
203
|
await this.enterScenarioNameInput.fill(newScenarioName);
|
|
202
204
|
}
|
|
203
205
|
async clickViewAllScenariosButton() {
|
|
204
|
-
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.viewAllScenariosButton
|
|
206
|
+
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.viewAllScenariosButton, {
|
|
207
|
+
totalTimeout: 60000,
|
|
208
|
+
visibilityTimeout: 15000,
|
|
209
|
+
maxRetries: 5,
|
|
210
|
+
});
|
|
205
211
|
}
|
|
206
212
|
async confirmSaveScenario() {
|
|
207
|
-
await this.confirmSaveScenarioButton.click();
|
|
213
|
+
await this.confirmSaveScenarioButton.click({ timeout: 30000 });
|
|
208
214
|
}
|
|
209
215
|
async getDeleteIconForScenario(scenarioName) {
|
|
210
216
|
const scenarioRow = this.page
|
|
@@ -1,29 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.clickLocatorWithRetry = void 0;
|
|
4
|
+
const RETRY_DELAY_MS = 2000;
|
|
5
|
+
const isPageClosedError = (err) => {
|
|
6
|
+
if (!(err instanceof Error))
|
|
7
|
+
return false;
|
|
8
|
+
const msg = err.message;
|
|
9
|
+
return (msg.includes('Target page, context or browser has been closed') ||
|
|
10
|
+
msg.includes('page has been closed') ||
|
|
11
|
+
msg.includes('Target closed') ||
|
|
12
|
+
msg.includes('frame was detached') ||
|
|
13
|
+
msg.includes('Frame was detached'));
|
|
14
|
+
};
|
|
4
15
|
const clickLocatorWithRetry = async (page, locator, options) => {
|
|
5
|
-
const { totalTimeout = 60000, visibilityTimeout = 10000, maxRetries = 3, } = options || {};
|
|
16
|
+
const { totalTimeout = 60000, visibilityTimeout = 10000, maxRetries = 3, retryDelayMs = RETRY_DELAY_MS, } = options || {};
|
|
6
17
|
let attempt = 0;
|
|
7
18
|
const startTime = Date.now();
|
|
8
19
|
while (Date.now() - startTime < totalTimeout && attempt < maxRetries) {
|
|
9
20
|
attempt++;
|
|
10
21
|
try {
|
|
22
|
+
if (page.isClosed()) {
|
|
23
|
+
throw new Error('clickLocatorWithRetry: page is closed, aborting retries');
|
|
24
|
+
}
|
|
11
25
|
if (options?.preAction) {
|
|
12
26
|
await options?.preAction();
|
|
13
27
|
}
|
|
14
|
-
await
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
await locator.click();
|
|
28
|
+
await locator.waitFor({ state: 'visible', timeout: visibilityTimeout });
|
|
29
|
+
await locator.scrollIntoViewIfNeeded({ timeout: visibilityTimeout });
|
|
30
|
+
await locator.waitFor({ state: 'attached', timeout: visibilityTimeout });
|
|
31
|
+
// Trial click to verify the element is clickable before the real click
|
|
32
|
+
await locator.click({ trial: true, timeout: visibilityTimeout });
|
|
33
|
+
await locator.click({ timeout: visibilityTimeout });
|
|
19
34
|
return;
|
|
20
35
|
}
|
|
21
36
|
catch (err) {
|
|
22
|
-
|
|
37
|
+
if (isPageClosedError(err)) {
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
console.log(`Attempt ${attempt} failed for ${locator}, retrying... Error: ${err}`);
|
|
23
41
|
if (options?.postAction) {
|
|
24
42
|
await options.postAction();
|
|
25
43
|
}
|
|
26
|
-
await page.waitForTimeout(
|
|
44
|
+
await page.waitForTimeout(retryDelayMs);
|
|
27
45
|
}
|
|
28
46
|
}
|
|
29
47
|
throw new Error(`Failed to click locator ${locator} after ${attempt} attempts.`);
|