@camunda/e2e-test-suite 0.0.1021 → 0.0.1023

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.
@@ -16,6 +16,7 @@ declare class ClusterSecretsPage {
16
16
  readonly confirmDeleteInput: Locator;
17
17
  constructor(page: Page);
18
18
  deleteConnectorSecretsIfExist(): Promise<void>;
19
+ private dismissOpenModal;
19
20
  clickCreateNewSecretButton(clusterName: string): Promise<void>;
20
21
  clickClusterBanner(): Promise<void>;
21
22
  clickCluster(name: string): Promise<void>;
@@ -38,14 +38,25 @@ class ClusterSecretsPage {
38
38
  name: 'Delete',
39
39
  exact: true,
40
40
  });
41
- this.deleteConnectorSecretSubButton = page.getByRole('button', {
42
- name: 'danger Delete',
43
- });
41
+ // The confirmation modal's destructive action is a plain "Delete" button
42
+ // (Console renders Carbon's ModalFooter danger button, whose accessible
43
+ // name is just its label). The old 'danger Delete' name came from a Carbon
44
+ // version that prefixed danger buttons with a visually-hidden kind label;
45
+ // it matches nothing today, so the click timed out and left the modal open
46
+ // on top of the page. Scoped to the dialog so it cannot collide with the
47
+ // row-level Delete control behind it.
48
+ this.deleteConnectorSecretSubButton = page
49
+ .getByRole('dialog')
50
+ .getByRole('button', { name: 'Delete', exact: true });
44
51
  this.dialog = page.getByRole('dialog');
45
52
  this.clusterBanner = this.page
46
53
  .getByRole('banner')
47
54
  .getByRole('link', { name: 'Clusters' });
48
- this.clusterLink = (name) => page.getByRole('link', { name: name });
55
+ // exact: true because console-user-flows.spec.ts creates a second cluster
56
+ // called "UI Test Cluster" in the same org -- a substring match on
57
+ // "Test Cluster" then resolves to both links and fails on strict mode.
58
+ // ClusterPage's own cluster locators already match exactly.
59
+ this.clusterLink = (name) => page.getByRole('link', { name: name, exact: true });
49
60
  this.clusterSecretTab = this.page.getByRole('tab', {
50
61
  name: 'Connector Secrets',
51
62
  });
@@ -95,13 +106,39 @@ class ClusterSecretsPage {
95
106
  break;
96
107
  }
97
108
  }
98
- await (0, test_1.expect)(this.optionsButton).not.toBeVisible({
99
- timeout: 30000,
100
- });
109
+ // Console auto-provisions CAMUNDA_PROVIDED_LLM_* secrets whose Delete
110
+ // menu item is disabled, so the table is never empty once the sweep is
111
+ // done. A page-wide not.toBeVisible() therefore matched three Options
112
+ // buttons at once (strict mode violation) while asserting something that
113
+ // is no longer true. The post-condition this helper actually owns is
114
+ // that nothing *deletable* is left behind.
115
+ const deletableSecretRows = this.page
116
+ .getByRole('row')
117
+ .filter({ has: this.page.getByRole('cell', { name: 'Options' }) })
118
+ .filter({ hasNotText: 'CAMUNDA_PROVIDED_' });
119
+ await (0, test_1.expect)(deletableSecretRows).toHaveCount(0, { timeout: 30000 });
101
120
  }
102
121
  catch (error) {
103
122
  console.error('Error during Connector Secrets deletion: ', error);
123
+ // A half-completed delete leaves Carbon's confirmation modal on screen,
124
+ // where its overlay swallows pointer events for every later click -- the
125
+ // next "Create new secret" click then burns its whole timeout against
126
+ // the overlay instead of the button. Cleanup must never hand the page
127
+ // back with a modal still open.
128
+ await this.dismissOpenModal();
129
+ }
130
+ }
131
+ // Closes whichever Carbon modal is currently on screen, and waits for it to
132
+ // actually leave the DOM rather than assuming a fixed delay.
133
+ async dismissOpenModal() {
134
+ const openModal = this.page.locator('.cds--modal.is-visible');
135
+ if ((await openModal.count().catch(() => 0)) === 0) {
136
+ return;
104
137
  }
138
+ await this.page.keyboard.press('Escape').catch(() => { });
139
+ await (0, test_1.expect)(openModal)
140
+ .toHaveCount(0, { timeout: 10000 })
141
+ .catch(() => { });
105
142
  }
106
143
  async clickCreateNewSecretButton(clusterName) {
107
144
  try {
@@ -118,16 +155,7 @@ class ClusterSecretsPage {
118
155
  }
119
156
  }
120
157
  async clickClusterBanner() {
121
- try {
122
- const blockingModal = this.page.locator('.cds--modal.is-visible');
123
- if ((await blockingModal.count()) > 0) {
124
- await this.page.keyboard.press('Escape');
125
- await (0, sleep_1.sleep)(1000);
126
- }
127
- }
128
- catch (_e) {
129
- // no blocking modal to dismiss
130
- }
158
+ await this.dismissOpenModal();
131
159
  await (0, test_1.expect)(this.clusterBanner).toBeVisible({ timeout: 30000 });
132
160
  await this.clusterBanner.click({ timeout: 60000 });
133
161
  }
@@ -89,8 +89,14 @@ async function modelRestConnector(modelerCreatePage, connectorSettingsPage, proc
89
89
  username: '',
90
90
  password: '',
91
91
  }) {
92
+ // 120s to match every other properties-panel wait in the 8.7 suite
93
+ // (modelJobWorkerDiagram, clickDiagramBreadcrumb and the specs' own waits all
94
+ // allow 90-200s). 30s was the lone outlier here and the bpmn-js properties
95
+ // panel regularly needs longer than that to mount on a freshly created
96
+ // diagram, which failed the REST connector flows before a single element was
97
+ // modelled.
92
98
  await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({
93
- timeout: 30000,
99
+ timeout: 120000,
94
100
  });
95
101
  await modelerCreatePage.enterDiagramName(processName);
96
102
  await (0, sleep_1.sleep)(10000);
@@ -46,16 +46,15 @@ class ManagementIdentityPage {
46
46
  this.optimizeCheckbox = page
47
47
  .locator('label')
48
48
  .filter({ hasText: 'Optimize (Grants full access to Optimize)' });
49
- // Mid-rename: camunda/identity#4541 moves these role descriptions from Web
50
- // Modeler to Hub, and the role names follow only later. Depending on which
51
- // Identity image the deployed chart carries, the same checkbox renders as
52
- // "Web Modeler (Grants full access to Web Modeler)", the half-renamed
53
- // "Web Modeler (Grants full access to Hub)", or "Hub (Grants full access to
54
- // Hub)". Match all three so the suite stays green on either side of the
55
- // rollout. The " (" after the name keeps this off the Admin row.
56
- this.modelerCheckbox = page.locator('label').filter({
57
- hasText: /(Web Modeler|Hub) \(Grants full access to (Web Modeler|Hub)\)/,
58
- });
49
+ // The chart's Keycloak preset (camunda-platform-helm#6896) renamed the Hub
50
+ // application and added "Hub"/"Hub Admin" roles while keeping the identical
51
+ // legacy "Web Modeler"/"Web Modeler Admin" roles for 8.10-alpha upgrades,
52
+ // so the straddle alternation that matched either wording now resolves to
53
+ // two rows and trips strict mode. Both roles grant the same permissions on
54
+ // the same application; target the go-forward "Hub" name, which is also
55
+ // what the chart assigns its own QA users. The `for` attribute is the role
56
+ // name, so this survives further description rewording.
57
+ this.modelerCheckbox = page.locator('label[for="Hub"]');
59
58
  this.identityCheckbox = page.locator('label').filter({
60
59
  hasText: 'ManagementIdentity (Provides full access to Management Identity)',
61
60
  });
@@ -67,10 +66,8 @@ class ManagementIdentityPage {
67
66
  this.licenseKeyTagNonCommercial = page.getByText('Non-commercial license');
68
67
  this.licenseKeyTagProduction = page.getByText('Production license').first();
69
68
  this.licenseKeyTagCommercial = page.getByText('Commercial license');
70
- // Same Web Modeler → Hub rename straddle as `modelerCheckbox` above.
71
- this.modelerAdminCheckbox = page.locator('label').filter({
72
- hasText: /(Web Modeler|Hub) Admin \(Grants elevated access to (Web Modeler|Hub)\)/,
73
- });
69
+ // Same two-role split as `modelerCheckbox` above.
70
+ this.modelerAdminCheckbox = page.locator('label[for="Hub Admin"]');
74
71
  this.openSidebarButton = page.getByLabel('Open User Sidebar');
75
72
  this.logoutButton = page.getByRole('button', { name: 'Log out' });
76
73
  this.orchestrationCheckbox = page.locator('label').filter({
@@ -21,19 +21,34 @@ class OCIdentityClusterVariablesPage {
21
21
  editModalHeading;
22
22
  constructor(page) {
23
23
  this.page = page;
24
- this.variablesList = page.locator('table.cds--data-table');
24
+ // The Admin UI is migrating off Carbon onto the Camunda design system:
25
+ // `identity/client/src/pages/cluster-variables/index.tsx` renders ListV2
26
+ // (design-system `DataTable`, Radix dialog/menu) when the
27
+ // `isNewDesignSystemEnabled` client config is on, which the orchestration
28
+ // server defaults to for Self-Managed. Released 8.10 alpha images predate
29
+ // ListV2 and still render Carbon, so the locators that differ between the
30
+ // two DOMs accept either.
31
+ this.variablesList = page.locator('table.cds--data-table, table[data-slot="table"]');
25
32
  this.variableRow = (variableName) => this.variablesList
26
33
  .locator('tbody')
27
34
  .getByRole('row')
28
35
  .filter({ hasText: variableName });
29
- this.editVariableButton = (variableName) => this.variableRow(variableName).getByRole('button', { name: 'Options' });
36
+ // Carbon's OverflowMenu labels its trigger "Options"; the design-system
37
+ // DataTable labels it "Row actions".
38
+ this.editVariableButton = (variableName) => this.variableRow(variableName).getByRole('button', {
39
+ name: /^(Options|Row actions)$/,
40
+ });
30
41
  this.editVariableModal = page.getByRole('dialog', {
31
42
  name: /Edit.*variable/i,
32
43
  });
33
44
  this.variableValueField = this.editVariableModal.getByRole('textbox', {
34
45
  name: 'Editor content',
35
46
  });
36
- this.saveVariableButton = this.editVariableModal.locator('.cds--modal-footer button.cds--btn--primary');
47
+ // Both modals pass `confirmLabel={t("save")}`, so the accessible name is
48
+ // stable across the two footers.
49
+ this.saveVariableButton = this.editVariableModal.getByRole('button', {
50
+ name: 'Save',
51
+ });
37
52
  this.closeEditVariableModal = this.editVariableModal.getByRole('button', {
38
53
  name: 'Close',
39
54
  });
@@ -44,11 +59,15 @@ class OCIdentityClusterVariablesPage {
44
59
  this.monacoEditorTextArea = this.monacoEditor.locator('textarea.inputarea');
45
60
  this.monacoSuggestWidget = this.monacoEditor.locator('.editor-widget.suggest-widget');
46
61
  this.successMessage = this.page.getByText('Cluster variable updated');
47
- this.editModalHeading =
48
- this.editVariableModal.locator('.cds--modal-header');
49
- this.editMenuItem = this.page
50
- .locator('button[role="menuitem"]')
51
- .filter({ hasText: /^Edit$/ });
62
+ // Carbon renders the modal title as an h3, the design-system dialog as an
63
+ // h2; the heading role covers both.
64
+ this.editModalHeading = this.editVariableModal.getByRole('heading').first();
65
+ // Carbon menu items are buttons, Radix menu items are divs — match on the
66
+ // role instead of the tag.
67
+ this.editMenuItem = this.page.getByRole('menuitem', {
68
+ name: 'Edit',
69
+ exact: true,
70
+ });
52
71
  }
53
72
  async editVariable(variableName, newValue) {
54
73
  await this.editVariableButton(variableName).click();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1021",
3
+ "version": "0.0.1023",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",