@camunda/e2e-test-suite 0.0.479 → 0.0.481

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.
@@ -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 winner = await Promise.race([
29
- this.usernameInput.waitFor({ state: 'visible' }).then(() => 'default'),
30
- this.coreUsernameInput.waitFor({ state: 'visible' }).then(() => 'core'),
31
- this.keycloakBanner.waitFor({ state: 'visible' }).then(() => 'keycloak'),
32
- ]);
33
- this.useCore = winner === 'core';
34
- this.useKeycloak = winner === 'keycloak';
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, sleep_1.sleep)(1000);
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 (0, sleep_1.sleep)(10000);
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, sleep_1.sleep)(5000);
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 (0, sleep_1.sleep)(10000);
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, sleep_1.sleep)(1000);
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
- await Promise.race([
172
- this.messageBanner.click(),
173
- this.closeButton.click(),
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
- try {
81
- await (0, test_1.expect)(loginPage.usernameInput).toBeVisible({ timeout: 5000 });
80
+ const loginVisible = await loginPage.usernameInput.isVisible();
81
+ if (loginVisible) {
82
82
  await loginPage.login(username, password);
83
83
  }
84
- catch (error) {
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)(5000);
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 (0, sleep_1.sleep)(10000);
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 (0, sleep_1.sleep)(10000);
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 (0, sleep_1.sleep)(10000);
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 (0, sleep_1.sleep)(10000);
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
- return Promise.race([
126
- this.incidentIcon.waitFor({ timeout: 90000 }).then(() => 'incident'),
127
- this.activeIcon.waitFor({ timeout: 90000 }).then(() => 'active'),
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
- return Promise.race([
132
- this.incidentIcon.waitFor({ timeout: 90000 }).then(() => 'incident'),
133
- this.completedIcon.waitFor({ timeout: 90000 }).then(() => 'completed'),
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 (0, sleep_1.sleep)(5000);
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 (0, sleep_1.sleep)(2000);
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 (0, sleep_1.sleep)(2000);
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
- try {
30
- await this.modalCloseButton.click({ timeout: 60000 });
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
- try {
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
- try {
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: 60000,
109
+ timeout: 30000,
113
110
  });
114
- await (0, test_1.expect)(taskPanelPage.availableTasks.getByText(taskName, { exact: true }).first()).not.toBeVisible({ timeout: 60000 });
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 = 120000, notVisible, maxRetries = 3, clickLocator) {
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 = 120000, maxRetries = 3) {
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
- let retries = 1000; // big number as this can struggle when many processes are running at once
9
- while (retries > 0) {
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
- break;
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, 5000));
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
- let retries = 1000; // big number as this can struggle when many processes are running at once
33
- while (retries > 0) {
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
- break;
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;
@@ -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 Promise.race([
16
- item.waitFor({
17
- state: shouldBeVisible ? 'visible' : 'hidden',
18
- timeout: visibilityTimeout,
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.479",
3
+ "version": "0.0.481",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",