@camunda/e2e-test-suite 0.0.931 → 0.0.933

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.
@@ -3,8 +3,8 @@ declare class OptimizeDashboardPage {
3
3
  private page;
4
4
  readonly filterTable: Locator;
5
5
  constructor(page: Page);
6
- clickFilterTable(): Promise<void>;
7
- fillFilterTable(processName: string): Promise<void>;
6
+ clickFilterTable(timeout?: number): Promise<void>;
7
+ fillFilterTable(processName: string, timeout?: number): Promise<void>;
8
8
  processLinkAssertion(processName: string, maxRetries: number, retryDelay?: number): Promise<void>;
9
9
  processOwnerNameAssertion(processName: string, userEmail: string): Promise<void>;
10
10
  }
@@ -9,11 +9,11 @@ class OptimizeDashboardPage {
9
9
  this.page = page;
10
10
  this.filterTable = page.getByPlaceholder('Filter table');
11
11
  }
12
- async clickFilterTable() {
13
- await this.filterTable.click({ timeout: 120000 });
12
+ async clickFilterTable(timeout = 120000) {
13
+ await this.filterTable.click({ timeout });
14
14
  }
15
- async fillFilterTable(processName) {
16
- await this.filterTable.fill(processName, { timeout: 60000 });
15
+ async fillFilterTable(processName, timeout = 60000) {
16
+ await this.filterTable.fill(processName, { timeout });
17
17
  await this.filterTable.press('Enter');
18
18
  }
19
19
  async processLinkAssertion(processName, maxRetries, retryDelay = 60000) {
@@ -39,26 +39,40 @@ class OptimizeDashboardPage {
39
39
  async processOwnerNameAssertion(processName, userEmail) {
40
40
  // Optimize's Process Overview only refreshes its owner data on a page
41
41
  // reload (it does not poll in the background), so a long per-attempt
42
- // assertion timeout just idles against a stale DOM. Poll more frequently
43
- // instead: a short assertion timeout (enough for the table to render after
44
- // reload) plus a shorter delay lets us reload roughly every ~55s and catch
45
- // a slow owner import sooner. The total budget (~23 min) stays safely under
46
- // the test timeout so a genuine failure surfaces as this clean error rather
47
- // than an opaque "page closed" test-timeout.
48
- const maxRetries = 25;
42
+ // assertion timeout just idles against a stale DOM. Poll frequently
43
+ // instead: a short assertion timeout (enough for the table to render) plus
44
+ // a short delay lets us reload roughly every ~45s and catch a slow owner
45
+ // import sooner.
46
+ //
47
+ // The reload also clears the "Filter table" search that
48
+ // processLinkAssertion applied, so every attempt re-applies it — otherwise
49
+ // attempts 2..n search the full, paginated org-wide process list and the
50
+ // row can be off-screen entirely. Filter waits are bounded per attempt so
51
+ // one slow render cannot consume the whole budget.
52
+ //
53
+ // Owner assignment is asynchronous (Optimize assigns the deploying Web
54
+ // Modeler user once the deployment is imported) and on a loaded nightly
55
+ // org it can lag well past 20 minutes, so the loop keeps polling until a
56
+ // wall-clock deadline. The deadline (not just the attempt count) is what
57
+ // keeps the total under the test.slow() timeout, so a genuine failure
58
+ // surfaces as this clean error rather than an opaque test-timeout.
59
+ const maxRetries = 32;
49
60
  const retryDelay = 25000;
61
+ const deadline = Date.now() + 25 * 60 * 1000;
50
62
  const localPart = userEmail.split('@')[0];
51
63
  const uuid = localPart.replace('qa-user-', '');
52
64
  const result = !uuid ? 'QA Camunda' : `QA User ${uuid}`;
53
65
  for (let attempt = 0; attempt < maxRetries; attempt++) {
54
66
  try {
67
+ await this.clickFilterTable(30000);
68
+ await this.fillFilterTable(processName, 15000);
55
69
  await (0, test_1.expect)(this.page.getByRole('row', {
56
70
  name: `${processName}\nProcess\n\t${result}`,
57
71
  })).toBeVisible({ timeout: 20000 });
58
72
  return;
59
73
  }
60
74
  catch (error) {
61
- if (attempt < maxRetries - 1) {
75
+ if (attempt < maxRetries - 1 && Date.now() < deadline) {
62
76
  console.warn(`Attempt ${attempt + 1} failed for asserting owner name ${result} assertion for ${processName} in Optimize.. Retrying...`);
63
77
  try {
64
78
  await this.page.reload();
@@ -69,7 +83,7 @@ class OptimizeDashboardPage {
69
83
  await new Promise((resolve) => setTimeout(resolve, retryDelay));
70
84
  }
71
85
  else {
72
- throw new Error(`Owner name ${result} assertion for ${processName} failed after ${maxRetries} attempts`);
86
+ throw new Error(`Owner name ${result} assertion for ${processName} failed after ${attempt + 1} attempts`);
73
87
  }
74
88
  }
75
89
  }
@@ -28,6 +28,7 @@ declare class IdpCreatePage {
28
28
  readonly selectUnstructuredDataExtraction: Locator;
29
29
  readonly selectStructuredDataExtraction: Locator;
30
30
  readonly extractionInProgressNotification: Locator;
31
+ readonly extractionFailureIndicator: Locator;
31
32
  readonly structured_FieldsTab: Locator;
32
33
  readonly structured_TablesTab: Locator;
33
34
  readonly structured_CheckboxSelectAllFields: Locator;
@@ -42,6 +43,12 @@ declare class IdpCreatePage {
42
43
  readonly structured_PublishTemplateToProjectButton: Locator;
43
44
  readonly structured_SuccessfullPublishNotification: Locator;
44
45
  constructor(page: Page);
46
+ /**
47
+ * Surfaces a product-side extraction failure as the test error instead of
48
+ * letting the next assertion block for its full timeout and report only
49
+ * "locator timed out" — the on-screen error carries the actual cause.
50
+ */
51
+ private assertNoExtractionFailure;
45
52
  clickCreateIdpTemplateButton(): Promise<void>;
46
53
  fillIdpExtractionTemplateName(name: string): Promise<void>;
47
54
  clickCreateIdpExtractationTemplateButton(): Promise<void>;
@@ -32,6 +32,7 @@ class IdpCreatePage {
32
32
  selectUnstructuredDataExtraction;
33
33
  selectStructuredDataExtraction;
34
34
  extractionInProgressNotification;
35
+ extractionFailureIndicator;
35
36
  structured_FieldsTab;
36
37
  structured_TablesTab;
37
38
  structured_CheckboxSelectAllFields;
@@ -101,6 +102,15 @@ class IdpCreatePage {
101
102
  this.selectUnstructuredDataExtraction = page.getByText('Unstructured data extraction');
102
103
  this.selectStructuredDataExtraction = page.getByText('Structured form extraction');
103
104
  this.extractionInProgressNotification = page.getByText('Extracting document...');
105
+ // Terminal states the product renders when extraction itself fails: the
106
+ // error toast (unstructured) and the empty state (structured). Both persist,
107
+ // so they can be probed once the in-progress indicator clears.
108
+ this.extractionFailureIndicator = page
109
+ .getByRole('alert')
110
+ .filter({ has: page.getByText(/^(Error|Extraction failed)$/) })
111
+ .or(page.getByRole('heading', {
112
+ name: 'Extraction could not be completed',
113
+ }));
104
114
  this.structured_uploadFilesButton = page
105
115
  .getByRole('button', {
106
116
  name: /Drag and drop.*PDF.*upload/i,
@@ -141,6 +151,22 @@ class IdpCreatePage {
141
151
  page.getByText('Template published');
142
152
  this.providerDropdown = page.getByRole('combobox', { name: 'Provider' });
143
153
  }
154
+ /**
155
+ * Surfaces a product-side extraction failure as the test error instead of
156
+ * letting the next assertion block for its full timeout and report only
157
+ * "locator timed out" — the on-screen error carries the actual cause.
158
+ */
159
+ async assertNoExtractionFailure(step) {
160
+ const failure = this.extractionFailureIndicator.first();
161
+ const failed = await failure.isVisible().catch(() => false);
162
+ if (!failed) {
163
+ return;
164
+ }
165
+ const detail = (await failure.innerText().catch(() => ''))
166
+ .replace(/\s+/g, ' ')
167
+ .trim();
168
+ throw new Error(`${step} failed in the product: ${detail}`);
169
+ }
144
170
  async clickCreateIdpTemplateButton() {
145
171
  await this.createIdpTemplateButton.click({ timeout: 60000 });
146
172
  }
@@ -192,12 +218,19 @@ class IdpCreatePage {
192
218
  await (0, test_1.expect)(this.page.getByText('Extracting..')).not.toBeVisible({
193
219
  timeout: 300000,
194
220
  });
221
+ await this.assertNoExtractionFailure('Document extraction');
195
222
  await (0, test_1.expect)(this.unstructured_saveAsTestCaseButton).toBeVisible({
196
223
  timeout: 300000,
197
224
  });
198
- await (0, test_1.expect)(this.unstructured_saveAsTestCaseButton).toBeEnabled({
199
- timeout: 300000,
200
- });
225
+ try {
226
+ await (0, test_1.expect)(this.unstructured_saveAsTestCaseButton).toBeEnabled({
227
+ timeout: 300000,
228
+ });
229
+ }
230
+ catch (error) {
231
+ await this.assertNoExtractionFailure('Document extraction');
232
+ throw error;
233
+ }
201
234
  }
202
235
  async clickSaveAsTestCaseButton() {
203
236
  await this.unstructured_saveAsTestCaseButton.click({ timeout: 60000 });
@@ -271,9 +304,16 @@ class IdpCreatePage {
271
304
  await (0, test_1.expect)(this.extractionInProgressNotification).not.toBeVisible({
272
305
  timeout: 300000,
273
306
  });
274
- await (0, test_1.expect)(this.structured_FieldsTab).toBeVisible({
275
- timeout: 300000,
276
- });
307
+ await this.assertNoExtractionFailure('Structured form extraction');
308
+ try {
309
+ await (0, test_1.expect)(this.structured_FieldsTab).toBeVisible({
310
+ timeout: 300000,
311
+ });
312
+ }
313
+ catch (error) {
314
+ await this.assertNoExtractionFailure('Structured form extraction');
315
+ throw error;
316
+ }
277
317
  await (0, test_1.expect)(this.structured_CheckboxSelectAllFields).toBeVisible({
278
318
  timeout: 60000,
279
319
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.931",
3
+ "version": "0.0.933",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",