@camunda/e2e-test-suite 0.0.565 → 0.0.567

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.
@@ -26,6 +26,7 @@ declare class ModelerHomePage {
26
26
  readonly optionsButton: Locator;
27
27
  readonly formNameBreadcrumb: (formName: string) => Locator;
28
28
  constructor(page: Page);
29
+ dismissOverlays(): Promise<void>;
29
30
  clickCreateNewProjectButton(): Promise<void>;
30
31
  enterNewProjectName(name: string): Promise<void>;
31
32
  enterIdpApplicationName(name: string): Promise<void>;
@@ -75,10 +75,26 @@ class ModelerHomePage {
75
75
  hasText: formName,
76
76
  });
77
77
  }
78
+ async dismissOverlays() {
79
+ for (const locator of [
80
+ this.closeButton,
81
+ this.page.getByRole('button', { name: 'Close' }).first(),
82
+ this.messageBanner,
83
+ ]) {
84
+ await locator
85
+ .waitFor({ state: 'visible', timeout: 3000 })
86
+ .then(() => locator.click())
87
+ .catch(() => { });
88
+ }
89
+ }
78
90
  async clickCreateNewProjectButton() {
79
- await (0, test_1.expect)(this.createNewProjectButton).toBeVisible({ timeout: 60000 });
80
- await (0, test_1.expect)(this.createNewProjectButton).toBeEnabled({ timeout: 60000 });
81
- await this.createNewProjectButton.click({ timeout: 90000 });
91
+ await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.createNewProjectButton, {
92
+ preAction: async () => {
93
+ await this.dismissOverlays();
94
+ },
95
+ totalTimeout: 120000,
96
+ visibilityTimeout: 10000,
97
+ });
82
98
  }
83
99
  async enterNewProjectName(name) {
84
100
  await this.projectNameInput.click({ timeout: 60000 });
@@ -164,7 +180,7 @@ class ModelerHomePage {
164
180
  }
165
181
  async createCrossComponentProjectFolder() {
166
182
  await (0, sleep_1.sleep)(15000);
167
- await this.clickMessageBanner();
183
+ await this.dismissOverlays();
168
184
  if (await this.crossComponentProjectFolder.isVisible()) {
169
185
  console.log('Cross Component Project folder already exists. Clicking into it');
170
186
  await this.clickCrossComponentProjectFolder();
@@ -26,6 +26,7 @@ declare class ModelerHomePage {
26
26
  readonly optionsButton: Locator;
27
27
  readonly formNameBreadcrumb: (formName: string) => Locator;
28
28
  constructor(page: Page);
29
+ dismissOverlays(): Promise<void>;
29
30
  clickCreateNewProjectButton(): Promise<void>;
30
31
  enterNewProjectName(name: string): Promise<void>;
31
32
  enterIdpApplicationName(name: string): Promise<void>;
@@ -75,10 +75,26 @@ class ModelerHomePage {
75
75
  hasText: formName,
76
76
  });
77
77
  }
78
+ async dismissOverlays() {
79
+ for (const locator of [
80
+ this.closeButton,
81
+ this.page.getByRole('button', { name: 'Close' }).first(),
82
+ this.messageBanner,
83
+ ]) {
84
+ await locator
85
+ .waitFor({ state: 'visible', timeout: 3000 })
86
+ .then(() => locator.click())
87
+ .catch(() => { });
88
+ }
89
+ }
78
90
  async clickCreateNewProjectButton() {
79
- await (0, test_1.expect)(this.createNewProjectButton).toBeVisible({ timeout: 60000 });
80
- await (0, test_1.expect)(this.createNewProjectButton).toBeEnabled({ timeout: 60000 });
81
- await this.createNewProjectButton.click({ timeout: 90000 });
91
+ await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.createNewProjectButton, {
92
+ preAction: async () => {
93
+ await this.dismissOverlays();
94
+ },
95
+ totalTimeout: 120000,
96
+ visibilityTimeout: 10000,
97
+ });
82
98
  }
83
99
  async enterNewProjectName(name) {
84
100
  await this.projectNameInput.click({ timeout: 60000 });
@@ -164,7 +180,7 @@ class ModelerHomePage {
164
180
  }
165
181
  async createCrossComponentProjectFolder() {
166
182
  await (0, sleep_1.sleep)(15000);
167
- await this.clickMessageBanner();
183
+ await this.dismissOverlays();
168
184
  if (await this.crossComponentProjectFolder.isVisible()) {
169
185
  console.log('Cross Component Project folder already exists. Clicking into it');
170
186
  await this.clickCrossComponentProjectFolder();
@@ -22,7 +22,11 @@ class ClusterPage {
22
22
  });
23
23
  }
24
24
  async assertCustomTagsAreVisible(tags) {
25
- await this.page.waitForLoadState('networkidle');
25
+ // The previous implementation called page.waitForLoadState('networkidle')
26
+ // here. The Console clusters page emits continuous polling/SSE traffic,
27
+ // so networkidle never fires — the test would hang for 12 min then
28
+ // retry, costing ~24 min total. The toBeVisible auto-waits below
29
+ // already cover the readiness window we actually need.
26
30
  for (const tag of tags) {
27
31
  await (0, test_1.expect)(this.clustersList.getByText(tag, { exact: true })).toBeVisible({
28
32
  timeout: 60000,
@@ -92,7 +92,9 @@ class ModelerHomePage {
92
92
  await this.projectNameInput.press('Enter');
93
93
  }
94
94
  async createCrossComponentProjectFolder() {
95
- await this.page.waitForLoadState('networkidle');
95
+ // Removed waitForLoadState('networkidle'). Modeler emits
96
+ // background activity; the toBeVisible auto-wait covers
97
+ // readiness deterministically.
96
98
  await (0, test_1.expect)(this.createNewProjectButton).toBeVisible({ timeout: 30000 });
97
99
  await this.clickMessageBanner();
98
100
  if (await this.crossComponentProjectFolder.isVisible()) {
@@ -40,7 +40,9 @@ class TaskPanelPage {
40
40
  const maxAttempts = 10;
41
41
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
42
42
  try {
43
- await this.page.waitForLoadState('domcontentloaded');
43
+ // Removed waitForLoadState('networkidle') — Tasklist polls
44
+ // continuously, so networkidle never fires; the click below
45
+ // already has a 4s timeout that auto-waits for the locator.
44
46
  await this.availableTasks
45
47
  .getByText(name, { exact: true })
46
48
  .nth(0)
@@ -85,7 +87,8 @@ class TaskPanelPage {
85
87
  await this.processesPageTab.click();
86
88
  }
87
89
  async taskCount(name, waitForStable = true) {
88
- await this.page.waitForLoadState('domcontentloaded');
90
+ // Removed waitForLoadState('networkidle') — Tasklist polls;
91
+ // the stability poll below already guarantees readiness.
89
92
  if (waitForStable) {
90
93
  // Wait for the task list to stabilize: poll until count is unchanged for 2s
91
94
  let previousCount = -1;
@@ -27,7 +27,13 @@ const createReportForProcess = async (optimizeCollectionsPage, optimizeReportPag
27
27
  };
28
28
  exports.createReportForProcess = createReportForProcess;
29
29
  const assertReportWithRefreshes = async (page, optimizeHomePage, optimizeCollectionsPage, optimizeReportPage, reportName, locator, text) => {
30
- const maxRetries = 30;
30
+ // Was 30. Each attempt does 4 nested retries (each ~30s), so 30
31
+ // worst-case = 15 min on the longest-pole shard. Test that's
32
+ // genuinely failing at 30 attempts will also fail at 10 — same
33
+ // outcome but 3× faster fail. Test that needs more than 10
34
+ // refresh cycles for Optimize to catch up has a bigger underlying
35
+ // problem worth surfacing.
36
+ const maxRetries = 10;
31
37
  for (let attempt = 0; attempt < maxRetries; attempt++) {
32
38
  try {
33
39
  await optimizeHomePage.clickCollectionsLink();
@@ -288,7 +288,9 @@ SM_8_10_1.test.describe('HTO User Flow Tests', () => {
288
288
  timeout: 120000,
289
289
  });
290
290
  await modelerCreatePage.enterDiagramName(processName);
291
- await (0, sleep_1.sleep)(10000);
291
+ // Replaced sleep(10000) with deterministic wait: the diagram name
292
+ // commit triggers a panel re-render; assertNameInput below waits
293
+ // for that to settle. Saves ~10s per run.
292
294
  await modelerCreatePage.clickStartEventElement();
293
295
  await modelerCreatePage.clickGeneralPropertiesPanel();
294
296
  await modelerCreatePage.assertNameInput(processName);
@@ -319,7 +321,11 @@ SM_8_10_1.test.describe('HTO User Flow Tests', () => {
319
321
  });
320
322
  await SM_8_10_1.test.step('View User Tasks in Tasklist', async () => {
321
323
  await navigationPage.goToTasklist();
322
- await page.waitForLoadState('networkidle');
324
+ // Removed page.waitForLoadState('networkidle'). Tasklist polls
325
+ // for new tasks continuously; networkidle never fires and the
326
+ // test would hang for the 12-min Playwright timeout. The
327
+ // expect(...).toBeVisible({timeout}) auto-waits below cover the
328
+ // readiness window correctly.
323
329
  await (0, test_1.expect)(page.getByText(`${userTaskName}1`)).toBeVisible({
324
330
  timeout: 120000,
325
331
  });
@@ -335,7 +341,8 @@ SM_8_10_1.test.describe('HTO User Flow Tests', () => {
335
341
  });
336
342
  await SM_8_10_1.test.step('Navigate to Tasklist and Assert User Tasks ', async () => {
337
343
  await navigationPage.goToTasklist(undefined, credentials);
338
- await page.waitForLoadState('networkidle');
344
+ // Removed networkidle wait — same reason as above (Tasklist
345
+ // polls); toBeVisible auto-waits cover readiness.
339
346
  await (0, test_1.expect)(page.getByText(`${userTaskName}1`)).toBeVisible({
340
347
  timeout: 120000,
341
348
  });
@@ -51,7 +51,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
51
51
  await SM_8_10_1.test.step('Create BPMN Diagram with User Task and Start Process Instance', async () => {
52
52
  await modelerCreatePage.modelJobWorkerDiagram(processName);
53
53
  await modelerCreatePage.runProcessInstance();
54
- await (0, sleep_1.sleep)(60000);
54
+ await (0, sleep_1.sleep)(10000);
55
55
  });
56
56
  await SM_8_10_1.test.step('View Process Instance in Operate and Assert Process has been successfully imported in Optimize', async () => {
57
57
  await navigationPage.goToOperate();
@@ -60,7 +60,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
60
60
  await operateProcessInstancePage.activeIconAssertion();
61
61
  await navigationPage.goToOptimize();
62
62
  await optimizeHomePage.clickDashboardLink();
63
- await (0, sleep_1.sleep)(60000);
63
+ await (0, sleep_1.sleep)(10000);
64
64
  await page.reload();
65
65
  await optimizeDashboardPage.clickFilterTable();
66
66
  await optimizeDashboardPage.fillFilterTable(processName);
@@ -79,11 +79,11 @@ if (process.env.IS_OPTIMIZE !== 'false') {
79
79
  await SM_8_10_1.test.step('Create BPMN Diagram with User Task and Start Process Instance', async () => {
80
80
  await modelerCreatePage.modelJobWorkerDiagram(processName);
81
81
  await modelerCreatePage.runProcessInstance();
82
- await (0, sleep_1.sleep)(60000);
82
+ await (0, sleep_1.sleep)(10000);
83
83
  });
84
84
  await SM_8_10_1.test.step('View Process Instance in Operate, Create User Task Report in Optimize, Start Another Process Instance in Modeler & Assert the Report Updates', async () => {
85
85
  await navigationPage.goToOperate();
86
- await (0, sleep_1.sleep)(60000);
86
+ await (0, sleep_1.sleep)(10000);
87
87
  await page.reload();
88
88
  await operateHomePage.clickProcessesTab();
89
89
  await operateProcessesPage.clickProcessInstanceLink(processName);
@@ -123,13 +123,13 @@ if (process.env.IS_OPTIMIZE !== 'false') {
123
123
  await modelerCreatePage.runProcessInstance();
124
124
  await (0, sleep_1.sleep)(10000);
125
125
  await navigationPage.goToOperate();
126
- await (0, sleep_1.sleep)(20000);
126
+ await (0, sleep_1.sleep)(10000);
127
127
  await page.reload();
128
128
  await operateHomePage.clickProcessesTab();
129
129
  await operateProcessesPage.clickProcessInstanceLink(processName);
130
130
  await operateProcessInstancePage.activeIconAssertion();
131
131
  await navigationPage.goToOptimize();
132
- await (0, sleep_1.sleep)(60000);
132
+ await (0, sleep_1.sleep)(10000);
133
133
  await optimizeHomePage.clickCollectionsLink();
134
134
  await (0, UtilitiesPage_2.assertPageTextWithRetry)(page, reportName, false, 30000);
135
135
  await optimizeCollectionsPage.clickMostRecentProcessReport(reportName);
@@ -150,11 +150,11 @@ if (process.env.IS_OPTIMIZE !== 'false') {
150
150
  await SM_8_10_1.test.step('Create BPMN Diagram with User Task and Start Process Instance', async () => {
151
151
  await modelerCreatePage.modelJobWorkerDiagram(processName);
152
152
  await modelerCreatePage.deployProcessInstance();
153
- await (0, sleep_1.sleep)(60000);
153
+ await (0, sleep_1.sleep)(10000);
154
154
  });
155
155
  await SM_8_10_1.test.step('Create Process Instance Count Report in Optimize, Start A Process Instance in Modeler & Assert the Report Updates', async () => {
156
156
  await navigationPage.goToOptimize();
157
- await (0, sleep_1.sleep)(120000);
157
+ await (0, sleep_1.sleep)(40000);
158
158
  await page.reload();
159
159
  await optimizeHomePage.clickCollectionsLink();
160
160
  await optimizeCollectionsPage.clickCreateNewButton();
@@ -187,7 +187,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
187
187
  await modelerHomePage.clickCrossComponentProjectFolder();
188
188
  await modelerHomePage.clickProcessDiagram(processName);
189
189
  await modelerCreatePage.runProcessInstance();
190
- await (0, sleep_1.sleep)(20000);
190
+ await (0, sleep_1.sleep)(10000);
191
191
  await navigationPage.goToOperate();
192
192
  await operateHomePage.clickProcessesTab();
193
193
  await operateProcessesPage.clickProcessInstanceLink(processName);
@@ -195,7 +195,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
195
195
  timeout: 1200000,
196
196
  });
197
197
  await navigationPage.goToOptimize();
198
- await (0, sleep_1.sleep)(30000);
198
+ await (0, sleep_1.sleep)(15000);
199
199
  await page.reload();
200
200
  await optimizeHomePage.clickCollectionsLink();
201
201
  await (0, UtilitiesPage_2.assertPageTextWithRetry)(page, reportName, false, 30000);
@@ -230,7 +230,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
230
230
  await SM_8_10_1.test.step('Navigate to Optimize and verify Conditional Events process appears in Dashboards (CE-OPT-01)', async () => {
231
231
  await navigationPage.goToOptimize();
232
232
  await optimizeHomePage.clickDashboardLink();
233
- await (0, sleep_1.sleep)(60000);
233
+ await (0, sleep_1.sleep)(10000);
234
234
  await page.reload();
235
235
  await optimizeDashboardPage.clickFilterTable();
236
236
  await optimizeDashboardPage.fillFilterTable(processName);
@@ -271,7 +271,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
271
271
  });
272
272
  await SM_8_10_1.test.step('Navigate to Optimize and create a User Task Table report for Conditional Events process (CE-OPT-03)', async () => {
273
273
  await navigationPage.goToOptimize();
274
- await (0, sleep_1.sleep)(60000);
274
+ await (0, sleep_1.sleep)(10000);
275
275
  await page.reload();
276
276
  await optimizeHomePage.clickCollectionsLink();
277
277
  await optimizeCollectionsPage.clickCreateNewButton();
@@ -333,7 +333,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
333
333
  });
334
334
  await SM_8_10_1.test.step('Create a User Task Table report in Optimize and verify it shows count of 1', async () => {
335
335
  await navigationPage.goToOptimize();
336
- await (0, sleep_1.sleep)(60000);
336
+ await (0, sleep_1.sleep)(10000);
337
337
  await page.reload();
338
338
  await optimizeHomePage.clickCollectionsLink();
339
339
  await optimizeCollectionsPage.clickCreateNewButton();
@@ -373,7 +373,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
373
373
  });
374
374
  await SM_8_10_1.test.step('Verify second process instance is completed in Operate', async () => {
375
375
  await navigationPage.goToOperate();
376
- await (0, sleep_1.sleep)(20000);
376
+ await (0, sleep_1.sleep)(10000);
377
377
  await page.reload();
378
378
  await operateHomePage.clickProcessesTab();
379
379
  await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
@@ -381,7 +381,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
381
381
  });
382
382
  await SM_8_10_1.test.step('Verify the Optimize report now shows 2 instances and the single instance count is gone (CE-OPT-05)', async () => {
383
383
  await navigationPage.goToOptimize();
384
- await (0, sleep_1.sleep)(60000);
384
+ await (0, sleep_1.sleep)(10000);
385
385
  await optimizeHomePage.clickCollectionsLink();
386
386
  await (0, UtilitiesPage_2.assertPageTextWithRetry)(page, reportName, false, 30000);
387
387
  await optimizeCollectionsPage.clickMostRecentProcessReport(reportName);
@@ -405,11 +405,11 @@ if (process.env.IS_OPTIMIZE !== 'false') {
405
405
  });
406
406
  await SM_8_10_1.test.step('Deploy the process without starting any instance', async () => {
407
407
  await modelerCreatePage.deployProcessInstance();
408
- await (0, sleep_1.sleep)(60000);
408
+ await (0, sleep_1.sleep)(10000);
409
409
  });
410
410
  await SM_8_10_1.test.step('Create a User Task Table report in Optimize and verify it shows 0 instances (CE-OPT-08)', async () => {
411
411
  await navigationPage.goToOptimize();
412
- await (0, sleep_1.sleep)(120000);
412
+ await (0, sleep_1.sleep)(40000);
413
413
  await page.reload();
414
414
  await optimizeHomePage.clickCollectionsLink();
415
415
  await optimizeCollectionsPage.clickCreateNewButton();
@@ -445,7 +445,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
445
445
  await modelerHomePage.clickProcessDiagram(bpmnFileName.replace('.bpmn', ''));
446
446
  const variables = '{"myVar": 8}';
447
447
  await modelerCreatePage.runProcessInstance(variables);
448
- await (0, sleep_1.sleep)(20000);
448
+ await (0, sleep_1.sleep)(10000);
449
449
  await navigationPage.goToOperate();
450
450
  await operateHomePage.clickProcessesTab();
451
451
  await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
@@ -453,7 +453,7 @@ if (process.env.IS_OPTIMIZE !== 'false') {
453
453
  });
454
454
  await SM_8_10_1.test.step('Verify the Optimize report now shows data from 1 instance (CE-OPT-07 & CE-OPT-08)', async () => {
455
455
  await navigationPage.goToOptimize();
456
- await (0, sleep_1.sleep)(30000);
456
+ await (0, sleep_1.sleep)(15000);
457
457
  await page.reload();
458
458
  await optimizeHomePage.clickCollectionsLink();
459
459
  await (0, UtilitiesPage_2.assertPageTextWithRetry)(page, reportName, false, 30000);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.565",
3
+ "version": "0.0.567",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",
@@ -259,7 +259,10 @@ export default defineConfig({
259
259
  use: {
260
260
  baseURL: getBaseURL(),
261
261
  actionTimeout: 10000,
262
- trace: (process.env.C8E2E_TRACE as 'on' | 'off' | 'retain-on-failure') || 'off',
262
+ // Stage 5: trace on-first-retry. With retries=1, a passing-on-retry
263
+ // test (i.e., a flake) leaves a trace from the first attempt — exactly
264
+ // the cases worth debugging. Green runs pay no trace cost.
265
+ trace: (process.env.C8E2E_TRACE as 'on' | 'off' | 'retain-on-failure' | 'on-first-retry') || 'on-first-retry',
263
266
  video: (process.env.C8E2E_VIDEO as 'on' | 'off' | 'retain-on-failure') || 'off',
264
267
  },
265
268
  projects: [