@camunda/e2e-test-suite 0.0.1153 → 0.0.1155

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 OperateProcessInstancePage {
32
32
  private reenterViaConsole;
33
33
  reload(): Promise<boolean>;
34
34
  assertProcessCompleteStatusWithRetry(timeout?: number, maxRetries?: number): Promise<void>;
35
+ assertProcessVariableIsVisible(variableName: string, timeout?: number, maxRetries?: number): Promise<void>;
35
36
  assertProcessVariableContainsText(variableName: string, text: string): Promise<void>;
36
37
  assertProcessVariableHasDocumentCount(variableName: string, count: number, softFail?: boolean): Promise<void>;
37
38
  clickDiagramTask(taskName: string): Promise<void>;
@@ -797,6 +797,29 @@ class OperateProcessInstancePage {
797
797
  }
798
798
  }
799
799
  }
800
+ // Operate's Variables tab fetches the scope's variables once per page
801
+ // load and does not re-poll them — only the instance header and the
802
+ // diagram are polled. So when a slow connector job completes *after* the
803
+ // panel has already rendered (AWS Bedrock knowledge-base retrieval has
804
+ // been observed taking ~6 minutes), the header flips to COMPLETED while
805
+ // the Variables panel still shows the pre-completion snapshot
806
+ // ("The element has no variables") and the output variable never appears.
807
+ // Reload between attempts so each retry re-fetches the variables, the
808
+ // same recovery `assertProcessVariableContainsText` already uses.
809
+ async assertProcessVariableIsVisible(variableName, timeout = 30000, maxRetries = 3) {
810
+ for (let retries = 0; retries < maxRetries; retries++) {
811
+ try {
812
+ await (0, test_1.expect)(this.connectorResultVariableName(variableName)).toBeVisible({ timeout: timeout });
813
+ return;
814
+ }
815
+ catch (error) {
816
+ console.log(`Variable ${variableName} is not visible yet (attempt ${retries + 1}): ${error}`);
817
+ await this.page.reload();
818
+ await (0, sleep_1.sleep)(10000);
819
+ }
820
+ }
821
+ throw new Error(`Variable ${variableName} was not visible after ${maxRetries} attempts.`);
822
+ }
800
823
  async assertProcessVariableContainsText(variableName, text) {
801
824
  const maxRetries = 3;
802
825
  for (let retries = 0; retries < maxRetries; retries++) {
@@ -66,20 +66,38 @@ class OperateHomePage {
66
66
  await this.variableValueInput.clear();
67
67
  }
68
68
  async fillVariableValueInput(newValue) {
69
- // clickEditVariableButton triggers autoFocus → editor.focus() in Monaco's
70
- // onMount. Wait for the cursor to confirm Monaco has keyboard focus before
71
- // sending events. Scoped to the variable row to avoid matching other editors.
72
- await this.page
73
- .getByTestId('variable-testVariable')
74
- .locator('.monaco-editor .cursor')
69
+ // Operate migrated this editor from Monaco to CodeMirror
70
+ // (@uiw/react-codemirror; see camunda/camunda#62782) -- the editable
71
+ // region is now a div.cm-content, not .monaco-editor, and it no longer
72
+ // exposes a Monaco-style .cursor element. clickEditVariableButton still
73
+ // triggers autoFocus, so wait for the content element to actually have
74
+ // focus (:focus) before sending events, same intent as the old cursor
75
+ // check. Scoped to the variable row to avoid matching other editors.
76
+ const variableRow = this.page.getByTestId('variable-testVariable');
77
+ await variableRow
78
+ .locator('.cm-content:focus')
75
79
  .first()
76
80
  .waitFor({ state: 'visible', timeout: 30000 });
77
- // Select all, then replace with insertText (single InputEvent dispatch).
78
- // keyboard.type() triggers Monaco's auto-close-quote feature which inserts
79
- // an extra closing quote and produces invalid JSON. insertText dispatches one
80
- // input event that replaces the selection atomically, bypassing auto-close.
81
- await this.page.keyboard.press('Control+A');
82
- await this.page.keyboard.insertText(`"${newValue}`);
81
+ // Insert the COMPLETE JSON value, both quotes included. Monaco used to
82
+ // auto-close a lone opening quote, so the old recipe inserted only
83
+ // `"value`; CodeMirror's closeBrackets extension ignores insertions
84
+ // longer than two characters, which left the string unterminated. That
85
+ // is invalid JSON, and EditButtons.tsx keeps "Save variable" disabled
86
+ // while hasValidationErrors -- the nightly timed out clicking a button
87
+ // that could never become enabled. Same recipe as
88
+ // pages/8.10/OperateHomePage.ts: select all, clear, insert the whole
89
+ // value in a single input event (no intermediate state to race, and
90
+ // multi-character insertText is not subject to auto-close), then
91
+ // confirm the editor actually holds it.
92
+ // ControlOrMeta+A (not Control+A) so select-all also works on Mac --
93
+ // same cross-platform shortcut the sibling page objects use for this
94
+ // exact operation (pages/SM-8.10/OperateHomePage.ts,
95
+ // pages/8.9/OCIdentityClusterVariablesPage.ts).
96
+ await this.page.keyboard.press('ControlOrMeta+A');
97
+ await this.page.keyboard.press('Backspace');
98
+ const jsonValue = JSON.stringify(newValue);
99
+ await this.page.keyboard.insertText(jsonValue);
100
+ await (0, test_1.expect)(variableRow.locator('.cm-content').first()).toContainText(jsonValue, { timeout: 10000 });
83
101
  }
84
102
  async clickSaveVariableButton() {
85
103
  await this.saveVariableButton.click({ timeout: 30000 });
@@ -213,7 +213,14 @@ class TaskDetailsPage {
213
213
  throw new Error(`Active icon not visible after ${maxRetries} attempts.`);
214
214
  }
215
215
  async assertVariableValue(variableName, variableValue) {
216
- await (0, test_1.expect)(this.page.getByTitle(variableName + ' Value')).toHaveValue(variableValue, { timeout: 60000 });
216
+ // Tasklist migrated its variables editor to the shadcn design system
217
+ // (@camunda/design-system's Label + LoadingTextarea/TextInput, see
218
+ // camunda/camunda#60894). The value field's accessible name comes from a
219
+ // visually-hidden <label> ("<variable name> Value", via
220
+ // taskVariablesValueLabel) associated by htmlFor -- the old Carbon input
221
+ // exposed the same string as an HTML title attribute, which getByTitle
222
+ // matched directly; getByLabel is the equivalent for a real <label>.
223
+ await (0, test_1.expect)(this.page.getByLabel(variableName + ' Value')).toHaveValue(variableValue, { timeout: 60000 });
217
224
  }
218
225
  }
219
226
  exports.TaskDetailsPage = TaskDetailsPage;
@@ -13,8 +13,11 @@ class TaskListLoginPage {
13
13
  this.usernameInput = page.getByLabel('Username');
14
14
  this.passwordInput = page.getByRole('textbox', { name: 'password' });
15
15
  this.loginButton = page.getByRole('button', { name: 'Login' });
16
+ // The header logo's accessible name is now just "Camunda logo" (the old
17
+ // Carbon header appended the product name, "Camunda logo Tasklist") --
18
+ // see camunda/camunda#60894.
16
19
  this.taskListPageBanner = page.getByRole('link', {
17
- name: 'Camunda logo Tasklist',
20
+ name: 'Camunda logo',
18
21
  });
19
22
  }
20
23
  async fillUsername(username) {
@@ -4,12 +4,10 @@ declare class TaskPanelPage {
4
4
  readonly assignToMeButton: Locator;
5
5
  readonly availableTasks: Locator;
6
6
  readonly completeTaskButton: Locator;
7
- readonly collapseSidePanelButton: Locator;
8
7
  readonly emptyTaskMessage: Locator;
9
- readonly expandSidePanelButton: Locator;
8
+ readonly filterSelectButton: Locator;
10
9
  private page;
11
10
  readonly taskListPageBanner: Locator;
12
- readonly collapseFilter: Locator;
13
11
  constructor(page: Page);
14
12
  assertAssigmentStatus(status: string): Promise<void>;
15
13
  assignTaskToMe(): Promise<void>;
@@ -18,6 +16,5 @@ declare class TaskPanelPage {
18
16
  taskListBannerIsVisible(): Promise<void>;
19
17
  asssertUnnassignedTaskEmptyMessage(): Promise<void>;
20
18
  filterBy(option: 'All open tasks' | 'Unassigned' | 'Assigned to me' | 'Completed' | 'Custom'): Promise<void>;
21
- clickCollapseFilter(): Promise<void>;
22
19
  }
23
20
  export { TaskPanelPage };
@@ -14,29 +14,33 @@ class TaskPanelPage {
14
14
  assignToMeButton;
15
15
  availableTasks;
16
16
  completeTaskButton;
17
- collapseSidePanelButton;
18
17
  emptyTaskMessage;
19
- expandSidePanelButton;
18
+ filterSelectButton;
20
19
  page;
21
20
  taskListPageBanner;
22
- collapseFilter;
23
21
  constructor(page) {
24
22
  this.page = page;
25
23
  this.assignmentTag = page.locator(' header > div').nth(2);
26
24
  this.assignToMeButton = page.getByRole('button', { name: 'Assign to me' });
27
25
  this.availableTasks = page.getByTitle('Available tasks');
28
26
  this.completeTaskButton = page.getByRole('button', { name: 'Complete Task' });
29
- this.collapseSidePanelButton = page.locator('button[aria-controls="task-nav-bar"][aria-expanded="true"]');
30
27
  this.emptyTaskMessage = this.emptyTaskMessage = page.getByRole('heading', {
31
28
  name: /Task has no variables/i,
32
29
  });
33
- this.expandSidePanelButton = page
34
- .locator('[aria-label="Filter controls"] li')
35
- .filter({ hasText: 'Expand to show filters' });
30
+ // The old Carbon expandable filter sidebar ([aria-label="Filter
31
+ // controls"], "Expand to show filters") no longer exists on the shadcn
32
+ // UI shipped since camunda/camunda#60894. Filtering is now a single
33
+ // dropdown-trigger button (accessible name "Filters") that opens a menu
34
+ // of filter options -- see filterBy() below.
35
+ this.filterSelectButton = page.getByRole('button', {
36
+ name: 'Filters',
37
+ exact: true,
38
+ });
39
+ // The header logo's accessible name is now just "Camunda logo" (the old
40
+ // Carbon header appended the product name, "Camunda logo Tasklist").
36
41
  this.taskListPageBanner = page.getByRole('link', {
37
- name: 'Camunda logo Tasklist',
42
+ name: 'Camunda logo',
38
43
  });
39
- this.collapseFilter = page.locator('button[aria-controls="task-nav-bar"][aria-expanded="false"]');
40
44
  }
41
45
  async assertAssigmentStatus(status) {
42
46
  await (0, test_1.expect)(this.assignmentTag).toContainText(status);
@@ -70,12 +74,27 @@ class TaskPanelPage {
70
74
  await (0, test_1.expect)(this.emptyTaskMessage).toBeVisible();
71
75
  }
72
76
  async filterBy(option) {
73
- await this.expandSidePanelButton.click();
74
- await this.page.getByRole('link', { name: option, exact: true }).click();
75
- await this.collapseSidePanelButton.click();
76
- }
77
- async clickCollapseFilter() {
78
- await this.collapseFilter.click({ timeout: 45000 });
77
+ // Open the filter dropdown, then pick the option from the menu that
78
+ // appears. Unlike the old Carbon sidebar, the trigger is always visible
79
+ // -- there's no separate expand/collapse step, and selecting an option
80
+ // closes the menu on its own.
81
+ await (0, test_1.expect)(this.filterSelectButton).toBeVisible({ timeout: 10000 });
82
+ await this.filterSelectButton.click();
83
+ const menuItem = this.page.getByRole('menuitem', {
84
+ name: option,
85
+ exact: true,
86
+ });
87
+ await (0, test_1.expect)(menuItem).toBeVisible({ timeout: 10000 });
88
+ await menuItem.click();
89
+ await (0, test_1.expect)(menuItem).toBeHidden({ timeout: 10000 });
90
+ // The trigger renders the active filter's label, so this confirms the
91
+ // selection was applied -- the same signal camunda/camunda's own
92
+ // Filters.test.tsx asserts on the trigger. It replaces the heading the
93
+ // old Carbon panel rendered for the active filter, which the shadcn
94
+ // panel no longer has.
95
+ await (0, test_1.expect)(this.filterSelectButton).toContainText(option, {
96
+ timeout: 10000,
97
+ });
79
98
  }
80
99
  }
81
100
  exports.TaskPanelPage = TaskPanelPage;
@@ -106,7 +106,7 @@ _8_10_1.test.describe('AWS Connectors User Flows', () => {
106
106
  await operateProcessInstancePage.assertProcessCompleteStatusWithRetry();
107
107
  // Assert retrievedChunks variable is present and contains at least one
108
108
  // entry with a sourceUri (list with at least one entry containing a source URI)
109
- await (0, test_1.expect)(operateProcessInstancePage.connectorResultVariableName('retrievedChunks')).toBeVisible({ timeout: 30000 });
109
+ await operateProcessInstancePage.assertProcessVariableIsVisible('retrievedChunks');
110
110
  await operateProcessInstancePage.assertProcessVariableContainsText('retrievedChunks', 'sourceUri');
111
111
  });
112
112
  });
@@ -135,10 +135,13 @@ c8Run_8_10_1.test.describe('HTO User Flow Tests', () => {
135
135
  await (0, UtilitiesPage_1.completeTaskWithRetry)(taskPanelPage, taskDetailsPage, 'priorityTest2', 'medium');
136
136
  await (0, UtilitiesPage_1.completeTaskWithRetry)(taskPanelPage, taskDetailsPage, 'priorityTest1', 'low');
137
137
  await taskPanelPage.filterBy('Completed');
138
- await (0, test_1.expect)(page.getByRole('heading', { name: 'completed' })).toBeVisible({
139
- timeout: 45000,
140
- });
141
- await taskPanelPage.clickCollapseFilter();
138
+ // The shadcn task panel no longer renders the active filter as a
139
+ // heading (filterBy asserts it on the Filters trigger instead), so
140
+ // wait for a completed task to actually appear in the list -- that
141
+ // also covers the indexing lag before the reload below.
142
+ await (0, test_1.expect)(taskPanelPage.availableTasks
143
+ .getByText('priorityTest4', { exact: true })
144
+ .first()).toBeVisible({ timeout: 45000 });
142
145
  await page.reload();
143
146
  await (0, sleep_1.sleep)(1000);
144
147
  await taskPanelPage.openTask('priorityTest4');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1153",
3
+ "version": "0.0.1155",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",