@camunda/e2e-test-suite 0.0.1279 → 0.0.1281

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.
@@ -227,7 +227,9 @@ declare class ModelerCreatePage {
227
227
  retries?: number;
228
228
  settleMs?: number;
229
229
  openPanel?: boolean;
230
+ elementId?: string;
230
231
  }): Promise<void>;
232
+ private ensureElementSelected;
231
233
  clickCloseDetailsPanel(): Promise<void>;
232
234
  clickOpenDetailsPanel(): Promise<void>;
233
235
  }
@@ -1843,6 +1843,9 @@ class ModelerCreatePage {
1843
1843
  if (openPanel) {
1844
1844
  await this.clickOpenDetailsPanel();
1845
1845
  }
1846
+ if (options?.elementId) {
1847
+ await this.ensureElementSelected(elementToClick, options.elementId);
1848
+ }
1846
1849
  await this.openAuthenticationPanel();
1847
1850
  let lastError;
1848
1851
  for (let attempt = 1; attempt <= retries; attempt++) {
@@ -1856,12 +1859,37 @@ class ModelerCreatePage {
1856
1859
  }
1857
1860
  catch (err) {
1858
1861
  lastError = err;
1862
+ // The stale-selection restore can land after ensureElementSelected
1863
+ // has already confirmed the target, detaching the field mid-fill.
1864
+ if (options?.elementId) {
1865
+ await this.ensureElementSelected(elementToClick, options.elementId);
1866
+ }
1859
1867
  await this.openAuthenticationPanel();
1860
1868
  await (0, sleep_1.sleep)(settleMs);
1861
1869
  }
1862
1870
  }
1863
1871
  throw new Error(`Failed to set OAuth 2.0 token endpoint after ${retries} attempt(s). Last error: ${String(lastError)}`);
1864
1872
  }
1873
+ // After a page reload, reopening the Details panel can restore the
1874
+ // selection from before the reload (and scroll the canvas to it), so the
1875
+ // panel shows a different element than the one just clicked. The target may
1876
+ // then sit under the panel, so re-select it with a DOM click that the panel
1877
+ // cannot intercept.
1878
+ async ensureElementSelected(element, elementId) {
1879
+ for (let attempt = 1; attempt <= 3; attempt++) {
1880
+ await (0, sleep_1.sleep)(1000);
1881
+ const selectedId = await this.elemendIdInput
1882
+ .inputValue({ timeout: 10000 })
1883
+ .catch(() => '');
1884
+ if (selectedId === elementId) {
1885
+ return;
1886
+ }
1887
+ await element.dispatchEvent('click');
1888
+ }
1889
+ await (0, test_1.expect)(this.elemendIdInput).toHaveValue(elementId, {
1890
+ timeout: 10000,
1891
+ });
1892
+ }
1865
1893
  async clickCloseDetailsPanel() {
1866
1894
  await this.closeDetailsPanel.click({ timeout: 30000 });
1867
1895
  }
@@ -566,10 +566,10 @@ async function modelAndRunConnectorsDocHandlingDiagram(modelerCreatePage, modele
566
566
  // closed before their shape can be clicked and reopened afterwards.
567
567
  await (0, sleep_1.sleep)(2000);
568
568
  await modelerCreatePage.clickCloseDetailsPanel();
569
- await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_0iyt4gv'), endpoint, { openPanel: true });
569
+ await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_0iyt4gv'), endpoint, { openPanel: true, elementId: 'Activity_0iyt4gv' });
570
570
  await (0, sleep_1.sleep)(2000);
571
571
  await modelerCreatePage.clickCloseDetailsPanel();
572
- await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_1oiegam'), endpoint, { openPanel: true });
572
+ await modelerCreatePage.setOAuthTokenEndpoint(restTaskHit('Activity_1oiegam'), endpoint, { openPanel: true, elementId: 'Activity_1oiegam' });
573
573
  await (0, sleep_1.sleep)(2000);
574
574
  await modelerCreatePage.runProcessInstance('', tenant);
575
575
  }
@@ -16,26 +16,20 @@ class ClusterDetailsPage {
16
16
  const matchesLink = (url) => typeof link === 'string'
17
17
  ? url.href.startsWith(link)
18
18
  : link.test(url.href);
19
- // Serve a stub document only when the external site itself is
20
- // unreachable, so the popup still commits the URL Console navigated to.
19
+ // Always serve a stub document: the popup only has to commit the URL
20
+ // Console navigated to, and Playwright withholds the "popup" event until
21
+ // this handler resolves, so fetching the real site would tie the popup
22
+ // wait to the external site's latency.
21
23
  const handler = async (route) => {
22
24
  if (route.request().resourceType() !== 'document') {
23
25
  await route.continue();
24
26
  return;
25
27
  }
26
- try {
27
- const response = await route.fetch({ timeout: 30000 });
28
- await route.fulfill({ response });
29
- }
30
- catch (error) {
31
- const url = route.request().url();
32
- console.warn(`External link ${url} unreachable, stubbing: ${error}`);
33
- await route.fulfill({
34
- status: 200,
35
- contentType: 'text/html',
36
- body: '<html><body></body></html>',
37
- });
38
- }
28
+ await route.fulfill({
29
+ status: 200,
30
+ contentType: 'text/html',
31
+ body: '<html><body></body></html>',
32
+ });
39
33
  };
40
34
  await context.route(matchesLink, handler);
41
35
  try {
@@ -49,6 +49,31 @@ async function createCancellationBatch(api, processId) {
49
49
  (0, assertions_1.assertRequiredFields)(json, ['batchOperationKey']);
50
50
  return String(json.batchOperationKey);
51
51
  }
52
+ /**
53
+ * Suspends a batch that may already have run to completion.
54
+ *
55
+ * The engine drops a finished batch from its state, so suspending one is
56
+ * rejected with 404 NOT_FOUND rather than 409. A 404 is accepted only after
57
+ * the search store confirms the batch finished, so a batch that never existed
58
+ * still fails.
59
+ */
60
+ async function suspendBatch(api, batchKey) {
61
+ const suspend = await api.post('/batch-operations/{batchOperationKey}/suspension', { params: { batchOperationKey: batchKey }, body: {}, tenant: 'none' });
62
+ await (0, assertions_1.assertStatusIn)(suspend, [204, 404, 409], 'a batch that has already finished cannot be suspended');
63
+ if (suspend.status() === 404) {
64
+ const body = (await suspend.json());
65
+ (0, test_1.expect)(String(body.detail)).toContain(`Expected to suspend a batch operation with key '${batchKey}', but no such batch operation was found`);
66
+ await (0, eventually_1.eventually)(async () => {
67
+ const lookup = await api.get('/batch-operations/{batchOperationKey}', {
68
+ params: { batchOperationKey: batchKey },
69
+ tenant: 'none',
70
+ });
71
+ const batch = (await (0, assertions_1.assertOk)(lookup));
72
+ (0, test_1.expect)(['COMPLETED', 'PARTIALLY_COMPLETED']).toContain(batch.state);
73
+ });
74
+ }
75
+ return suspend;
76
+ }
52
77
  api_1.test.describe('Batch operations', () => {
53
78
  (0, api_1.test)('creates a cancellation batch and cancels its instances', async ({ api, resources, }) => {
54
79
  const { processId, instanceKeys } = await seedInstances(api, resources, 3);
@@ -129,8 +154,7 @@ api_1.test.describe('Batch operations', () => {
129
154
  // A larger batch keeps the operation in flight long enough to suspend.
130
155
  const { processId } = await seedInstances(api, resources, 5);
131
156
  const batchKey = await createCancellationBatch(api, processId);
132
- const suspend = await api.post('/batch-operations/{batchOperationKey}/suspension', { params: { batchOperationKey: batchKey }, body: {}, tenant: 'none' });
133
- await (0, assertions_1.assertStatusIn)(suspend, [204, 409], 'a batch that has already finished cannot be suspended');
157
+ const suspend = await suspendBatch(api, batchKey);
134
158
  if (suspend.status() === 204) {
135
159
  await (0, eventually_1.eventually)(async () => {
136
160
  const lookup = await api.get('/batch-operations/{batchOperationKey}', {
@@ -155,8 +179,7 @@ api_1.test.describe('Batch operations', () => {
155
179
  (0, api_1.test)('cancels a suspended batch', async ({ api, resources }) => {
156
180
  const { processId } = await seedInstances(api, resources, 5);
157
181
  const batchKey = await createCancellationBatch(api, processId);
158
- const suspend = await api.post('/batch-operations/{batchOperationKey}/suspension', { params: { batchOperationKey: batchKey }, body: {}, tenant: 'none' });
159
- await (0, assertions_1.assertStatusIn)(suspend, [204, 409], 'a batch that has already finished cannot be suspended');
182
+ const suspend = await suspendBatch(api, batchKey);
160
183
  if (suspend.status() === 204) {
161
184
  const cancel = await api.post('/batch-operations/{batchOperationKey}/cancellation', { params: { batchOperationKey: batchKey }, body: {}, tenant: 'none' });
162
185
  await (0, assertions_1.assertStatusIn)(cancel, [204], 'cancellation is acknowledged');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1279",
3
+ "version": "0.0.1281",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",