@camunda/e2e-test-suite 0.0.478 → 0.0.480
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.10/LoginPage.js +10 -8
- package/dist/pages/SM-8.10/ModelerHomePage.js +13 -10
- package/dist/pages/SM-8.10/NavigationPage.js +4 -7
- package/dist/pages/SM-8.10/OperateProcessInstancePage.js +17 -15
- package/dist/pages/SM-8.10/OptimizeCollectionsPage.js +4 -8
- package/dist/pages/SM-8.10/OptimizeHomePage.js +4 -10
- package/dist/pages/SM-8.10/UtilitiesPage.js +6 -11
- package/dist/pages/SM-8.10/optimizeReportUtils.js +9 -12
- package/dist/pages/SM-8.8/IdentityTenantPage.js +12 -11
- package/dist/pages/SM-8.8/NavigationPage.js +20 -10
- package/dist/pages/SM-8.8/OCIdentityRolesPage.js +3 -1
- package/dist/pages/SM-8.8/OCTenantPage.d.ts +2 -0
- package/dist/pages/SM-8.8/OCTenantPage.js +16 -10
- package/dist/tests/SM-8.8/mt-enabled-user-flows.spec.js +8 -2
- package/dist/utils/assertionHelpers/expectLocatorWithRetry.js +4 -7
- package/dist/utils/resetSession.js +1 -4
- package/package.json +1 -1
|
@@ -23,15 +23,17 @@ class LoginPage {
|
|
|
23
23
|
this.coreLoginButton = page.getByRole('button', { name: 'Login' });
|
|
24
24
|
this.keycloakBanner = page.locator('body#keycloak-bg[data-page-id="login-login"]');
|
|
25
25
|
}
|
|
26
|
-
// Race logic: call before interacting
|
|
27
26
|
async detectLoginForm() {
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
const anyForm = this.usernameInput
|
|
28
|
+
.or(this.coreUsernameInput)
|
|
29
|
+
.or(this.keycloakBanner);
|
|
30
|
+
await anyForm.waitFor({ state: 'visible', timeout: 15000 });
|
|
31
|
+
if (await this.coreUsernameInput.isVisible()) {
|
|
32
|
+
this.useCore = true;
|
|
33
|
+
}
|
|
34
|
+
else if (await this.keycloakBanner.isVisible()) {
|
|
35
|
+
this.useKeycloak = true;
|
|
36
|
+
}
|
|
35
37
|
}
|
|
36
38
|
async fillUsername(username) {
|
|
37
39
|
if (await this.page.locator('#username').isVisible()) {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ModelerHomePage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
-
const sleep_1 = require("../../utils/sleep");
|
|
6
5
|
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
7
6
|
class ModelerHomePage {
|
|
8
7
|
page;
|
|
@@ -75,13 +74,14 @@ class ModelerHomePage {
|
|
|
75
74
|
await this.createNewProjectButton.click();
|
|
76
75
|
}
|
|
77
76
|
async enterNewProjectName(name) {
|
|
78
|
-
await (0,
|
|
77
|
+
await (0, test_1.expect)(this.projectNameInput).toBeVisible({ timeout: 10000 });
|
|
79
78
|
await this.projectNameInput.click({ timeout: 60000 });
|
|
80
79
|
await this.projectNameInput.fill(name);
|
|
81
80
|
await this.projectNameInput.press('Enter');
|
|
82
81
|
}
|
|
83
82
|
async createCrossComponentProjectFolder() {
|
|
84
|
-
await
|
|
83
|
+
await this.page.waitForLoadState('networkidle');
|
|
84
|
+
await (0, test_1.expect)(this.createNewProjectButton).toBeVisible({ timeout: 30000 });
|
|
85
85
|
await this.clickMessageBanner();
|
|
86
86
|
if (await this.crossComponentProjectFolder.isVisible()) {
|
|
87
87
|
console.log('Cross Component Project folder already exists. Clicking into it');
|
|
@@ -90,7 +90,7 @@ class ModelerHomePage {
|
|
|
90
90
|
}
|
|
91
91
|
await this.clickCreateNewProjectButton();
|
|
92
92
|
await this.enterNewProjectName(this.defaultFolderName);
|
|
93
|
-
await (0,
|
|
93
|
+
await (0, test_1.expect)(this.page.getByRole('heading', { name: this.defaultFolderName })).toBeVisible({ timeout: 10000 });
|
|
94
94
|
}
|
|
95
95
|
async clickCrossComponentProjectFolder() {
|
|
96
96
|
let attempts = 0;
|
|
@@ -109,7 +109,7 @@ class ModelerHomePage {
|
|
|
109
109
|
if (attempts < maxAttempts) {
|
|
110
110
|
console.log(`Attempt ${attempts} failed. Reloading page and retrying...`);
|
|
111
111
|
await this.page.reload();
|
|
112
|
-
await
|
|
112
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
113
113
|
}
|
|
114
114
|
else {
|
|
115
115
|
throw new Error('Failed to click crossComponentProjectFolder after 3 attempts.');
|
|
@@ -149,7 +149,7 @@ class ModelerHomePage {
|
|
|
149
149
|
await this.formTemplateOption.click();
|
|
150
150
|
}
|
|
151
151
|
async enterFormName(name) {
|
|
152
|
-
await (0,
|
|
152
|
+
await (0, test_1.expect)(this.formNameInput).toBeVisible({ timeout: 10000 });
|
|
153
153
|
await this.formNameInput.click({ timeout: 60000 });
|
|
154
154
|
await this.formNameInput.fill(name);
|
|
155
155
|
await this.formNameInput.press('Enter');
|
|
@@ -168,10 +168,13 @@ class ModelerHomePage {
|
|
|
168
168
|
}
|
|
169
169
|
async clickMessageBanner() {
|
|
170
170
|
try {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
const banner = this.messageBanner.or(this.closeButton);
|
|
172
|
+
if (await banner.isVisible({ timeout: 2000 })) {
|
|
173
|
+
await banner.click();
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
console.log('No banner or close button found to click');
|
|
177
|
+
}
|
|
175
178
|
}
|
|
176
179
|
catch {
|
|
177
180
|
console.log('No banner or close button found to click');
|
|
@@ -77,14 +77,11 @@ class NavigationPage {
|
|
|
77
77
|
await (0, test_1.expect)(loginEntryPoint).toBeVisible({ timeout: 30000 });
|
|
78
78
|
const isBannerVisible = await banner.isVisible().catch(() => false);
|
|
79
79
|
if (isBannerVisible) {
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
const loginVisible = await loginPage.usernameInput.isVisible();
|
|
81
|
+
if (loginVisible) {
|
|
82
82
|
await loginPage.login(username, password);
|
|
83
83
|
}
|
|
84
|
-
|
|
85
|
-
// The login selector did NOT appear. The banner is real. We are on the correct page.
|
|
86
|
-
// The navigation was successful, so we can just return.
|
|
87
|
-
}
|
|
84
|
+
// If login selector not visible, banner is real - navigation succeeded
|
|
88
85
|
}
|
|
89
86
|
else {
|
|
90
87
|
await loginPage.login(username, password);
|
|
@@ -96,7 +93,7 @@ class NavigationPage {
|
|
|
96
93
|
const now = new Date();
|
|
97
94
|
const elapsed = Date.now() - startTime;
|
|
98
95
|
if (attempt < maxRetries - 1) {
|
|
99
|
-
await (0, sleep_1.sleep)(
|
|
96
|
+
await (0, sleep_1.sleep)(2000);
|
|
100
97
|
if (!this.page.isClosed()) {
|
|
101
98
|
try {
|
|
102
99
|
await this.page.waitForLoadState('load', { timeout: timeout });
|
|
@@ -50,7 +50,7 @@ class OperateProcessInstancePage {
|
|
|
50
50
|
retryCount++;
|
|
51
51
|
console.log(`Attempt ${retryCount} failed. Retrying...`);
|
|
52
52
|
await this.page.reload();
|
|
53
|
-
await
|
|
53
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
throw new Error(`Active icon not visible after ${maxRetries} attempts.`);
|
|
@@ -70,7 +70,7 @@ class OperateProcessInstancePage {
|
|
|
70
70
|
retryCount++;
|
|
71
71
|
console.log(`Attempt ${retryCount} failed. Retrying...`);
|
|
72
72
|
await this.page.reload();
|
|
73
|
-
await
|
|
73
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
throw new Error(`Active icon not visible after ${maxRetries} attempts.`);
|
|
@@ -90,7 +90,7 @@ class OperateProcessInstancePage {
|
|
|
90
90
|
retryCount++;
|
|
91
91
|
console.log(`Attempt ${retryCount} failed. Retrying...`);
|
|
92
92
|
await this.page.reload();
|
|
93
|
-
await
|
|
93
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
throw new Error(`Active icon not visible after ${maxRetries} attempts.`);
|
|
@@ -110,7 +110,7 @@ class OperateProcessInstancePage {
|
|
|
110
110
|
retryCount++;
|
|
111
111
|
console.log(`Attempt ${retryCount} failed. Retrying...`);
|
|
112
112
|
await this.page.reload();
|
|
113
|
-
await
|
|
113
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
throw new Error(`Active icon visible after ${maxRetries} attempts.`);
|
|
@@ -122,16 +122,18 @@ class OperateProcessInstancePage {
|
|
|
122
122
|
await (0, test_1.expect)(this.incidentIcon).toBeVisible({ timeout: 90000 });
|
|
123
123
|
}
|
|
124
124
|
async assertEitherIncidentOrActiveIconVisible() {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
const either = this.incidentIcon.or(this.activeIcon);
|
|
126
|
+
await (0, test_1.expect)(either).toBeVisible({ timeout: 90000 });
|
|
127
|
+
if (await this.incidentIcon.isVisible())
|
|
128
|
+
return 'incident';
|
|
129
|
+
return 'active';
|
|
129
130
|
}
|
|
130
131
|
async assertEitherIncidentOrCompletedIconVisible() {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
const either = this.incidentIcon.or(this.completedIcon);
|
|
133
|
+
await (0, test_1.expect)(either).toBeVisible({ timeout: 90000 });
|
|
134
|
+
if (await this.incidentIcon.isVisible())
|
|
135
|
+
return 'incident';
|
|
136
|
+
return 'completed';
|
|
135
137
|
}
|
|
136
138
|
async assertProcessCompleteStatusWithRetry(timeout = 60000, maxRetries = 10) {
|
|
137
139
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
@@ -145,7 +147,7 @@ class OperateProcessInstancePage {
|
|
|
145
147
|
if (attempt < maxRetries - 1) {
|
|
146
148
|
console.warn(`Process complete status attempt ${attempt + 1} failed. Retrying...`);
|
|
147
149
|
await this.page.reload();
|
|
148
|
-
await
|
|
150
|
+
await this.page.waitForLoadState('domcontentloaded');
|
|
149
151
|
}
|
|
150
152
|
else {
|
|
151
153
|
throw new Error(`Assertion failed after ${maxRetries} attempts`);
|
|
@@ -164,7 +166,7 @@ class OperateProcessInstancePage {
|
|
|
164
166
|
console.log(`assertProcessVariableContainsText attempt ${attempt + 1}/${maxRetries} failed: ${error}`);
|
|
165
167
|
if (attempt < maxRetries - 1) {
|
|
166
168
|
await this.page.reload({ timeout: 10000 }).catch(() => { });
|
|
167
|
-
await (
|
|
169
|
+
await this.page.waitForLoadState('domcontentloaded').catch(() => { });
|
|
168
170
|
}
|
|
169
171
|
}
|
|
170
172
|
}
|
|
@@ -182,7 +184,7 @@ class OperateProcessInstancePage {
|
|
|
182
184
|
console.log(`assertResultVariableVisibleWithRetry attempt ${attempt + 1}/${maxRetries} failed: ${error}`);
|
|
183
185
|
if (attempt < maxRetries - 1) {
|
|
184
186
|
await this.page.reload({ timeout: 10000 }).catch(() => { });
|
|
185
|
-
await (
|
|
187
|
+
await this.page.waitForLoadState('domcontentloaded').catch(() => { });
|
|
186
188
|
}
|
|
187
189
|
}
|
|
188
190
|
}
|
|
@@ -26,15 +26,11 @@ class OptimizeCollectionsPage {
|
|
|
26
26
|
this.reportAuthor = page.getByRole('cell', { name: 'Demo User' });
|
|
27
27
|
}
|
|
28
28
|
async clickCreateNewButton() {
|
|
29
|
-
|
|
30
|
-
await this.modalCloseButton.click(
|
|
31
|
-
await this.collectionsLink.click({ timeout: 60000 });
|
|
32
|
-
await this.createNewButton.click({ timeout: 90000 });
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
await this.collectionsLink.click({ timeout: 60000 });
|
|
36
|
-
await this.createNewButton.click({ timeout: 90000 });
|
|
29
|
+
if (await this.modalCloseButton.isVisible({ timeout: 2000 })) {
|
|
30
|
+
await this.modalCloseButton.click();
|
|
37
31
|
}
|
|
32
|
+
await this.collectionsLink.click({ timeout: 60000 });
|
|
33
|
+
await this.createNewButton.click({ timeout: 90000 });
|
|
38
34
|
}
|
|
39
35
|
async clickReportOption() {
|
|
40
36
|
await this.reportOption.click();
|
|
@@ -30,22 +30,16 @@ class OptimizeHomePage {
|
|
|
30
30
|
this.licenseKeyTagProduction = page.getByText('Production license').first();
|
|
31
31
|
}
|
|
32
32
|
async clickCollectionsLink() {
|
|
33
|
-
|
|
33
|
+
if (await this.modalCloseButton.isVisible({ timeout: 2000 })) {
|
|
34
34
|
await this.modalCloseButton.click();
|
|
35
|
-
await this.collectionsLink.click();
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
await this.collectionsLink.click();
|
|
39
35
|
}
|
|
36
|
+
await this.collectionsLink.click();
|
|
40
37
|
}
|
|
41
38
|
async clickDashboardLink() {
|
|
42
|
-
|
|
39
|
+
if (await this.modalCloseButton.isVisible({ timeout: 2000 })) {
|
|
43
40
|
await this.modalCloseButton.click();
|
|
44
|
-
await this.dashboardLink.click();
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
await this.dashboardLink.click();
|
|
48
41
|
}
|
|
42
|
+
await this.dashboardLink.click();
|
|
49
43
|
}
|
|
50
44
|
async assertProcessHasBeenImported(processId) {
|
|
51
45
|
await this.clickDashboardLink();
|
|
@@ -75,7 +75,6 @@ async function completeTaskWithRetry(page, taskPanelPage, taskDetailsPage, taskN
|
|
|
75
75
|
.first();
|
|
76
76
|
if (await toastCloseButton.isVisible({ timeout: 2000 })) {
|
|
77
77
|
await toastCloseButton.click();
|
|
78
|
-
await (0, sleep_1.sleep)(500);
|
|
79
78
|
}
|
|
80
79
|
}
|
|
81
80
|
catch {
|
|
@@ -84,7 +83,6 @@ async function completeTaskWithRetry(page, taskPanelPage, taskDetailsPage, taskN
|
|
|
84
83
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
85
84
|
try {
|
|
86
85
|
await page.waitForLoadState('networkidle');
|
|
87
|
-
await (0, sleep_1.sleep)(500);
|
|
88
86
|
const taskLocator = taskPanelPage.availableTasks
|
|
89
87
|
.getByText(taskName, { exact: true })
|
|
90
88
|
.first();
|
|
@@ -97,7 +95,6 @@ async function completeTaskWithRetry(page, taskPanelPage, taskDetailsPage, taskN
|
|
|
97
95
|
// Click the task directly instead of using openTask's 30-retry loop
|
|
98
96
|
// (this outer loop already provides retry logic)
|
|
99
97
|
await taskLocator.click({ timeout: 10000 });
|
|
100
|
-
await (0, sleep_1.sleep)(1000);
|
|
101
98
|
await (0, test_1.expect)(taskDetailsPage.detailsPanel).toBeVisible({ timeout: 30000 });
|
|
102
99
|
// Verify the correct task is loaded by checking the task name appears
|
|
103
100
|
// in the details-info section (the task name heading is outside the
|
|
@@ -109,9 +106,9 @@ async function completeTaskWithRetry(page, taskPanelPage, taskDetailsPage, taskN
|
|
|
109
106
|
await (0, test_1.expect)(taskDetailsPage.detailsPanel.getByText(taskPriority)).toBeVisible({ timeout: 30000 });
|
|
110
107
|
await taskDetailsPage.completeTaskButton.click({ timeout: 30000 });
|
|
111
108
|
await (0, test_1.expect)(taskDetailsPage.taskCompletedBanner).toBeVisible({
|
|
112
|
-
timeout:
|
|
109
|
+
timeout: 30000,
|
|
113
110
|
});
|
|
114
|
-
await (0, test_1.expect)(taskPanelPage.availableTasks.getByText(taskName, { exact: true }).first()).not.toBeVisible({ timeout:
|
|
111
|
+
await (0, test_1.expect)(taskPanelPage.availableTasks.getByText(taskName, { exact: true }).first()).not.toBeVisible({ timeout: 15000 });
|
|
115
112
|
console.log(`Successfully completed task: ${taskName}`);
|
|
116
113
|
return;
|
|
117
114
|
}
|
|
@@ -126,7 +123,6 @@ async function completeTaskWithRetry(page, taskPanelPage, taskDetailsPage, taskN
|
|
|
126
123
|
.first();
|
|
127
124
|
if (await toastCloseButton.isVisible({ timeout: 1000 })) {
|
|
128
125
|
await toastCloseButton.click();
|
|
129
|
-
await (0, sleep_1.sleep)(300);
|
|
130
126
|
}
|
|
131
127
|
}
|
|
132
128
|
catch {
|
|
@@ -134,7 +130,6 @@ async function completeTaskWithRetry(page, taskPanelPage, taskDetailsPage, taskN
|
|
|
134
130
|
}
|
|
135
131
|
await page.reload();
|
|
136
132
|
await page.waitForLoadState('networkidle');
|
|
137
|
-
await (0, sleep_1.sleep)(500);
|
|
138
133
|
}
|
|
139
134
|
else {
|
|
140
135
|
console.error(`All ${maxRetries} attempts failed for task ${taskName}`);
|
|
@@ -253,10 +248,11 @@ async function assertLocatorVisibleWithPaginated(page, locator, text) {
|
|
|
253
248
|
}
|
|
254
249
|
}
|
|
255
250
|
exports.assertLocatorVisibleWithPaginated = assertLocatorVisibleWithPaginated;
|
|
256
|
-
async function assertLocatorVisibleWithRetry(page, locator, text, timeout =
|
|
251
|
+
async function assertLocatorVisibleWithRetry(page, locator, text, timeout = 30000, notVisible, maxRetries = 3, clickLocator) {
|
|
257
252
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
258
253
|
try {
|
|
259
254
|
await page.reload();
|
|
255
|
+
await page.waitForLoadState('domcontentloaded');
|
|
260
256
|
if (clickLocator) {
|
|
261
257
|
await (0, test_1.expect)(clickLocator).toBeVisible({
|
|
262
258
|
timeout: 30000,
|
|
@@ -264,7 +260,6 @@ async function assertLocatorVisibleWithRetry(page, locator, text, timeout = 1200
|
|
|
264
260
|
await clickLocator.click();
|
|
265
261
|
}
|
|
266
262
|
if (notVisible == true) {
|
|
267
|
-
await (0, sleep_1.sleep)(10000);
|
|
268
263
|
await (0, test_1.expect)(locator.first()).not.toBeVisible({
|
|
269
264
|
timeout: timeout,
|
|
270
265
|
});
|
|
@@ -287,12 +282,12 @@ async function assertLocatorVisibleWithRetry(page, locator, text, timeout = 1200
|
|
|
287
282
|
}
|
|
288
283
|
}
|
|
289
284
|
exports.assertLocatorVisibleWithRetry = assertLocatorVisibleWithRetry;
|
|
290
|
-
async function assertPageTextWithRetry(page, text, notVisible, timeout =
|
|
285
|
+
async function assertPageTextWithRetry(page, text, notVisible, timeout = 30000, maxRetries = 3) {
|
|
291
286
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
292
287
|
try {
|
|
293
288
|
await page.reload();
|
|
289
|
+
await page.waitForLoadState('domcontentloaded');
|
|
294
290
|
if (notVisible == true) {
|
|
295
|
-
await (0, sleep_1.sleep)(10000);
|
|
296
291
|
await (0, test_1.expect)(page.getByText(text, { exact: true }).first()).not.toBeVisible({
|
|
297
292
|
timeout: timeout,
|
|
298
293
|
});
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.assertReportWithRefreshes = exports.createReportForProcess = void 0;
|
|
4
|
-
const test_1 = require("@playwright/test");
|
|
5
4
|
const UtilitiesPage_1 = require("../SM-8.10/UtilitiesPage");
|
|
6
5
|
const UtilitiesPage_2 = require("../SM-8.10/UtilitiesPage");
|
|
7
6
|
const createReportForProcess = async (optimizeCollectionsPage, optimizeReportPage, processName) => {
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const maxRetries = 30;
|
|
8
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
10
9
|
try {
|
|
11
10
|
await optimizeCollectionsPage.clickCreateNewButton();
|
|
12
11
|
await optimizeCollectionsPage.clickReportOption();
|
|
13
12
|
await optimizeReportPage.clickProcessSelectionButton();
|
|
14
13
|
await optimizeReportPage.waitUntilUserTaskProcessIsVisible(processName);
|
|
15
|
-
|
|
14
|
+
return;
|
|
16
15
|
}
|
|
17
16
|
catch (error) {
|
|
18
17
|
try {
|
|
@@ -21,28 +20,26 @@ const createReportForProcess = async (optimizeCollectionsPage, optimizeReportPag
|
|
|
21
20
|
catch (cancelError) {
|
|
22
21
|
// Page may have been closed due to test timeout, ignore
|
|
23
22
|
}
|
|
24
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
23
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
25
24
|
}
|
|
26
|
-
retries--;
|
|
27
|
-
(0, test_1.expect)(retries).toBeGreaterThan(0);
|
|
28
25
|
}
|
|
26
|
+
throw new Error(`Failed to create report for process ${processName} after ${maxRetries} attempts`);
|
|
29
27
|
};
|
|
30
28
|
exports.createReportForProcess = createReportForProcess;
|
|
31
29
|
const assertReportWithRefreshes = async (page, optimizeHomePage, optimizeCollectionsPage, optimizeReportPage, reportName, locator, text) => {
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
const maxRetries = 30;
|
|
31
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
34
32
|
try {
|
|
35
33
|
await optimizeHomePage.clickCollectionsLink();
|
|
36
34
|
await (0, UtilitiesPage_1.assertPageTextWithRetry)(page, reportName, false);
|
|
37
35
|
await optimizeCollectionsPage.clickMostRecentProcessReport(reportName);
|
|
38
36
|
await (0, UtilitiesPage_2.assertLocatorVisibleWithRetry)(page, locator, text, 0);
|
|
39
|
-
|
|
37
|
+
return;
|
|
40
38
|
}
|
|
41
39
|
catch (error) {
|
|
42
40
|
// nothing to do. Just loop back to the collections
|
|
43
41
|
}
|
|
44
|
-
retries--;
|
|
45
|
-
(0, test_1.expect)(retries).toBeGreaterThan(0);
|
|
46
42
|
}
|
|
43
|
+
throw new Error(`Failed to assert report ${reportName} after ${maxRetries} attempts`);
|
|
47
44
|
};
|
|
48
45
|
exports.assertReportWithRefreshes = assertReportWithRefreshes;
|
|
@@ -3,7 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.IdentityTenantPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const sleep_1 = require("../../utils/sleep");
|
|
6
|
-
const
|
|
6
|
+
const expectLocatorWithPagination_1 = require("../../utils/assertionHelpers/expectLocatorWithPagination");
|
|
7
|
+
const clickLocatorWithRetry_1 = require("../../utils/assertionHelpers/clickLocatorWithRetry");
|
|
7
8
|
class IdentityTenantPage {
|
|
8
9
|
page;
|
|
9
10
|
createTenantMainButton;
|
|
@@ -43,7 +44,7 @@ class IdentityTenantPage {
|
|
|
43
44
|
this.assignUsersButton = page.getByRole('button', { name: 'Assign users' });
|
|
44
45
|
this.searchUsersInput = page.getByPlaceholder('Search users');
|
|
45
46
|
this.assignUserFinalButton = page
|
|
46
|
-
.
|
|
47
|
+
.getByRole('dialog', { name: 'Assign users' })
|
|
47
48
|
.getByRole('button', { name: 'Assign users' });
|
|
48
49
|
this.removeUserButton = page.getByLabel('Remove user');
|
|
49
50
|
this.removeButton = page.getByRole('button', { name: 'danger Remove' });
|
|
@@ -91,8 +92,11 @@ class IdentityTenantPage {
|
|
|
91
92
|
await this.enterTenantIdInput.fill(tenantId);
|
|
92
93
|
}
|
|
93
94
|
async clickAssignedUsersTab() {
|
|
94
|
-
await (0,
|
|
95
|
-
|
|
95
|
+
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.assignedUsersTab, {
|
|
96
|
+
postAction: async () => {
|
|
97
|
+
await this.page.reload();
|
|
98
|
+
},
|
|
99
|
+
});
|
|
96
100
|
}
|
|
97
101
|
async clickAssignUsersButton() {
|
|
98
102
|
await (0, test_1.expect)(this.assignUsersButton).toBeVisible({ timeout: 60000 });
|
|
@@ -108,13 +112,10 @@ class IdentityTenantPage {
|
|
|
108
112
|
try {
|
|
109
113
|
await (0, test_1.expect)(this.assignUserFinalButton).toBeVisible({ timeout: 60000 });
|
|
110
114
|
await this.assignUserFinalButton.click();
|
|
111
|
-
await (0, test_1.expect)(this.page.getByText('Users assigned')).toBeVisible();
|
|
115
|
+
await (0, test_1.expect)(this.page.getByText('Users assigned', { exact: true })).toBeVisible();
|
|
112
116
|
}
|
|
113
117
|
catch (e) {
|
|
114
|
-
if (await this.page
|
|
115
|
-
.getByText('ALREADY_EXISTS')
|
|
116
|
-
.first()
|
|
117
|
-
.isVisible({ timeout: 8000 })) {
|
|
118
|
+
if (await this.page.getByText('ALREADY_EXISTS').first().isVisible()) {
|
|
118
119
|
console.log('Tenant is already assigned to tenant');
|
|
119
120
|
await this.cancelButton.click();
|
|
120
121
|
await (0, test_1.expect)(this.dialog).not.toBeVisible({ timeout: 15000 });
|
|
@@ -151,7 +152,7 @@ class IdentityTenantPage {
|
|
|
151
152
|
try {
|
|
152
153
|
await this.page.waitForLoadState('domcontentloaded').catch(() => { });
|
|
153
154
|
const tenantRow = this.row(tenantName);
|
|
154
|
-
await (0,
|
|
155
|
+
await (0, expectLocatorWithPagination_1.expectLocatorWithPagination)(this.page, tenantRow);
|
|
155
156
|
await tenantRow.locator('td').first().click({ timeout: 30000 });
|
|
156
157
|
await this.usersTab.waitFor({ state: 'visible', timeout: 30000 });
|
|
157
158
|
return;
|
|
@@ -185,7 +186,7 @@ class IdentityTenantPage {
|
|
|
185
186
|
await this.clickSearchUsersInput();
|
|
186
187
|
await this.fillSearchUsersInput(user);
|
|
187
188
|
await (0, test_1.expect)(this.page.getByText(userEmail)).toBeVisible({ timeout: 30000 });
|
|
188
|
-
await this.page.getByText(userEmail).click();
|
|
189
|
+
await this.page.getByText(userEmail).click({ timeout: 30000 });
|
|
189
190
|
await this.clickAssignUserFinalButton();
|
|
190
191
|
}
|
|
191
192
|
async removeUserFromTenant(tenantName) {
|
|
@@ -29,6 +29,7 @@ class NavigationPage {
|
|
|
29
29
|
this.optimizePageBanner = page.getByRole('link', {
|
|
30
30
|
name: 'Camunda logo Optimize',
|
|
31
31
|
});
|
|
32
|
+
// TODO: Drop support for Identity once we fully rename it to Admin
|
|
32
33
|
this.identityPageBanner = page
|
|
33
34
|
.locator('a')
|
|
34
35
|
.filter({ hasText: /^Camunda logo\s*(Identity|Admin)$/ })
|
|
@@ -36,31 +37,39 @@ class NavigationPage {
|
|
|
36
37
|
this.consolePageBanner = page.getByRole('link', {
|
|
37
38
|
name: 'Camunda logo Console',
|
|
38
39
|
});
|
|
39
|
-
this.managementIdentityPageBanner = page
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
this.managementIdentityPageBanner = page
|
|
41
|
+
.locator('a')
|
|
42
|
+
.filter({ hasText: /^Camunda logo\s*Management Identity$/ })
|
|
43
|
+
.first();
|
|
42
44
|
this.keyboardPageBanner = page.locator('#keycloak-bg');
|
|
43
45
|
}
|
|
44
46
|
async goTo(url, banner, sleepTimeout, { username = 'demo', password = process.env.DISTRO_QA_E2E_TESTS_IDENTITY_FIRSTUSER_PASSWORD ??
|
|
45
47
|
'demo', } = {}, maxRetries = 3) {
|
|
46
48
|
const startTime = Date.now();
|
|
47
|
-
let timeout = constants_1._1_SECOND_IN_MS *
|
|
49
|
+
let timeout = constants_1._1_SECOND_IN_MS * 10;
|
|
48
50
|
if (url === '/modeler') {
|
|
49
|
-
timeout = constants_1._1_SECOND_IN_MS *
|
|
51
|
+
timeout = constants_1._1_SECOND_IN_MS * 20;
|
|
50
52
|
}
|
|
51
53
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
52
54
|
try {
|
|
53
55
|
if (sleepTimeout) {
|
|
54
56
|
await (0, sleep_1.sleep)(sleepTimeout);
|
|
55
57
|
}
|
|
56
|
-
await this.page.goto(url, {
|
|
58
|
+
await this.page.goto(url, {
|
|
59
|
+
timeout: 30000,
|
|
60
|
+
waitUntil: 'domcontentloaded',
|
|
61
|
+
});
|
|
57
62
|
const loginPage = new LoginPage_1.LoginPage(this.page);
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
63
|
+
const loginEntryPoint = banner
|
|
64
|
+
.or(loginPage.usernameInput)
|
|
65
|
+
.or(loginPage.coreUsernameInput)
|
|
66
|
+
.or(loginPage.keycloakBanner)
|
|
67
|
+
.first();
|
|
68
|
+
await (0, test_1.expect)(loginEntryPoint).toBeVisible({ timeout: 30000 });
|
|
69
|
+
const isBannerVisible = await banner.isVisible().catch(() => false);
|
|
61
70
|
if (isBannerVisible) {
|
|
62
71
|
try {
|
|
63
|
-
await (0, test_1.expect)(
|
|
72
|
+
await (0, test_1.expect)(loginPage.usernameInput).toBeVisible({ timeout: 5000 });
|
|
64
73
|
await loginPage.login(username, password);
|
|
65
74
|
}
|
|
66
75
|
catch (error) {
|
|
@@ -71,6 +80,7 @@ class NavigationPage {
|
|
|
71
80
|
else {
|
|
72
81
|
await loginPage.login(username, password);
|
|
73
82
|
}
|
|
83
|
+
await (0, test_1.expect)(banner).toBeVisible({ timeout: 60000 });
|
|
74
84
|
return;
|
|
75
85
|
}
|
|
76
86
|
catch (error) {
|
|
@@ -160,7 +160,8 @@ class OCIdentityRolesPage {
|
|
|
160
160
|
await this.clickAssignUserSubButton();
|
|
161
161
|
}
|
|
162
162
|
async clickAssignUserButton() {
|
|
163
|
-
await this.assignUserButton.
|
|
163
|
+
await (0, test_1.expect)(this.assignUserButton).toBeVisible({ timeout: 60000 });
|
|
164
|
+
await this.assignUserButton.click({ timeout: 60000 });
|
|
164
165
|
}
|
|
165
166
|
async clickUsernameTextbox() {
|
|
166
167
|
await this.usernameTextBox.click();
|
|
@@ -172,6 +173,7 @@ class OCIdentityRolesPage {
|
|
|
172
173
|
await this.assignUserSubButton.click();
|
|
173
174
|
}
|
|
174
175
|
async clickAdminRole() {
|
|
176
|
+
await (0, test_1.expect)(this.adminRole).toBeVisible({ timeout: 60000 });
|
|
175
177
|
await this.adminRole.click();
|
|
176
178
|
}
|
|
177
179
|
async clickClientsTab() {
|
|
@@ -24,6 +24,7 @@ declare class OCTenantPage {
|
|
|
24
24
|
readonly roleIdSearchBox: Locator;
|
|
25
25
|
readonly assignRoleSubButton: Locator;
|
|
26
26
|
readonly cancelButton: Locator;
|
|
27
|
+
readonly gotItButton: Locator;
|
|
27
28
|
readonly row: (name: string) => Locator;
|
|
28
29
|
constructor(page: Page);
|
|
29
30
|
clickCreateTenantMainButton(): Promise<void>;
|
|
@@ -44,6 +45,7 @@ declare class OCTenantPage {
|
|
|
44
45
|
createTenant(tenantName: string): Promise<void>;
|
|
45
46
|
assertTenantCreated(): Promise<void>;
|
|
46
47
|
clickCancelButton(): Promise<void>;
|
|
48
|
+
clickGotItButton(): Promise<void>;
|
|
47
49
|
clickTenant(tenantName: string): Promise<void>;
|
|
48
50
|
assignUserToTenant(user: string): Promise<void>;
|
|
49
51
|
removeUserFromTenant(tenantName: string): Promise<void>;
|
|
@@ -29,6 +29,7 @@ class OCTenantPage {
|
|
|
29
29
|
roleIdSearchBox;
|
|
30
30
|
assignRoleSubButton;
|
|
31
31
|
cancelButton;
|
|
32
|
+
gotItButton;
|
|
32
33
|
row;
|
|
33
34
|
constructor(page) {
|
|
34
35
|
this.page = page;
|
|
@@ -77,6 +78,7 @@ class OCTenantPage {
|
|
|
77
78
|
this.cancelButton = page
|
|
78
79
|
.getByRole('dialog')
|
|
79
80
|
.getByRole('button', { name: 'Cancel' });
|
|
81
|
+
this.gotItButton = page.getByRole('button', { name: 'Got it' });
|
|
80
82
|
this.row = (name) => this.page.getByRole('row').filter({ hasText: name }).first();
|
|
81
83
|
}
|
|
82
84
|
async clickCreateTenantMainButton() {
|
|
@@ -115,10 +117,7 @@ class OCTenantPage {
|
|
|
115
117
|
await (0, test_1.expect)(this.page.getByRole('dialog')).not.toBeVisible();
|
|
116
118
|
}
|
|
117
119
|
catch (e) {
|
|
118
|
-
if (await this.page
|
|
119
|
-
.getByText('ALREADY_EXISTS')
|
|
120
|
-
.first()
|
|
121
|
-
.isVisible({ timeout: 10000 })) {
|
|
120
|
+
if (await this.page.getByText('ALREADY_EXISTS').first().isVisible()) {
|
|
122
121
|
console.log('User is already assigned to tenant');
|
|
123
122
|
await this.clickCancelButton();
|
|
124
123
|
}
|
|
@@ -152,25 +151,32 @@ class OCTenantPage {
|
|
|
152
151
|
}
|
|
153
152
|
async assertTenantCreated() {
|
|
154
153
|
try {
|
|
155
|
-
await (0, test_1.expect)(this.page.getByText('
|
|
154
|
+
await (0, test_1.expect)(this.page.getByText('successfully created')).toBeVisible({
|
|
156
155
|
timeout: 8000,
|
|
157
156
|
});
|
|
157
|
+
// "Got it" button appears in some versions but not others
|
|
158
|
+
try {
|
|
159
|
+
await this.clickGotItButton();
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// Button not present in this version, continue
|
|
163
|
+
}
|
|
158
164
|
}
|
|
159
165
|
catch (error) {
|
|
160
|
-
if (await this.page
|
|
161
|
-
.getByText('ALREADY_EXISTS')
|
|
162
|
-
.first()
|
|
163
|
-
.isVisible({ timeout: 8000 })) {
|
|
166
|
+
if (await this.page.getByText('ALREADY_EXISTS').first().isVisible()) {
|
|
164
167
|
await this.clickCancelButton();
|
|
165
168
|
}
|
|
166
169
|
else {
|
|
167
|
-
throw new Error('
|
|
170
|
+
throw new Error('Creating tenant failed' + error);
|
|
168
171
|
}
|
|
169
172
|
}
|
|
170
173
|
}
|
|
171
174
|
async clickCancelButton() {
|
|
172
175
|
await this.cancelButton.click({ timeout: 30000 });
|
|
173
176
|
}
|
|
177
|
+
async clickGotItButton() {
|
|
178
|
+
await this.gotItButton.click({ timeout: 30000 });
|
|
179
|
+
}
|
|
174
180
|
async clickTenant(tenantName) {
|
|
175
181
|
const maxRetries = 10;
|
|
176
182
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
@@ -6,6 +6,7 @@ const _setup_1 = require("../../test-setup.js");
|
|
|
6
6
|
const UtilitiesPage_1 = require("../../pages/SM-8.8/UtilitiesPage");
|
|
7
7
|
const resetSession_1 = require("../../utils/resetSession");
|
|
8
8
|
const expectTextWithRetry_1 = require("../../utils/assertionHelpers/expectTextWithRetry");
|
|
9
|
+
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
9
10
|
const demoUserEmail = process.env.DEMO_USER_EMAIL || 'demo@example.org';
|
|
10
11
|
const demoUserDisplayText = `Demo User${demoUserEmail}`;
|
|
11
12
|
if (process.env.IS_MT === 'true') {
|
|
@@ -49,7 +50,7 @@ if (process.env.IS_MT === 'true') {
|
|
|
49
50
|
});
|
|
50
51
|
await SM_8_8_1.test.step('Open Cross Component Test Project', async () => {
|
|
51
52
|
await navigationPage.goToModeler();
|
|
52
|
-
await modelerHomePage.
|
|
53
|
+
await modelerHomePage.createCrossComponentProjectFolder();
|
|
53
54
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
54
55
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
55
56
|
});
|
|
@@ -490,7 +491,7 @@ if (process.env.IS_MT === 'true') {
|
|
|
490
491
|
});
|
|
491
492
|
await SM_8_8_1.test.step('Open Cross Component Test Project', async () => {
|
|
492
493
|
await navigationPage.goToModeler();
|
|
493
|
-
await modelerHomePage.
|
|
494
|
+
await modelerHomePage.createCrossComponentProjectFolder();
|
|
494
495
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
495
496
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
496
497
|
});
|
|
@@ -531,6 +532,11 @@ if (process.env.IS_MT === 'true') {
|
|
|
531
532
|
}
|
|
532
533
|
await SM_8_8_1.test.step('Delete Tenant Access For Demo User OC', async () => {
|
|
533
534
|
await navigationPage.goToOCIdentity();
|
|
535
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(page, ocIdentityHomePage.tenantsTab, {
|
|
536
|
+
postAction: async () => {
|
|
537
|
+
await navigationPage.goToOCIdentity();
|
|
538
|
+
},
|
|
539
|
+
});
|
|
534
540
|
await ocIdentityHomePage.clickTenantsTab();
|
|
535
541
|
await ocTenantPage.removeUserFromTenant(tenantName);
|
|
536
542
|
});
|
|
@@ -12,13 +12,10 @@ const expectLocatorWithRetry = async (page, item, options) => {
|
|
|
12
12
|
await options?.preAction();
|
|
13
13
|
}
|
|
14
14
|
await page.waitForLoadState('domcontentloaded');
|
|
15
|
-
await
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}),
|
|
20
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Visibility timeout')), visibilityTimeout)),
|
|
21
|
-
]);
|
|
15
|
+
await item.waitFor({
|
|
16
|
+
state: shouldBeVisible ? 'visible' : 'hidden',
|
|
17
|
+
timeout: visibilityTimeout,
|
|
18
|
+
});
|
|
22
19
|
return;
|
|
23
20
|
}
|
|
24
21
|
catch (err) {
|
|
@@ -4,11 +4,8 @@ exports.resetSessionAll = exports.resetSession = void 0;
|
|
|
4
4
|
async function resetSession(browser, page) {
|
|
5
5
|
const context = browser.contexts()[0];
|
|
6
6
|
await context.clearCookies();
|
|
7
|
-
await page.evaluate(() => {
|
|
8
|
-
localStorage.clear();
|
|
9
|
-
sessionStorage.clear();
|
|
10
|
-
});
|
|
11
7
|
await page.reload();
|
|
8
|
+
await page.waitForLoadState('domcontentloaded');
|
|
12
9
|
await page.goto('/');
|
|
13
10
|
}
|
|
14
11
|
exports.resetSession = resetSession;
|