@camunda/e2e-test-suite 0.0.890 → 0.0.892

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,7 +3,9 @@ declare class ConnectorMarketplacePage {
3
3
  private page;
4
4
  readonly searchForConnectorTextbox: Locator;
5
5
  readonly downloadToProjectButton: Locator;
6
+ readonly addToProjectButton: Locator;
6
7
  readonly replaceResourceButton: Locator;
8
+ readonly saveAsCopyButton: Locator;
7
9
  readonly cancelButton: Locator;
8
10
  readonly marketplaceErrorMessage: Locator;
9
11
  readonly noResultsMessage: Locator;
@@ -15,5 +17,6 @@ declare class ConnectorMarketplacePage {
15
17
  clickReplaceResourceButton(): Promise<void>;
16
18
  waitForConnectorSearchResults(): Promise<void>;
17
19
  downloadConnectorToProject(): Promise<void>;
20
+ private confirmImport;
18
21
  }
19
22
  export { ConnectorMarketplacePage };
@@ -7,7 +7,9 @@ class ConnectorMarketplacePage {
7
7
  page;
8
8
  searchForConnectorTextbox;
9
9
  downloadToProjectButton;
10
+ addToProjectButton;
10
11
  replaceResourceButton;
12
+ saveAsCopyButton;
11
13
  cancelButton;
12
14
  marketplaceErrorMessage;
13
15
  noResultsMessage;
@@ -18,9 +20,13 @@ class ConnectorMarketplacePage {
18
20
  .getByRole('button', { name: 'Download to project' })
19
21
  .first();
20
22
  this.cancelButton = page.getByRole('button', { name: 'Cancel' });
23
+ this.addToProjectButton = page.getByRole('button', {
24
+ name: 'Add to project',
25
+ });
21
26
  this.replaceResourceButton = page.getByRole('button', {
22
27
  name: 'Replace resource',
23
28
  });
29
+ this.saveAsCopyButton = page.getByRole('button', { name: 'Save as copy' });
24
30
  this.marketplaceErrorMessage = page.getByText('an error occurred, please try again later');
25
31
  this.noResultsMessage = page.getByText('find a match for your search phrase');
26
32
  }
@@ -42,7 +48,7 @@ class ConnectorMarketplacePage {
42
48
  await this.replaceResourceButton.click({ timeout: 30000 });
43
49
  }
44
50
  async waitForConnectorSearchResults() {
45
- const MAX_RETRIES = 3;
51
+ const MAX_RETRIES = 4;
46
52
  for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
47
53
  await (0, test_1.expect)(this.downloadToProjectButton
48
54
  .or(this.marketplaceErrorMessage)
@@ -52,6 +58,10 @@ class ConnectorMarketplacePage {
52
58
  }
53
59
  console.log(`Marketplace search attempt ${attempt} of ${MAX_RETRIES} returned an error or no results. Retrying search...`);
54
60
  if (attempt < MAX_RETRIES) {
61
+ // The marketplace search API returns transient 5xx. Back off for
62
+ // growing intervals before re-issuing the query so a short outage
63
+ // self-heals instead of burning all attempts inside a few seconds.
64
+ await (0, sleep_1.sleep)(attempt * 5000);
55
65
  const searchText = await this.searchForConnectorTextbox.inputValue();
56
66
  await this.searchForConnectorTextbox.clear();
57
67
  await (0, sleep_1.sleep)(2000);
@@ -63,15 +73,44 @@ class ConnectorMarketplacePage {
63
73
  }
64
74
  async downloadConnectorToProject() {
65
75
  await this.clickDownloadToProjectButton();
66
- try {
67
- await Promise.race([
68
- this.replaceResourceButton.click({ timeout: 20000 }),
69
- this.cancelButton.click({ timeout: 20000 }),
70
- ]);
71
- }
72
- catch (e) {
76
+ if (await this.confirmImport()) {
73
77
  return;
74
78
  }
79
+ // The modal is up but rendered none of the known import actions. Dismiss it
80
+ // so it does not block the next click on the diagram, then fail here:
81
+ // continuing would leave the diagram's connector template unresolved
82
+ // ("Template: Not found") and only surface 60s later as a missing
83
+ // properties-panel group, pointing at the wrong step.
84
+ if (await this.cancelButton.isVisible().catch(() => false)) {
85
+ await this.cancelButton.click({ timeout: 20000 });
86
+ throw new Error('Connector import modal offered no import action ("Add to project", "Replace resource" or "Save as copy"); the import was abandoned.');
87
+ }
88
+ }
89
+ // Hub's import modal labels its primary button after the project state:
90
+ // "Add to project" when the template is new to the project, "Replace
91
+ // resource" when the same template is already there, "Save as copy" on a
92
+ // conflicting version. Probe them in order and click the one actually
93
+ // rendered; clicking "Cancel" instead abandons the import and leaves the
94
+ // diagram's connector template unresolved ("Template: Not found"), which
95
+ // only surfaces much later as a missing properties-panel group.
96
+ async confirmImport() {
97
+ const importButtons = [
98
+ this.addToProjectButton,
99
+ this.replaceResourceButton,
100
+ this.saveAsCopyButton,
101
+ ];
102
+ const deadline = Date.now() + 20000;
103
+ do {
104
+ for (const button of importButtons) {
105
+ if (await button.isVisible().catch(() => false)) {
106
+ await button.click({ timeout: 20000 });
107
+ await (0, test_1.expect)(button).toBeHidden({ timeout: 60000 });
108
+ return true;
109
+ }
110
+ }
111
+ await (0, sleep_1.sleep)(1000);
112
+ } while (Date.now() < deadline);
113
+ return false;
75
114
  }
76
115
  }
77
116
  exports.ConnectorMarketplacePage = ConnectorMarketplacePage;
@@ -48,6 +48,8 @@ declare class ModelerCreatePage {
48
48
  readonly secondPlacedGateway: Locator;
49
49
  readonly secondPlacedElement: Locator;
50
50
  readonly appendPreButton: Locator;
51
+ readonly appendAnythingEntry: Locator;
52
+ readonly appendPopup: Locator;
51
53
  readonly appendGatewayButton: Locator;
52
54
  readonly parallelGatewayOption: Locator;
53
55
  readonly connectToOtherElementButton: Locator;
@@ -105,6 +107,8 @@ declare class ModelerCreatePage {
105
107
  fillElementIdInput(id: string): Promise<void>;
106
108
  clickStartEventElement(): Promise<void>;
107
109
  selectStartEventElement(): Promise<void>;
110
+ private clickCreatePadEntry;
111
+ private appendViaPopup;
108
112
  clickAppendTaskButton(): Promise<void>;
109
113
  hoverOnLocator(locator: Locator, selector?: string): Promise<void>;
110
114
  clickAppendGatewayButton(): Promise<void>;
@@ -112,6 +116,7 @@ declare class ModelerCreatePage {
112
116
  clickChangeTypeButton(): Promise<void>;
113
117
  clickUserTaskOption(): Promise<void>;
114
118
  clickServiceTaskOption(): Promise<void>;
119
+ private appendEndEvent;
115
120
  clickAppendEndEventButton(parentElement?: string): Promise<void>;
116
121
  clickFirstPlacedElement(): Promise<void>;
117
122
  clickSecondPlacedElement(): Promise<void>;
@@ -139,10 +144,12 @@ declare class ModelerCreatePage {
139
144
  clickDeploySubButton(): Promise<void>;
140
145
  clickCancelButton(): Promise<void>;
141
146
  private recoverModelerSession;
147
+ private searchAndClickRestConnector;
142
148
  clickRestConnectorOption(recoverSession?: () => Promise<void>): Promise<void>;
143
149
  clickMarketPlaceButton(): Promise<void>;
144
150
  completeDeploymentEndpointConfiguration(): Promise<void>;
145
151
  completePlayConfiguration(): Promise<void>;
152
+ filterChangeElementPopup(searchTerm: string): Promise<void>;
146
153
  clickWebhookMessageStartEventConnectorOption(): Promise<void>;
147
154
  clickWebhookIdInput(): Promise<void>;
148
155
  clearWebhookIdInput(): Promise<void>;
@@ -53,6 +53,8 @@ class ModelerCreatePage {
53
53
  secondPlacedGateway;
54
54
  secondPlacedElement;
55
55
  appendPreButton;
56
+ appendAnythingEntry;
57
+ appendPopup;
56
58
  appendGatewayButton;
57
59
  parallelGatewayOption;
58
60
  connectToOtherElementButton;
@@ -104,6 +106,8 @@ class ModelerCreatePage {
104
106
  this.startEventElement = page.locator('.djs-hit').first();
105
107
  this.appendPreButton = page.locator('.djs-create-pad-icon > svg').first();
106
108
  this.appendTaskButton = page.getByRole('button', { name: 'Append task' });
109
+ this.appendAnythingEntry = page.locator('.djs-create-pad-entries [data-entry-id="append"]');
110
+ this.appendPopup = page.locator('.djs-popup.bpmn-append');
107
111
  this.changeTypeButton = page.getByRole('button', {
108
112
  name: 'Change element',
109
113
  exact: true,
@@ -148,20 +152,27 @@ class ModelerCreatePage {
148
152
  .getByRole('dialog')
149
153
  .getByRole('button', { name: 'Deploy' });
150
154
  this.cancelButton = page.getByRole('button', { name: 'Cancel' });
151
- this.restConnectorOption = page.locator('[data-id="replace.template-io.camunda.connectors.HttpJson.v2"]');
155
+ this.restConnectorOption = page
156
+ .locator('.djs-popup-results')
157
+ .locator('[data-id="replace.template-io.camunda.connectors.HttpJson.v2"]');
152
158
  this.changeElementSearchInput = page.locator('.djs-popup-search input');
153
- this.marketPlaceButton = page.getByTitle('Browse Marketplace for more Connectors');
159
+ // A title query is ambiguous: when the filtered result list has no connector
160
+ // match the popup also renders an empty-state link carrying the same title,
161
+ // so the query resolves to two elements and clicking throws in strict mode.
162
+ // Target the popup header entry by its stable entry id instead.
163
+ this.marketPlaceButton = page.locator('[data-id="browseConnectors"]');
154
164
  this.clientIdTextbox = page.getByLabel('Client ID');
155
165
  this.clientSecretTextbox = page.getByLabel('Client secret');
156
166
  this.rememberCredentialsCheckbox = page.getByText('Remember credentials');
157
- this.webhookMessageStartEventConnectorOption = page.getByRole('listitem', {
167
+ this.webhookMessageStartEventConnectorOption = page
168
+ .locator('.djs-popup-results')
169
+ .getByRole('option', {
158
170
  name: 'Webhook Message Start Event Connector',
159
- exact: true,
160
171
  });
161
172
  this.webhookIdInput = page.getByLabel('Webhook ID');
162
- this.firstElement = page.locator('[class="djs-element djs-shape"]').nth(0);
163
- this.secondElement = page.locator('[class="djs-element djs-shape"]').nth(1);
164
- this.thirdElement = page.locator('[class="djs-element djs-shape"]').nth(2);
173
+ this.firstElement = page.locator('.djs-element.djs-shape').nth(0);
174
+ this.secondElement = page.locator('.djs-element.djs-shape').nth(1);
175
+ this.thirdElement = page.locator('.djs-element.djs-shape').nth(2);
165
176
  this.implementationSection = page.locator('[data-group-id="group-userTaskImplementation"]');
166
177
  this.implementationOptions = page.locator('#bio-properties-panel-userTaskImplementation');
167
178
  this.assignmentSection = page.locator('[data-group-id="group-assignmentDefinition"]');
@@ -175,9 +186,7 @@ class ModelerCreatePage {
175
186
  this.secondPlacedGateway = page
176
187
  .locator('[data-element-id*="Gateway"]')
177
188
  .last();
178
- this.secondPlacedElement = page
179
- .locator('[class= "djs-element djs-shape"]')
180
- .last();
189
+ this.secondPlacedElement = page.locator('.djs-element.djs-shape').last();
181
190
  this.connectToOtherElementButton = page.getByRole('button', {
182
191
  name: 'Connect to other element',
183
192
  });
@@ -185,7 +194,9 @@ class ModelerCreatePage {
185
194
  this.intermediateBoundaryEvent = page.getByRole('button', {
186
195
  name: 'Append intermediate/boundary',
187
196
  });
188
- this.intermediateWebhookConnectorOption = page.getByRole('listitem', {
197
+ this.intermediateWebhookConnectorOption = page
198
+ .locator('.djs-popup-results')
199
+ .getByRole('option', {
189
200
  name: 'Webhook Intermediate Event Connector',
190
201
  });
191
202
  this.correlationKeyPayloadInput = page.getByLabel('Correlation key (payload)');
@@ -201,9 +212,10 @@ class ModelerCreatePage {
201
212
  name: 'candidate groups',
202
213
  });
203
214
  this.tenantIdInput = page.getByLabel('Tenant ID (Optional)');
204
- this.timerEventOption = page.getByRole('listitem', {
215
+ this.timerEventOption = page
216
+ .locator('.djs-popup-results')
217
+ .getByRole('option', {
205
218
  name: 'Timer intermediate catch event',
206
- exact: true,
207
219
  });
208
220
  this.timerEventSettings = page.getByText(/^Timer$/).first();
209
221
  this.timerType = page.getByLabel('Type');
@@ -426,9 +438,66 @@ class ModelerCreatePage {
426
438
  async selectStartEventElement() {
427
439
  await this.startEventElement.click();
428
440
  }
441
+ // The create pad's direct append icons no longer carry the bpmn-js `title`
442
+ // attributes ("Append task", "Append intermediate/boundary", "Append end
443
+ // event"), so append through the "append anything" entry instead: it opens
444
+ // the bpmn-append popup whose entries are addressed by the stable `data-id`
445
+ // ids bpmn-js declares in PopupEntries. Since camunda-bpmn-js 5.30.0 those
446
+ // entries sit in drill-in categories, so filter with the popup search first
447
+ // and fall back to walking the categories when search does not surface it.
448
+ // The append create pad renders its entries asynchronously once the source
449
+ // element is selected, so wait for the requested entry instead of probing for
450
+ // it. Entries are addressed by the `data-entry-id` bpmn-js declares on them
451
+ // ("append.end-event", "append.intermediate-event", "append.append-task").
452
+ async clickCreatePadEntry(entryId) {
453
+ const entry = this.page.locator(`.djs-create-pad-entries [data-entry-id="${entryId}"]`);
454
+ try {
455
+ await entry.waitFor({ state: 'visible', timeout: 30000 });
456
+ }
457
+ catch {
458
+ return false;
459
+ }
460
+ await entry.click({ timeout: 30000 });
461
+ return true;
462
+ }
463
+ async appendViaPopup(entryId, categoryIds, searchTerm) {
464
+ await this.hoverOnLocator(this.appendPreButton);
465
+ await this.appendAnythingEntry.click({ timeout: 30000 });
466
+ await (0, test_1.expect)(this.appendPopup).toBeVisible({ timeout: 30000 });
467
+ const entry = this.appendPopup.locator(`[data-id="${entryId}"]`).first();
468
+ const search = this.appendPopup.locator('.djs-popup-search input');
469
+ const hasSearch = await search
470
+ .isVisible({ timeout: 5000 })
471
+ .catch(() => false);
472
+ if (hasSearch) {
473
+ await search.fill(searchTerm);
474
+ }
475
+ const surfaced = await entry.isVisible({ timeout: 5000 }).catch(() => false);
476
+ if (!surfaced) {
477
+ if (hasSearch) {
478
+ await search.fill('');
479
+ }
480
+ // The popup drills into a category based on its own hover-tracked
481
+ // selection, so hover each category before clicking it.
482
+ for (const categoryId of categoryIds) {
483
+ const category = this.appendPopup
484
+ .locator(`[data-id="${categoryId}"]`)
485
+ .first();
486
+ await category.scrollIntoViewIfNeeded({ timeout: 15000 });
487
+ await category.hover({ timeout: 15000 });
488
+ await category.click({ timeout: 15000 });
489
+ }
490
+ }
491
+ await entry.scrollIntoViewIfNeeded({ timeout: 30000 });
492
+ await entry.click({ timeout: 30000 });
493
+ await (0, test_1.expect)(this.appendPopup).toBeHidden({ timeout: 30000 });
494
+ }
429
495
  async clickAppendTaskButton() {
430
496
  await this.hoverOnLocator(this.appendPreButton);
431
- await this.appendTaskButton.click({ timeout: 90000 });
497
+ if (await this.clickCreatePadEntry('append.append-task')) {
498
+ return;
499
+ }
500
+ await this.appendViaPopup('append-task', ['append-tasks'], 'Task');
432
501
  }
433
502
  async hoverOnLocator(locator, selector = '.djs-create-pad-entry') {
434
503
  const canvasState = await Promise.race([
@@ -543,9 +612,15 @@ class ModelerCreatePage {
543
612
  }
544
613
  throw new Error(`Failed to click the button after ${maxRetries} attempts.`);
545
614
  }
615
+ async appendEndEvent() {
616
+ if (await this.clickCreatePadEntry('append.end-event')) {
617
+ return;
618
+ }
619
+ await this.appendViaPopup('append-none-end-event', ['append-events', 'append-end-events'], 'End event');
620
+ }
546
621
  async clickAppendEndEventButton(parentElement) {
547
622
  try {
548
- await this.appendEndEventButton.click();
623
+ await this.appendEndEvent();
549
624
  }
550
625
  catch (error) {
551
626
  await this.page.reload();
@@ -558,7 +633,7 @@ class ModelerCreatePage {
558
633
  await this.clickSecondPlacedGateway();
559
634
  }
560
635
  await this.hoverOnLocator(this.appendElementButton);
561
- await this.appendEndEventButton.click({ timeout: 30000 });
636
+ await this.appendEndEvent();
562
637
  }
563
638
  }
564
639
  async clickFirstPlacedElement() {
@@ -686,22 +761,39 @@ class ModelerCreatePage {
686
761
  });
687
762
  await (0, test_1.expect)(this.secondElement).toBeVisible({ timeout: 60000 });
688
763
  }
764
+ // The change-element popup virtualizes its list: connector templates render
765
+ // below the built-in BPMN tasks and are not in the queryable DOM slice until
766
+ // the list is filtered, so every attempt has to re-type the filter -- a freshly
767
+ // (re)opened popup is always unfiltered, and asserting straight on the entry
768
+ // then times out against an off-screen node. Waiting for the search input also
769
+ // confirms the popup actually opened: the "Change element" click reports
770
+ // success even when the popup does not render. Use pressSequentially (not
771
+ // fill): fill sets the value in one shot and the single input event can land
772
+ // before bpmn-js attaches its search handler during the popup re-render.
773
+ async searchAndClickRestConnector() {
774
+ await (0, test_1.expect)(this.changeElementSearchInput).toBeVisible({ timeout: 30000 });
775
+ await this.changeElementSearchInput.click();
776
+ await this.changeElementSearchInput.fill('');
777
+ await this.changeElementSearchInput.pressSequentially('REST Outbound', {
778
+ delay: 50,
779
+ });
780
+ await (0, test_1.expect)(this.restConnectorOption).toBeVisible({ timeout: 90000 });
781
+ await this.restConnectorOption.click({ timeout: 90000 });
782
+ }
689
783
  async clickRestConnectorOption(recoverSession) {
690
784
  const maxRetries = 4;
691
785
  for (let retries = 0; retries < maxRetries; retries++) {
692
786
  try {
693
787
  if (retries === 0) {
694
- // First attempt
695
- await (0, test_1.expect)(this.restConnectorOption).toBeVisible({ timeout: 60000 });
696
- await this.restConnectorOption.click({ timeout: 60000 });
788
+ // Panel already open from the caller (modelRestConnector in UtilitiesPage)
789
+ await this.searchAndClickRestConnector();
697
790
  }
698
791
  else if (retries === 1 || retries === 2) {
699
792
  // Recover session cleanly instead of page.reload()
700
793
  await this.recoverModelerSession(recoverSession);
701
794
  await this.secondElement.click({ timeout: 60000 });
702
795
  await this.changeTypeButton.click({ force: true, timeout: 60000 });
703
- await (0, test_1.expect)(this.restConnectorOption).toBeVisible({ timeout: 90000 });
704
- await this.restConnectorOption.click({ timeout: 90000 });
796
+ await this.searchAndClickRestConnector();
705
797
  }
706
798
  else {
707
799
  // Fourth attempt: install via marketplace (real product flow)
@@ -711,10 +803,13 @@ class ModelerCreatePage {
711
803
  await this.clickMarketPlaceButton();
712
804
  const marketplace = new ConnectorMarketplacePage_1.ConnectorMarketplacePage(this.page);
713
805
  await marketplace.clickSearchForConnectorTextbox();
714
- await (0, sleep_1.sleep)(5000);
715
806
  await marketplace.fillSearchForConnectorTextbox('REST Connector');
807
+ await marketplace.waitForConnectorSearchResults();
716
808
  await marketplace.downloadConnectorToProject();
717
- await this.restConnectorOption.click({ timeout: 120000 });
809
+ // Marketplace closes the change-type panel; reopen it so the newly
810
+ // installed connector appears in the list.
811
+ await this.changeTypeButton.click({ force: true, timeout: 60000 });
812
+ await this.searchAndClickRestConnector();
718
813
  }
719
814
  return;
720
815
  }
@@ -824,11 +919,23 @@ class ModelerCreatePage {
824
919
  }
825
920
  }
826
921
  }
922
+ // Connector templates nest under the change-element popup's "Templates"
923
+ // category and every entry now renders a description, so filter the popup by
924
+ // name to surface the entry as a flat search result before clicking it.
925
+ async filterChangeElementPopup(searchTerm) {
926
+ const hasSearch = await this.changeElementSearchInput
927
+ .isVisible({ timeout: 5000 })
928
+ .catch(() => false);
929
+ if (hasSearch) {
930
+ await this.changeElementSearchInput.fill(searchTerm);
931
+ }
932
+ }
827
933
  async clickWebhookMessageStartEventConnectorOption() {
828
934
  const maxRetries = 3;
829
935
  for (let retries = 0; retries < maxRetries; retries++) {
830
936
  try {
831
937
  if (retries === 0) {
938
+ await this.filterChangeElementPopup('Webhook Message Start Event Connector');
832
939
  await this.webhookMessageStartEventConnectorOption.click({
833
940
  timeout: 30000,
834
941
  });
@@ -836,6 +943,7 @@ class ModelerCreatePage {
836
943
  else {
837
944
  await this.page.reload();
838
945
  await this.changeTypeButton.click({ force: true, timeout: 30000 });
946
+ await this.filterChangeElementPopup('Webhook Message Start Event Connector');
839
947
  await this.webhookMessageStartEventConnectorOption.click({
840
948
  timeout: 90000,
841
949
  });
@@ -997,7 +1105,10 @@ class ModelerCreatePage {
997
1105
  }
998
1106
  }
999
1107
  async clickIntermediateBoundaryEvent() {
1000
- await this.intermediateBoundaryEvent.click({ timeout: 60000 });
1108
+ if (await this.clickCreatePadEntry('append.intermediate-event')) {
1109
+ return;
1110
+ }
1111
+ await this.appendViaPopup('append-none-intermediate-throwing', ['append-events', 'append-intermediate-throw-events'], 'Intermediate throw event');
1001
1112
  }
1002
1113
  async clickIntermediateWebhookConnectorOption() {
1003
1114
  const max = 3;
@@ -1079,7 +1190,10 @@ class ModelerCreatePage {
1079
1190
  await (0, sleep_1.sleep)(1000);
1080
1191
  }
1081
1192
  async clickTimerEventOption() {
1082
- await this.timerEventOption.click();
1193
+ // The change-element popup renders its results list asynchronously, so wait
1194
+ // past the 10s default action timeout before clicking.
1195
+ await (0, test_1.expect)(this.timerEventOption).toBeVisible({ timeout: 60000 });
1196
+ await this.timerEventOption.click({ timeout: 30000 });
1083
1197
  }
1084
1198
  async clickTimerEventSettings() {
1085
1199
  await this.timerEventSettings.click();
@@ -15,7 +15,8 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
15
15
  await (0, _setup_1.captureScreenshot)(page, testInfo);
16
16
  await (0, _setup_1.captureFailureVideo)(page, testInfo);
17
17
  });
18
- (0, SM_8_10_1.test)('REST Connector No Auth User Flow', async ({ page, operateHomePage, modelerHomePage, operateProcessInstancePage, modelerCreatePage, connectorSettingsPage, operateProcessesPage, connectorMarketplacePage, navigationPage, }) => {
18
+ // Skipped due to bug #7716: https://github.com/camunda/connectors/issues/7716
19
+ SM_8_10_1.test.skip('REST Connector No Auth User Flow', async ({ page, operateHomePage, modelerHomePage, operateProcessInstancePage, modelerCreatePage, connectorSettingsPage, operateProcessesPage, connectorMarketplacePage, navigationPage, }) => {
19
20
  SM_8_10_1.test.slow();
20
21
  const processName = 'REST_Connector_No_Auth_Process' + (await (0, _setup_1.generateRandomStringAsync)(3));
21
22
  await SM_8_10_1.test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
@@ -43,7 +44,8 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
43
44
  });
44
45
  });
45
46
  });
46
- (0, SM_8_10_1.test)('REST Connector Bearer Token Auth User Flow', async ({ page, operateHomePage, modelerHomePage, modelerCreatePage, connectorSettingsPage, navigationPage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, }) => {
47
+ // Skipped due to bug #8162: https://github.com/camunda/connectors/issues/8162
48
+ SM_8_10_1.test.skip('REST Connector Bearer Token Auth User Flow', async ({ page, operateHomePage, modelerHomePage, modelerCreatePage, connectorSettingsPage, navigationPage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, }) => {
47
49
  SM_8_10_1.test.slow();
48
50
  const processName = 'REST_Connector_Bearer_Auth_Process' +
49
51
  (await (0, _setup_1.generateRandomStringAsync)(3));
@@ -97,6 +99,7 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
97
99
  await modelerCreatePage.clickStartEventElement();
98
100
  await modelerCreatePage.clickChangeTypeButton();
99
101
  try {
102
+ await modelerCreatePage.filterChangeElementPopup('Webhook Message Start Event Connector');
100
103
  await (0, test_1.expect)(modelerCreatePage.webhookMessageStartEventConnectorOption).toBeVisible({
101
104
  timeout: 15000,
102
105
  });
@@ -123,8 +126,23 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
123
126
  await SM_8_10_1.test.step('Make Authorization Request', async () => {
124
127
  const baseURL = process.env.PLAYWRIGHT_BASE_URL ||
125
128
  `http://gke-${process.env.BASE_URL}.ci.distro.ultrawombat.com`;
126
- const response = await request.post(`${baseURL}/connectors/inbound/test-webhook-id${randomString}`);
127
- await (0, test_1.expect)(response.status()).toBe(200);
129
+ const url = `${baseURL}/connectors/inbound/test-webhook-id${randomString}`;
130
+ // Poll for inbound endpoint readiness — connector deployment is async
131
+ // after the diagram is deployed.
132
+ const deadline = Date.now() + 180000;
133
+ let response;
134
+ let attempt = 0;
135
+ while (Date.now() < deadline) {
136
+ attempt++;
137
+ response = await request.post(url);
138
+ if (response.status() === 200)
139
+ break;
140
+ console.error(`Webhook readiness attempt ${attempt}: ${url} -> ${response.status()}`);
141
+ await (0, sleep_1.sleep)(10000);
142
+ }
143
+ if (!response || response.status() !== 200) {
144
+ throw new Error(`Webhook request failed with status ${response?.status()} after ${attempt} attempts`);
145
+ }
128
146
  });
129
147
  await SM_8_10_1.test.step('Assert Diagram Has Successfully Completed in Operate', async () => {
130
148
  await navigationPage.goToOperate();
@@ -134,7 +152,8 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
134
152
  (0, test_1.expect)(result).toBe('completed');
135
153
  });
136
154
  });
137
- (0, SM_8_10_1.test)('Connector Secrets User Flow', async ({ operateHomePage, modelerHomePage, navigationPage, modelerCreatePage, connectorSettingsPage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, }) => {
155
+ // Skipped due to bug #7716: https://github.com/camunda/connectors/issues/7716
156
+ SM_8_10_1.test.skip('Connector Secrets User Flow', async ({ operateHomePage, modelerHomePage, navigationPage, modelerCreatePage, connectorSettingsPage, operateProcessInstancePage, operateProcessesPage, connectorMarketplacePage, }) => {
138
157
  SM_8_10_1.test.slow();
139
158
  const processName = 'REST_Connector_Process' + (await (0, _setup_1.generateRandomStringAsync)(3));
140
159
  await SM_8_10_1.test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
@@ -191,7 +210,11 @@ SM_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
191
210
  await modelerCreatePage.clickIntermediateBoundaryEvent();
192
211
  await modelerCreatePage.clickChangeTypeButton();
193
212
  try {
194
- await (0, test_1.expect)(modelerCreatePage.webhookMessageStartEventConnectorOption).toBeVisible({
213
+ // Probe for the template this flow needs: an intermediate event's
214
+ // change-element list never offers the message start event connector,
215
+ // so probing for that one always fell through to the marketplace.
216
+ await modelerCreatePage.filterChangeElementPopup('Webhook Intermediate Event Connector');
217
+ await (0, test_1.expect)(modelerCreatePage.intermediateWebhookConnectorOption).toBeVisible({
195
218
  timeout: 15000,
196
219
  });
197
220
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.890",
3
+ "version": "0.0.892",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",