@camunda/e2e-test-suite 0.0.886 → 0.0.888

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.
@@ -32,6 +32,7 @@ declare class ModelerCreatePage {
32
32
  readonly createTask: Locator;
33
33
  readonly createEndEvent: Locator;
34
34
  readonly canvas: Locator;
35
+ readonly zoomOutButton: Locator;
35
36
  readonly endEventCanvas: Locator;
36
37
  readonly connectToOtherElementButton: Locator;
37
38
  readonly firstPlacedElement: Locator;
@@ -163,6 +164,8 @@ declare class ModelerCreatePage {
163
164
  clickDeploySubButtonWithRetry(clusterName: string): Promise<void>;
164
165
  clickCreateTask(): Promise<void>;
165
166
  clickCreateEndEvent(): Promise<void>;
167
+ fitElementIntoCanvas(element: Locator, margin?: number, maxZoomOutSteps?: number): Promise<void>;
168
+ clickShapeBelowContextPad(element: Locator): Promise<void>;
166
169
  clickCanvas(): Promise<void>;
167
170
  clickEndEventCanvas(): Promise<void>;
168
171
  clickConnectToOtherElementButton(): Promise<void>;
@@ -38,6 +38,7 @@ class ModelerCreatePage {
38
38
  createTask;
39
39
  createEndEvent;
40
40
  canvas;
41
+ zoomOutButton;
41
42
  endEventCanvas;
42
43
  connectToOtherElementButton;
43
44
  firstPlacedElement;
@@ -122,7 +123,11 @@ class ModelerCreatePage {
122
123
  name: 'Change element',
123
124
  exact: true,
124
125
  });
125
- this.userTaskOption = page.getByRole('option', { name: 'User task' });
126
+ // Anchor on the built-in entry's data-id: the popup also lists the
127
+ // project's deployed resources (`data-id="resources-replace-bpmnProcess-N"`)
128
+ // labelled with the diagram name, which makes a role+name match on
129
+ // 'User task' ambiguous as soon as such a diagram exists.
130
+ this.userTaskOption = page.locator('.djs-popup-results [data-id="replace-with-user-task"]');
126
131
  this.priorityInput = page.getByRole('textbox', { name: 'priority' });
127
132
  this.appendEndEventButton = page.getByRole('button', {
128
133
  name: 'Append end event',
@@ -159,10 +164,13 @@ class ModelerCreatePage {
159
164
  this.deploySubButton = page.locator('[data-test="deploy-action"]');
160
165
  this.cancelButton = page.getByRole('button', { name: 'Cancel' });
161
166
  this.restConnectorOption = page.locator('[data-id="replace.template-io.camunda.connectors.HttpJson.v2"]');
162
- this.webhookMessageStartEventConnectorOption = page.getByRole('listitem', {
163
- name: 'Webhook Message Start Event Connector',
164
- exact: true,
165
- });
167
+ // bpmn-js popup entries are `li[role="option"]` inside a `role="listbox"`,
168
+ // so getByRole('listitem') no longer matches. Their accessible name also
169
+ // includes the entry description, and three entries share the label
170
+ // ("GitHub …", "Slack …", plain "Webhook …"), so name matching is
171
+ // ambiguous. Anchor on the entry's data-id — the same selector the hub's
172
+ // own e2e suite uses (`.djs-popup-results [data-id="<entryId>"]`).
173
+ this.webhookMessageStartEventConnectorOption = page.locator('.djs-popup-results [data-id="replace.template-io.camunda.connectors.webhook.WebhookConnectorStartMessage.v1"]');
166
174
  this.webhookTab = page.getByRole('tab', { name: 'Webhook' });
167
175
  this.webhookIsActiveButton = page.getByRole('button', {
168
176
  name: 'Webhook is active in Test',
@@ -174,7 +182,8 @@ class ModelerCreatePage {
174
182
  .first();
175
183
  this.createTask = page.getByTitle('Create task');
176
184
  this.createEndEvent = page.getByTitle('Create end event');
177
- this.canvas = page.locator('rect').nth(1);
185
+ this.canvas = page.locator('.djs-container');
186
+ this.zoomOutButton = page.locator('[data-test="zoom-out"]');
178
187
  this.endEventCanvas = page.locator('[class="bjs-container"]');
179
188
  this.connectToOtherElementButton = page.getByRole('button', {
180
189
  name: 'Connect to other element',
@@ -197,9 +206,7 @@ class ModelerCreatePage {
197
206
  this.intermediateBoundaryEvent = page.getByRole('button', {
198
207
  name: 'Append intermediate/boundary',
199
208
  });
200
- this.intermediateWebhookConnectorOption = page.getByRole('listitem', {
201
- name: 'Webhook Intermediate Event',
202
- });
209
+ this.intermediateWebhookConnectorOption = page.locator('.djs-popup-results [data-id="replace.template-io.camunda.connectors.webhook.WebhookConnectorIntermediate.v1"]');
203
210
  this.correlationKeyPayloadInput = page.getByLabel('Correlation key (payload)');
204
211
  this.correlationKeyProcessInput = page.getByLabel('Correlation key (process)');
205
212
  this.form = page.locator('[class="fjs-container"]');
@@ -240,7 +247,7 @@ class ModelerCreatePage {
240
247
  this.secondPlacedGateway = page
241
248
  .locator('[data-element-id*="Gateway"]')
242
249
  .last();
243
- this.serviceTaskOption = page.getByRole('option', { name: 'Service task' });
250
+ this.serviceTaskOption = page.locator('.djs-popup-results [data-id="replace-with-service-task"]');
244
251
  this.taskDefinitionPanel = page.locator('[data-group-id="group-taskDefinition"]');
245
252
  this.jobTypeInput = page.getByRole('textbox', { name: /job type/i });
246
253
  this.playTab = page.getByRole('tab', {
@@ -283,10 +290,7 @@ class ModelerCreatePage {
283
290
  this.variableAssignmentValueTextboxThirdVariable = page.locator('#bio-properties-panel-StartEvent_1-output-2-source div');
284
291
  this.connectorsDocHandlingStartEventElement = page.locator('g:nth-child(5) > .djs-element > .djs-hit');
285
292
  this.detailsPanelToggle = page.locator('[data-test="details-panel-toggle"]');
286
- this.timerEventOption = page.getByRole('listitem', {
287
- name: 'Timer intermediate catch event',
288
- exact: true,
289
- });
293
+ this.timerEventOption = page.locator('.djs-popup-results [data-id="replace-with-timer-intermediate-catch"]');
290
294
  this.timerEventSettings = page.getByText(/^Timer$/).first();
291
295
  this.timerType = page.getByLabel('Type');
292
296
  this.timerValue = page.getByLabel('Value');
@@ -725,8 +729,45 @@ class ModelerCreatePage {
725
729
  async clickCreateEndEvent() {
726
730
  await this.createEndEvent.click({ timeout: 60000 });
727
731
  }
732
+ // The canvas does not scroll with the DOM, so an element the diagram has
733
+ // pushed past the canvas edge cannot be clicked at all — the hit test returns
734
+ // the canvas container (or the panel toggle bar beside it). Zoom out until
735
+ // the element and one element-width of margin fit inside the canvas.
736
+ async fitElementIntoCanvas(element, margin = 120, maxZoomOutSteps = 3) {
737
+ for (let step = 0; step < maxZoomOutSteps; step++) {
738
+ const canvasBox = await this.canvas.boundingBox();
739
+ const elementBox = await element.boundingBox();
740
+ if (canvasBox === null || elementBox === null) {
741
+ return;
742
+ }
743
+ const elementRightEdge = elementBox.x + elementBox.width + margin;
744
+ if (elementRightEdge <= canvasBox.x + canvasBox.width) {
745
+ return;
746
+ }
747
+ await this.zoomOutButton.click({ timeout: 30000 });
748
+ }
749
+ }
750
+ // A context pad is a fixed-size strip anchored to the top-right of its
751
+ // element, so once the diagram is zoomed out it can reach across the gap and
752
+ // cover the top of the next shape. Click the bottom edge of the target, below
753
+ // the strip, so a neighbour's open pad cannot swallow the click.
754
+ async clickShapeBelowContextPad(element) {
755
+ const box = await element.boundingBox();
756
+ if (box === null) {
757
+ await element.click({ timeout: 60000 });
758
+ return;
759
+ }
760
+ await element.click({
761
+ timeout: 60000,
762
+ position: { x: box.width / 2, y: box.height - 2 },
763
+ });
764
+ }
728
765
  async clickCanvas() {
729
- await this.canvas.click({ timeout: 60000 });
766
+ // Clicking the canvas centre lands on a shape (or an open create pad) as
767
+ // soon as the diagram has more than a couple of elements, and the click is
768
+ // then intercepted instead of clearing the selection. Click the empty
769
+ // gutter above the diagram and right of the palette instead.
770
+ await this.canvas.click({ timeout: 60000, position: { x: 150, y: 25 } });
730
771
  }
731
772
  async clickEndEventCanvas() {
732
773
  await this.endEventCanvas.click({ timeout: 60000 });
@@ -971,16 +1012,22 @@ class ModelerCreatePage {
971
1012
  }
972
1013
  async clickSecondPlacedGateway(userTaskId = '') {
973
1014
  try {
974
- await this.secondPlacedGateway.click({ timeout: 60000 });
1015
+ await this.clickShapeBelowContextPad(this.secondPlacedGateway);
975
1016
  }
976
1017
  catch (error) {
977
1018
  await this.page.reload();
978
1019
  await (0, sleep_1.sleep)(10000);
1020
+ // The reload resets the canvas viewbox to the origin, discarding the
1021
+ // auto-scroll that kept the right-most gateway on screen.
1022
+ await this.fitElementIntoCanvas(this.secondPlacedGateway);
1023
+ // Clear any selection the reload restored, so its context pad is closed
1024
+ // before the gateway is clicked.
1025
+ await this.clickCanvas();
979
1026
  if (userTaskId != '') {
980
1027
  await this.clickUserTask(userTaskId);
981
1028
  await this.clickConnectToOtherElementButton();
982
1029
  }
983
- await this.secondPlacedGateway.click({ timeout: 60000 });
1030
+ await this.clickShapeBelowContextPad(this.secondPlacedGateway);
984
1031
  }
985
1032
  }
986
1033
  async addParallelUserTasks(numberOfTasks, taskName) {
@@ -1027,6 +1074,7 @@ class ModelerCreatePage {
1027
1074
  await this.clickCanvas();
1028
1075
  await (0, sleep_1.sleep)(1000);
1029
1076
  }
1077
+ await this.fitElementIntoCanvas(this.secondPlacedGateway);
1030
1078
  await this.clickSecondPlacedGateway();
1031
1079
  }
1032
1080
  async clickServiceTaskOption() {
@@ -90,8 +90,12 @@ class ClusterDetailsPage {
90
90
  this.rbaDisableButton = page.getByRole('button', { name: 'Disable' });
91
91
  this.dialog = page.getByRole('dialog');
92
92
  this.deleteButton = page.getByRole('button', { name: 'Delete' });
93
- this.deleteSubButton = page.getByRole('button', {
94
- name: 'danger Delete',
93
+ // The danger button in Console's confirmation modals is now named just
94
+ // "Delete" (it used to expose "danger Delete"), so scope to the open
95
+ // dialog to keep it distinct from the per-row Delete buttons behind it.
96
+ this.deleteSubButton = this.dialog.getByRole('button', {
97
+ name: 'Delete',
98
+ exact: true,
95
99
  });
96
100
  this.createClientCredentialsDialog = page.getByRole('dialog', {
97
101
  name: 'Create new client credentials',
@@ -40,9 +40,10 @@ class ClusterSecretsPage {
40
40
  name: 'Delete',
41
41
  exact: true,
42
42
  });
43
- this.deleteConnectorSecretSubButton = page.getByRole('button', {
44
- name: 'danger Delete',
45
- });
43
+ // See ClusterDetailsPage: the modal's danger button is now named "Delete".
44
+ this.deleteConnectorSecretSubButton = page
45
+ .getByRole('dialog')
46
+ .getByRole('button', { name: 'Delete', exact: true });
46
47
  this.dialog = page.getByRole('dialog');
47
48
  this.importButton = page.getByRole('button', { name: 'Import', exact: true });
48
49
  this.fromFileButton = page.getByText('from File', { exact: true });
@@ -31,6 +31,7 @@ declare class ModelerCreatePage {
31
31
  readonly createTask: Locator;
32
32
  readonly createEndEvent: Locator;
33
33
  readonly canvas: Locator;
34
+ readonly zoomOutButton: Locator;
34
35
  readonly endEventCanvas: Locator;
35
36
  readonly connectToOtherElementButton: Locator;
36
37
  readonly firstPlacedElement: Locator;
@@ -162,6 +163,8 @@ declare class ModelerCreatePage {
162
163
  clickDeploySubButtonWithRetry(clusterName: string): Promise<void>;
163
164
  clickCreateTask(): Promise<void>;
164
165
  clickCreateEndEvent(): Promise<void>;
166
+ fitElementIntoCanvas(element: Locator, margin?: number, maxZoomOutSteps?: number): Promise<void>;
167
+ clickShapeBelowContextPad(element: Locator): Promise<void>;
165
168
  clickCanvas(): Promise<void>;
166
169
  clickEndEventCanvas(): Promise<void>;
167
170
  clickConnectToOtherElementButton(): Promise<void>;
@@ -37,6 +37,7 @@ class ModelerCreatePage {
37
37
  createTask;
38
38
  createEndEvent;
39
39
  canvas;
40
+ zoomOutButton;
40
41
  endEventCanvas;
41
42
  connectToOtherElementButton;
42
43
  firstPlacedElement;
@@ -121,7 +122,11 @@ class ModelerCreatePage {
121
122
  name: 'Change element',
122
123
  exact: true,
123
124
  });
124
- this.userTaskOption = page.getByRole('option', { name: 'User task' });
125
+ // The popup also lists the project's deployed resources
126
+ // (`data-id="resources-replace-bpmnProcess-N"`) labelled with the diagram
127
+ // name, so a role+name match on 'User task' is ambiguous as soon as a
128
+ // diagram is called e.g. "Optimize Job Worker User Task Diagram".
129
+ this.userTaskOption = page.locator('.djs-popup-results [data-id="replace-with-user-task"]');
125
130
  this.priorityInput = page.getByRole('textbox', { name: 'priority' });
126
131
  this.appendEndEventButton = page.getByRole('button', {
127
132
  name: 'Append end event',
@@ -157,10 +162,13 @@ class ModelerCreatePage {
157
162
  this.deploySubButton = page.locator('[data-test="deploy-action"]');
158
163
  this.cancelButton = page.getByRole('button', { name: 'Cancel' });
159
164
  this.restConnectorOption = page.locator('[data-id="replace.template-io.camunda.connectors.HttpJson.v2"]');
160
- this.webhookMessageStartEventConnectorOption = page.getByRole('listitem', {
161
- name: 'Webhook Message Start Event Connector',
162
- exact: true,
163
- });
165
+ // bpmn-js popup entries are `li[role="option"]` inside a `role="listbox"`,
166
+ // so getByRole('listitem') no longer matches. Their accessible name also
167
+ // includes the entry description, and three entries share the label
168
+ // ("GitHub …", "Slack …", plain "Webhook …"), so name matching is
169
+ // ambiguous. Anchor on the entry's data-id — the same selector the hub's
170
+ // own e2e suite uses (`.djs-popup-results [data-id="<entryId>"]`).
171
+ this.webhookMessageStartEventConnectorOption = page.locator('.djs-popup-results [data-id="replace.template-io.camunda.connectors.webhook.WebhookConnectorStartMessage.v1"]');
164
172
  this.webhookTab = page.getByRole('tab', { name: 'Webhook' });
165
173
  this.webhookIsActiveButton = page.getByRole('button', {
166
174
  name: 'Webhook is active in Test',
@@ -172,7 +180,8 @@ class ModelerCreatePage {
172
180
  .first();
173
181
  this.createTask = page.getByTitle('Create task');
174
182
  this.createEndEvent = page.getByTitle('Create end event');
175
- this.canvas = page.locator('rect').nth(1);
183
+ this.canvas = page.locator('.djs-container');
184
+ this.zoomOutButton = page.locator('[data-test="zoom-out"]');
176
185
  this.endEventCanvas = page.locator('[class="bjs-container"]');
177
186
  this.connectToOtherElementButton = page.getByRole('button', {
178
187
  name: 'Connect to other element',
@@ -195,9 +204,7 @@ class ModelerCreatePage {
195
204
  this.intermediateBoundaryEvent = page.getByRole('button', {
196
205
  name: 'Append intermediate/boundary',
197
206
  });
198
- this.intermediateWebhookConnectorOption = page.getByRole('listitem', {
199
- name: 'Webhook Intermediate Event',
200
- });
207
+ this.intermediateWebhookConnectorOption = page.locator('.djs-popup-results [data-id="replace.template-io.camunda.connectors.webhook.WebhookConnectorIntermediate.v1"]');
201
208
  this.correlationKeyPayloadInput = page.getByLabel('Correlation key (payload)');
202
209
  this.correlationKeyProcessInput = page.getByLabel('Correlation key (process)');
203
210
  this.form = page.locator('[class="fjs-container"]');
@@ -239,7 +246,7 @@ class ModelerCreatePage {
239
246
  this.secondPlacedGateway = page
240
247
  .locator('[data-element-id*="Gateway"]')
241
248
  .last();
242
- this.serviceTaskOption = page.getByRole('option', { name: 'Service task' });
249
+ this.serviceTaskOption = page.locator('.djs-popup-results [data-id="replace-with-service-task"]');
243
250
  this.taskDefinitionPanel = page.locator('[data-group-id="group-taskDefinition"]');
244
251
  this.jobTypeInput = page.getByRole('textbox', { name: /job type/i });
245
252
  this.playTab = page.getByRole('tab', {
@@ -281,10 +288,7 @@ class ModelerCreatePage {
281
288
  .getByText('zeebeClientId');
282
289
  this.variableAssignmentValueTextboxThirdVariable = page.locator('#bio-properties-panel-StartEvent_1-output-2-source div');
283
290
  this.connectorsDocHandlingStartEventElement = page.locator('g:nth-child(5) > .djs-element > .djs-hit');
284
- this.timerEventOption = page.getByRole('listitem', {
285
- name: 'Timer intermediate catch event',
286
- exact: true,
287
- });
291
+ this.timerEventOption = page.locator('.djs-popup-results [data-id="replace-with-timer-intermediate-catch"]');
288
292
  this.timerEventSettings = page.getByText(/^Timer$/).first();
289
293
  this.timerType = page.getByLabel('Type');
290
294
  this.timerValue = page.getByLabel('Value');
@@ -719,8 +723,45 @@ class ModelerCreatePage {
719
723
  async clickCreateEndEvent() {
720
724
  await this.createEndEvent.click({ timeout: 60000 });
721
725
  }
726
+ // The canvas does not scroll with the DOM, so an element the diagram has
727
+ // pushed past the canvas edge cannot be clicked at all — the hit test returns
728
+ // the canvas container (or the panel toggle bar beside it). Zoom out until
729
+ // the element and one element-width of margin fit inside the canvas.
730
+ async fitElementIntoCanvas(element, margin = 120, maxZoomOutSteps = 3) {
731
+ for (let step = 0; step < maxZoomOutSteps; step++) {
732
+ const canvasBox = await this.canvas.boundingBox();
733
+ const elementBox = await element.boundingBox();
734
+ if (canvasBox === null || elementBox === null) {
735
+ return;
736
+ }
737
+ const elementRightEdge = elementBox.x + elementBox.width + margin;
738
+ if (elementRightEdge <= canvasBox.x + canvasBox.width) {
739
+ return;
740
+ }
741
+ await this.zoomOutButton.click({ timeout: 30000 });
742
+ }
743
+ }
744
+ // A context pad is a fixed-size strip anchored to the top-right of its
745
+ // element, so once the diagram is zoomed out it can reach across the gap and
746
+ // cover the top of the next shape. Click the bottom edge of the target, below
747
+ // the strip, so a neighbour's open pad cannot swallow the click.
748
+ async clickShapeBelowContextPad(element) {
749
+ const box = await element.boundingBox();
750
+ if (box === null) {
751
+ await element.click({ timeout: 60000 });
752
+ return;
753
+ }
754
+ await element.click({
755
+ timeout: 60000,
756
+ position: { x: box.width / 2, y: box.height - 2 },
757
+ });
758
+ }
722
759
  async clickCanvas() {
723
- await this.canvas.click({ timeout: 60000 });
760
+ // Clicking the canvas centre lands on a shape (or an open create pad) as
761
+ // soon as the diagram has more than a couple of elements, and the click is
762
+ // then intercepted instead of clearing the selection. Click the empty
763
+ // gutter above the diagram and right of the palette instead.
764
+ await this.canvas.click({ timeout: 60000, position: { x: 150, y: 25 } });
724
765
  }
725
766
  async clickEndEventCanvas() {
726
767
  await this.endEventCanvas.click({ timeout: 60000 });
@@ -965,16 +1006,22 @@ class ModelerCreatePage {
965
1006
  }
966
1007
  async clickSecondPlacedGateway(userTaskId = '') {
967
1008
  try {
968
- await this.secondPlacedGateway.click({ timeout: 60000 });
1009
+ await this.clickShapeBelowContextPad(this.secondPlacedGateway);
969
1010
  }
970
1011
  catch (error) {
971
1012
  await this.page.reload();
972
1013
  await (0, sleep_1.sleep)(10000);
1014
+ // The reload resets the canvas viewbox to the origin, discarding the
1015
+ // auto-scroll that kept the right-most gateway on screen.
1016
+ await this.fitElementIntoCanvas(this.secondPlacedGateway);
1017
+ // Clear any selection the reload restored, so its context pad is closed
1018
+ // before the gateway is clicked.
1019
+ await this.clickCanvas();
973
1020
  if (userTaskId != '') {
974
1021
  await this.clickUserTask(userTaskId);
975
1022
  await this.clickConnectToOtherElementButton();
976
1023
  }
977
- await this.secondPlacedGateway.click({ timeout: 60000 });
1024
+ await this.clickShapeBelowContextPad(this.secondPlacedGateway);
978
1025
  }
979
1026
  }
980
1027
  async addParallelUserTasks(numberOfTasks, taskName) {
@@ -1021,6 +1068,7 @@ class ModelerCreatePage {
1021
1068
  await this.clickCanvas();
1022
1069
  await (0, sleep_1.sleep)(1000);
1023
1070
  }
1071
+ await this.fitElementIntoCanvas(this.secondPlacedGateway);
1024
1072
  await this.clickSecondPlacedGateway();
1025
1073
  }
1026
1074
  async clickServiceTaskOption() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.886",
3
+ "version": "0.0.888",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",