@camunda/e2e-test-suite 0.0.715 → 0.0.717

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.
@@ -59,6 +59,7 @@ declare class ModelerCreatePage {
59
59
  readonly formLinkingTypeDropdown: Locator;
60
60
  readonly formLinkTypeOptions: Locator;
61
61
  readonly addFormJsonConfigurationInput: Locator;
62
+ readonly formIdInput: Locator;
62
63
  readonly publicationSection: Locator;
63
64
  readonly publicAccessToggle: Locator;
64
65
  readonly publicationTab: Locator;
@@ -213,7 +214,8 @@ declare class ModelerCreatePage {
213
214
  fillTimerValue(value: string): Promise<void>;
214
215
  clickEighthPlacedElement(): Promise<void>;
215
216
  clickGlobalConnectToolButton(): Promise<void>;
216
- linkFormToStartEvent(formName: string): Promise<void>;
217
+ fillFormIdInput(id: string): Promise<void>;
218
+ linkFormToStartEvent(formId: string, isPublic: boolean): Promise<void>;
217
219
  expandPublicationSection(): Promise<void>;
218
220
  enablePublicAccessIfDisabled(): Promise<void>;
219
221
  clickPublicationTab(): Promise<void>;
@@ -65,6 +65,7 @@ class ModelerCreatePage {
65
65
  formLinkingTypeDropdown;
66
66
  formLinkTypeOptions;
67
67
  addFormJsonConfigurationInput;
68
+ formIdInput;
68
69
  publicationSection;
69
70
  publicAccessToggle;
70
71
  publicationTab;
@@ -210,13 +211,14 @@ class ModelerCreatePage {
210
211
  this.formLinkingTypeDropdown = page.getByLabel('Type');
211
212
  this.formLinkTypeOptions = page.locator('#bio-properties-panel-formType');
212
213
  this.addFormJsonConfigurationInput = page.getByLabel('Form JSON configuration');
214
+ this.formIdInput = page.getByLabel('Form ID');
213
215
  this.publicationSection = page.locator('[data-group-id="group-process-publication"]');
214
216
  this.publicAccessToggle = page.getByRole('switch', {
215
217
  name: 'Toggle public access',
216
218
  });
217
219
  this.publicationTab = page.getByRole('tab', { name: 'Publication' });
218
220
  this.copyPublicLinkButton = page.getByRole('button', {
219
- name: 'Copy to clipboard',
221
+ name: 'Copy public link',
220
222
  });
221
223
  this.closeButton = page.getByRole('button', { name: 'Close' });
222
224
  this.rbaEnabledDeployedDialog = page.getByRole('dialog', {
@@ -1191,10 +1193,18 @@ class ModelerCreatePage {
1191
1193
  await this.globalConnectToolButton.click({ timeout: 90000 });
1192
1194
  await (0, sleep_1.sleep)(1000);
1193
1195
  }
1194
- async linkFormToStartEvent(formName) {
1196
+ async fillFormIdInput(id) {
1197
+ await this.formIdInput.fill(id);
1198
+ }
1199
+ async linkFormToStartEvent(formId, isPublic) {
1195
1200
  await this.startEventElement.click({ timeout: 90000 });
1196
1201
  await (0, sleep_1.sleep)(1000);
1197
- await this.embedForm(formName);
1202
+ await this.expandFormsSection();
1203
+ await this.formLinkTypeOptions.selectOption('Camunda form (linked)');
1204
+ await this.fillFormIdInput(formId);
1205
+ if (isPublic) {
1206
+ await this.enablePublicAccessIfDisabled();
1207
+ }
1198
1208
  }
1199
1209
  async expandPublicationSection() {
1200
1210
  const isExpanded = (await this.publicationSection
@@ -15,6 +15,7 @@ declare class OperateProcessesPage {
15
15
  private readonly gotItButton;
16
16
  private readonly processesTabLink;
17
17
  constructor(page: Page);
18
+ private setCheckboxState;
18
19
  private checkCheckbox;
19
20
  private uncheckCheckbox;
20
21
  private uncheckCompletedCheckbox;
@@ -46,44 +46,49 @@ class OperateProcessesPage {
46
46
  });
47
47
  this.gotItButton = page.getByRole('button', { name: 'Got it' });
48
48
  }
49
- async checkCheckbox(checkbox) {
49
+ // Carbon DS checkboxes are hidden inputs — click the label to trigger React's
50
+ // synthetic event. Operate's filter sidebar is URL-bound and the URL→state
51
+ // hydration that runs on mount can revert a click that races with it, so the
52
+ // setter re-clicks (bounded) when the post-click assertion fails.
53
+ async setCheckboxState(checkbox, desired) {
50
54
  await checkbox.waitFor({ state: 'attached', timeout: constants_1._1_SECOND_IN_MS * 10 });
51
- if (!(await checkbox.isChecked())) {
52
- // Carbon DS checkboxes are hidden inputs — click the label to trigger React's
53
- // synthetic event instead of force-checking the hidden input directly, which
54
- // would be overridden by React's controlled state on the next render.
55
- const checkboxId = await checkbox.getAttribute('id');
56
- if (checkboxId) {
57
- await this.page
58
- .locator(`label[for="${checkboxId}"]`)
59
- .click({ timeout: constants_1._1_SECOND_IN_MS * 30 });
55
+ const checkboxId = await checkbox.getAttribute('id');
56
+ const MAX_ATTEMPTS = 4;
57
+ let lastError;
58
+ for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
59
+ if ((await checkbox.isChecked()) !== desired) {
60
+ if (checkboxId) {
61
+ await this.page
62
+ .locator(`label[for="${checkboxId}"]`)
63
+ .click({ timeout: constants_1._1_SECOND_IN_MS * 10 });
64
+ }
65
+ else if (desired) {
66
+ await checkbox.check({ force: true, timeout: constants_1._1_SECOND_IN_MS * 10 });
67
+ }
68
+ else {
69
+ await checkbox.uncheck({ force: true, timeout: constants_1._1_SECOND_IN_MS * 10 });
70
+ }
60
71
  }
61
- else {
62
- await checkbox.check({ force: true, timeout: constants_1._1_SECOND_IN_MS * 30 });
72
+ try {
73
+ await (0, test_1.expect)(checkbox).toBeChecked({
74
+ checked: desired,
75
+ timeout: constants_1._1_SECOND_IN_MS * 5,
76
+ });
77
+ return;
78
+ }
79
+ catch (err) {
80
+ lastError = err;
63
81
  }
64
- await (0, test_1.expect)(checkbox).toBeChecked({
65
- checked: true,
66
- timeout: constants_1._1_SECOND_IN_MS * 30,
67
- });
68
82
  }
83
+ throw lastError instanceof Error
84
+ ? lastError
85
+ : new Error(`Checkbox did not settle to checked=${desired} after ${MAX_ATTEMPTS} attempts`);
86
+ }
87
+ async checkCheckbox(checkbox) {
88
+ await this.setCheckboxState(checkbox, true);
69
89
  }
70
90
  async uncheckCheckbox(checkbox) {
71
- await checkbox.waitFor({ state: 'attached', timeout: constants_1._1_SECOND_IN_MS * 10 });
72
- if (await checkbox.isChecked()) {
73
- const checkboxId = await checkbox.getAttribute('id');
74
- if (checkboxId) {
75
- await this.page
76
- .locator(`label[for="${checkboxId}"]`)
77
- .click({ timeout: constants_1._1_SECOND_IN_MS * 30 });
78
- }
79
- else {
80
- await checkbox.uncheck({ force: true, timeout: constants_1._1_SECOND_IN_MS * 30 });
81
- }
82
- await (0, test_1.expect)(checkbox).toBeChecked({
83
- checked: false,
84
- timeout: constants_1._1_SECOND_IN_MS * 30,
85
- });
86
- }
91
+ await this.setCheckboxState(checkbox, false);
87
92
  }
88
93
  async uncheckCompletedCheckbox() {
89
94
  await this.uncheckCheckbox(this.processCompletedCheckbox);
@@ -15,6 +15,7 @@ declare class OperateProcessesPage {
15
15
  private readonly gotItButton;
16
16
  private readonly processesTabLink;
17
17
  constructor(page: Page);
18
+ private setCheckboxState;
18
19
  private checkCheckbox;
19
20
  private uncheckCheckbox;
20
21
  private uncheckCompletedCheckbox;
@@ -46,44 +46,49 @@ class OperateProcessesPage {
46
46
  });
47
47
  this.gotItButton = page.getByRole('button', { name: 'Got it' });
48
48
  }
49
- async checkCheckbox(checkbox) {
49
+ // Carbon DS checkboxes are hidden inputs — click the label to trigger React's
50
+ // synthetic event. Operate's filter sidebar is URL-bound and the URL→state
51
+ // hydration that runs on mount can revert a click that races with it, so the
52
+ // setter re-clicks (bounded) when the post-click assertion fails.
53
+ async setCheckboxState(checkbox, desired) {
50
54
  await checkbox.waitFor({ state: 'attached', timeout: constants_1._1_SECOND_IN_MS * 10 });
51
- if (!(await checkbox.isChecked())) {
52
- // Carbon Design System checkboxes use a hidden input + label pattern.
53
- // Clicking the label triggers the React onChange event; .check({force})
54
- // does not fire synthetic events on hidden inputs.
55
- const id = await checkbox.getAttribute('id');
56
- if (id) {
57
- await this.page
58
- .locator(`label[for="${id}"]`)
59
- .click({ timeout: constants_1._1_SECOND_IN_MS * 30 });
55
+ const checkboxId = await checkbox.getAttribute('id');
56
+ const MAX_ATTEMPTS = 4;
57
+ let lastError;
58
+ for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) {
59
+ if ((await checkbox.isChecked()) !== desired) {
60
+ if (checkboxId) {
61
+ await this.page
62
+ .locator(`label[for="${checkboxId}"]`)
63
+ .click({ timeout: constants_1._1_SECOND_IN_MS * 10 });
64
+ }
65
+ else if (desired) {
66
+ await checkbox.check({ force: true, timeout: constants_1._1_SECOND_IN_MS * 10 });
67
+ }
68
+ else {
69
+ await checkbox.uncheck({ force: true, timeout: constants_1._1_SECOND_IN_MS * 10 });
70
+ }
60
71
  }
61
- else {
62
- await checkbox.check({ force: true, timeout: constants_1._1_SECOND_IN_MS * 30 });
72
+ try {
73
+ await (0, test_1.expect)(checkbox).toBeChecked({
74
+ checked: desired,
75
+ timeout: constants_1._1_SECOND_IN_MS * 5,
76
+ });
77
+ return;
78
+ }
79
+ catch (err) {
80
+ lastError = err;
63
81
  }
64
- await (0, test_1.expect)(checkbox).toBeChecked({
65
- checked: true,
66
- timeout: constants_1._1_SECOND_IN_MS * 30,
67
- });
68
82
  }
83
+ throw lastError instanceof Error
84
+ ? lastError
85
+ : new Error(`Checkbox did not settle to checked=${desired} after ${MAX_ATTEMPTS} attempts`);
86
+ }
87
+ async checkCheckbox(checkbox) {
88
+ await this.setCheckboxState(checkbox, true);
69
89
  }
70
90
  async uncheckCheckbox(checkbox) {
71
- await checkbox.waitFor({ state: 'attached', timeout: constants_1._1_SECOND_IN_MS * 10 });
72
- if (await checkbox.isChecked()) {
73
- const id = await checkbox.getAttribute('id');
74
- if (id) {
75
- await this.page
76
- .locator(`label[for="${id}"]`)
77
- .click({ timeout: constants_1._1_SECOND_IN_MS * 30 });
78
- }
79
- else {
80
- await checkbox.uncheck({ force: true, timeout: constants_1._1_SECOND_IN_MS * 30 });
81
- }
82
- await (0, test_1.expect)(checkbox).toBeChecked({
83
- checked: false,
84
- timeout: constants_1._1_SECOND_IN_MS * 30,
85
- });
86
- }
91
+ await this.setCheckboxState(checkbox, false);
87
92
  }
88
93
  async uncheckCompletedCheckbox() {
89
94
  await this.uncheckCheckbox(this.processCompletedCheckbox);
@@ -415,8 +415,8 @@ _8_9_1.test.describe('Web Modeler User Flow Tests', () => {
415
415
  await (0, UtilitiesPage_1.assertLocatorVisibleWithRetry)(operateProcessInstancePage, operateProcessInstancePage.completedIcon, 'Completed icon', 60000, false, 5);
416
416
  });
417
417
  });
418
- //Skipped due to bug 22577: https://github.com/camunda/camunda-hub/issues/22577
419
- _8_9_1.test.skip('Public Start Form @tasklistV1', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, browser, taskDetailsPage, loginPage, taskPanelPage, operateHomePage, operateProcessesPage, operateProcessInstancePage, }) => {
418
+ (0, _8_9_1.test)('Form.js Integration with User Task and AI Generated Form', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, browser, }) => {
419
+ _8_9_1.test.slow();
420
420
  const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
421
421
  const processName = 'User_Task_Process_With_Public_Form' + randomString;
422
422
  const formName = 'Public form' + randomString;
@@ -437,64 +437,69 @@ _8_9_1.test.describe('Web Modeler User Flow Tests', () => {
437
437
  await modelerHomePage.clickDiagramTypeDropdown();
438
438
  await modelerHomePage.clickFormOption();
439
439
  await modelerHomePage.enterFormName(formName);
440
- await (0, sleep_1.sleep)(2000);
440
+ await (0, sleep_1.sleep)(10000);
441
441
  await formJsPage.dragAndDrop(formJsPage.textField, formJsPage.formEditor);
442
442
  await formJsPage.clickGeneralPropertiesPanel();
443
- await formJsPage.fillKeyInput('Public_Form_Text_Field');
444
- await formJsPage.deployForm(clusterName);
443
+ await formJsPage.fillKeyInput('Public_Form');
444
+ await (0, sleep_1.sleep)(10000);
445
445
  });
446
446
  await _8_9_1.test.step('Add A BPMN Template To The Project', async () => {
447
447
  await modelerHomePage.clickProjectBreadcrumb();
448
448
  await modelerHomePage.clickDiagramTypeDropdown();
449
449
  await modelerHomePage.clickBpmnTemplateOption();
450
450
  });
451
- await _8_9_1.test.step('Create BPMN Diagram with a Public Start Form and Deploy the Process', async () => {
451
+ await _8_9_1.test.step('Create BPMN Diagram with a User Task with an embedded AI Generated Form and Start Process Instance', async () => {
452
452
  await modelerCreatePage.modelCamundaUserTaskDiagram(processName, processName);
453
- await modelerCreatePage.linkFormToStartEvent(formName);
454
- await modelerCreatePage.enablePublicAccessIfDisabled();
453
+ await modelerCreatePage.linkFormToStartEvent('Public_Form', true);
455
454
  await modelerCreatePage.deployDiagram(clusterName);
456
455
  await (0, sleep_1.sleep)(5000);
457
456
  });
458
457
  let publicFormLink;
459
- await _8_9_1.test.step('Enable Public Access and Get Publication Link', async () => {
458
+ await _8_9_1.test.step('Enable public access and get publication link', async () => {
459
+ await modelerCreatePage.enablePublicAccessIfDisabled();
460
+ await modelerCreatePage.clickCopyPublicLinkButton();
460
461
  publicFormLink = await modelerCreatePage.getPublicationLink();
461
- await (0, sleep_1.sleep)(1000);
462
+ console.log('Captured public link:', publicFormLink);
462
463
  });
463
- await _8_9_1.test.step('Clear Cookies and Reset Session', async () => {
464
+ await _8_9_1.test.step('Clear cookies and reset session', async () => {
464
465
  await (0, resetSession_1.resetSession)(browser, page);
465
466
  });
466
- await _8_9_1.test.step('Access Public Form After Session Reset and Submit the Form', async () => {
467
- console.log('Navigating to public form:', publicFormLink);
467
+ await _8_9_1.test.step('Access public form after session reset', async () => {
468
468
  await page.goto(publicFormLink);
469
- await (0, test_1.expect)(taskDetailsPage.textInput).toBeVisible({
469
+ await (0, test_1.expect)(page.getByLabel('Public_Form')).toBeVisible({
470
470
  timeout: 30000,
471
471
  });
472
- await taskDetailsPage.fillTextInput('Public Form Test Value');
473
- await taskDetailsPage.clickSubmitButton();
474
- await (0, test_1.expect)(page.getByRole('heading', { name: 'Success!' })).toBeVisible({
472
+ await page
473
+ .getByLabel('Public_Form')
474
+ .fill('Test submission from public link');
475
+ await page.getByRole('button', { name: 'Submit' }).click();
476
+ await (0, test_1.expect)(page.getByText('Form submitted successfully')).toBeVisible({
475
477
  timeout: 30000,
476
478
  });
477
479
  });
478
- await _8_9_1.test.step('Login to Tasklist and Check User Task Has the Correct Input Values and Can Be Completed', async () => {
479
- await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, testUser, 5000);
480
- await appsPage.clickCamundaApps();
481
- await appsPage.clickTasklist(clusterName);
482
- await (0, UtilitiesPage_1.assertLocatorVisibleWithRetry)(page, taskPanelPage.taskListPageBanner, 'Tasklist banner');
483
- await taskPanelPage.openTask(processName);
484
- await (0, test_1.expect)(page
485
- .getByRole('row')
486
- .filter({ hasText: 'Public_Form_Text_Field' })
487
- .getByText('"Public Form Test Value"')).toBeVisible({ timeout: 30000 });
488
- await taskDetailsPage.clickAssignToMeButton();
489
- await taskDetailsPage.clickCompleteTaskButton();
490
- });
491
- await _8_9_1.test.step('Assert Process Instance is Completed in Operate', async () => {
492
- await appsPage.clickCamundaApps();
493
- await appsPage.clickOperate(clusterName);
494
- await operateHomePage.clickProcessesTab();
495
- await operateProcessesPage.clickProcessCompletedCheckbox();
496
- await operateProcessesPage.clickProcessInstanceLink(processName);
497
- await operateProcessInstancePage.assertProcessCompleteStatusWithRetry(40000);
480
+ await _8_9_1.test.step('View Process Instance in Operate and complete User Task in Tasklist', async () => {
481
+ await (0, test_1.expect)(modelerCreatePage.viewProcessInstanceLink).toBeVisible({
482
+ timeout: 180000,
483
+ });
484
+ await modelerCreatePage.clickViewProcessInstanceLink();
485
+ const operateTab = await page.waitForEvent('popup', { timeout: 60000 });
486
+ const operateTabAppsPage = new AppsPage_1.AppsPage(operateTab);
487
+ const operateTabOperateProcessInstancePage = new OperateProcessInstancePage_1.OperateProcessInstancePage(operateTab);
488
+ const operateTabTaskPanelPage = new TaskPanelPage_1.TaskPanelPage(operateTab);
489
+ const operateTabTaskDetailsPage = new TaskDetailsPage_1.TaskDetailsPage(operateTab);
490
+ await (0, test_1.expect)(operateTabOperateProcessInstancePage.activeIcon).toBeVisible({ timeout: 180000 });
491
+ await operateTabAppsPage.clickCamundaApps();
492
+ await operateTabAppsPage.clickTasklist(clusterName);
493
+ await operateTabTaskPanelPage.openTask(processName);
494
+ await operateTabTaskDetailsPage.clickAssignToMeButton();
495
+ await (0, test_1.expect)(operateTabTaskDetailsPage.assignedToMeText).toBeVisible({
496
+ timeout: 60000,
497
+ });
498
+ await operateTabTaskDetailsPage.fillName('test user');
499
+ await operateTabTaskDetailsPage.checkCheckbox();
500
+ await operateTabTaskDetailsPage.fillDate('11/11/1999');
501
+ await operateTabTaskDetailsPage.fillNumber('10');
502
+ await operateTabTaskDetailsPage.clickCompleteTaskButton();
498
503
  });
499
504
  });
500
505
  (0, _8_9_1.test)('Conditional Events - Deploy, verify in Operate and verify process in Optimize dashboard @tasklistV2', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.715",
3
+ "version": "0.0.717",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",