@camunda/e2e-test-suite 0.0.809 → 0.0.810

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.
@@ -9,6 +9,8 @@ declare class FormJsPage {
9
9
  readonly textField: Locator;
10
10
  readonly documentPreview: Locator;
11
11
  readonly keyInput: Locator;
12
+ readonly fieldLabelInput: Locator;
13
+ readonly formIdInput: Locator;
12
14
  readonly uploadMultipleFilesToggle: Locator;
13
15
  readonly documentReferenceInput: Locator;
14
16
  readonly generalPanel: Locator;
@@ -25,6 +27,8 @@ declare class FormJsPage {
25
27
  clickGenerateFormButton(): Promise<void>;
26
28
  dragAndDrop(source: Locator, target: Locator): Promise<void>;
27
29
  fillKeyInput(key: string): Promise<void>;
30
+ fillFieldLabel(label: string): Promise<void>;
31
+ fillFormId(id: string): Promise<void>;
28
32
  enableUploadMultipleFiles(): Promise<void>;
29
33
  filldocumentReferenceInput(key: string): Promise<void>;
30
34
  clickGeneralPropertiesPanel(): Promise<void>;
@@ -13,6 +13,8 @@ class FormJsPage {
13
13
  textField;
14
14
  documentPreview;
15
15
  keyInput;
16
+ fieldLabelInput;
17
+ formIdInput;
16
18
  uploadMultipleFilesToggle;
17
19
  documentReferenceInput;
18
20
  generalPanel;
@@ -33,6 +35,10 @@ class FormJsPage {
33
35
  this.filePicker = page.locator('button[data-field-type="filepicker"]');
34
36
  this.textField = page.locator('button[data-field-type="textfield"]');
35
37
  this.keyInput = page.getByRole('textbox', { name: 'key' });
38
+ this.fieldLabelInput = page.locator('#bio-properties-panel-label');
39
+ // Form-root "Form ID" entry in the form-js editor properties panel; the
40
+ // BPMN start-event link uses a different entry ("formId"), so no collision.
41
+ this.formIdInput = page.locator('#bio-properties-panel-id');
36
42
  this.uploadMultipleFilesToggle = page.locator('div[data-entry-id="multiple"] .bio-properties-panel-toggle-switch__switcher');
37
43
  this.documentReferenceInput = page.getByRole('textbox', {
38
44
  name: 'document reference',
@@ -89,6 +95,23 @@ class FormJsPage {
89
95
  await (0, test_1.expect)(this.keyInput).toHaveValue(key, { timeout: 20000 });
90
96
  await (0, sleep_1.sleep)(1000);
91
97
  }
98
+ async fillFieldLabel(label) {
99
+ // "Field label" is a contenteditable (FEEL-capable) editor, not an <input>,
100
+ // so assert its text content rather than a form value.
101
+ await this.fieldLabelInput.fill(label, { timeout: 60000 });
102
+ await (0, test_1.expect)(this.fieldLabelInput).toContainText(label, { timeout: 20000 });
103
+ await (0, sleep_1.sleep)(1000);
104
+ }
105
+ async fillFormId(id) {
106
+ // On a new form the General group is collapsed; expand it so the form-root
107
+ // "Form ID" input is visible before filling.
108
+ if (!(await this.formIdInput.isVisible())) {
109
+ await this.clickGeneralPropertiesPanel();
110
+ }
111
+ await this.formIdInput.fill(id, { timeout: 60000 });
112
+ await (0, test_1.expect)(this.formIdInput).toHaveValue(id, { timeout: 20000 });
113
+ await (0, sleep_1.sleep)(1000);
114
+ }
92
115
  async enableUploadMultipleFiles() {
93
116
  await this.uploadMultipleFilesToggle.click({ timeout: 60000 });
94
117
  }
@@ -219,6 +219,7 @@ declare class ModelerCreatePage {
219
219
  expandPublicationSection(): Promise<void>;
220
220
  enablePublicAccessIfDisabled(): Promise<void>;
221
221
  clickPublicationTab(): Promise<void>;
222
+ ensureCopyPublicLinkButtonVisible(): Promise<void>;
222
223
  clickCopyPublicLinkButton(): Promise<void>;
223
224
  getPublicationLink(): Promise<string>;
224
225
  assertFormEmbedded(): Promise<void>;
@@ -219,8 +219,8 @@ class ModelerCreatePage {
219
219
  name: 'Toggle public access',
220
220
  });
221
221
  this.publicationTab = page.getByRole('tab', { name: 'Publication' });
222
- this.copyPublicLinkButton = page.getByRole('button', {
223
- name: 'Copy public link',
222
+ this.copyPublicLinkButton = page.getByRole('textbox', {
223
+ name: 'Copy to clipboard',
224
224
  });
225
225
  this.closeButton = page.getByRole('button', { name: 'Close' });
226
226
  this.rbaEnabledDeployedDialog = page.getByRole('dialog', {
@@ -1230,7 +1230,7 @@ class ModelerCreatePage {
1230
1230
  await this.startEventElement.click({ timeout: 90000 });
1231
1231
  await (0, sleep_1.sleep)(1000);
1232
1232
  await this.expandFormsSection();
1233
- await this.formLinkTypeOptions.selectOption('Camunda form (linked)');
1233
+ await this.formLinkTypeOptions.selectOption('camunda-form-linked');
1234
1234
  await this.fillFormIdInput(formId);
1235
1235
  if (isPublic) {
1236
1236
  await this.enablePublicAccessIfDisabled();
@@ -1265,21 +1265,35 @@ class ModelerCreatePage {
1265
1265
  },
1266
1266
  });
1267
1267
  }
1268
+ async ensureCopyPublicLinkButtonVisible() {
1269
+ await this.clickPublicationTab();
1270
+ for (let attempt = 0; attempt < 3; attempt++) {
1271
+ const isVisible = await this.copyPublicLinkButton.isVisible();
1272
+ if (isVisible) {
1273
+ return;
1274
+ }
1275
+ await this.page.reload();
1276
+ await this.page.waitForLoadState('load');
1277
+ await this.clickStartEventElement();
1278
+ await this.clickPublicationTab();
1279
+ }
1280
+ await (0, test_1.expect)(this.copyPublicLinkButton).toBeVisible({ timeout: 60000 });
1281
+ }
1268
1282
  async clickCopyPublicLinkButton() {
1283
+ await this.ensureCopyPublicLinkButtonVisible();
1269
1284
  await this.copyPublicLinkButton.click({ timeout: 60000 });
1270
1285
  }
1271
1286
  async getPublicationLink() {
1272
- await this.clickPublicationTab();
1273
- await (0, test_1.expect)(this.copyPublicLinkButton).toBeVisible({ timeout: 60000 });
1274
- await this.clickCopyPublicLinkButton();
1275
- await (0, sleep_1.sleep)(1000);
1276
- const context = this.page.context();
1277
- await context.grantPermissions(['clipboard-read']);
1278
- const clipboardText = await this.page.evaluate(async () => {
1279
- return await navigator.clipboard.readText();
1280
- });
1281
- console.log('Captured public link:', clipboardText);
1282
- return clipboardText;
1287
+ await this.ensureCopyPublicLinkButtonVisible();
1288
+ const codeLocator = this.copyPublicLinkButton.locator('code');
1289
+ // The publication tab polls every 3s for active links; wait until the URL
1290
+ // is present in the DOM before reading it to avoid a race with re-renders.
1291
+ await (0, test_1.expect)(codeLocator).toContainText(/https?:\/\//, { timeout: 60000 });
1292
+ const linkText = await codeLocator.innerText({ timeout: 10000 });
1293
+ const link = linkText.trim();
1294
+ (0, test_1.expect)(link).toMatch(/^https?:\/\//);
1295
+ console.log('Captured public link:', link);
1296
+ return link;
1283
1297
  }
1284
1298
  async assertFormEmbedded() {
1285
1299
  await (0, test_1.expect)(this.formLinkedSuccessMessage).toBeVisible({ timeout: 15000 });
@@ -15,7 +15,6 @@ const UtilitiesPage_1 = require("../../pages/8.9/UtilitiesPage");
15
15
  const deleteOrg_1 = require("../../utils/deleteOrg");
16
16
  const sleep_1 = require("../../utils/sleep");
17
17
  const mailSlurpClient_1 = require("../../utils/mailSlurpClient");
18
- const resetSession_1 = require("../../utils/resetSession");
19
18
  const users_1 = require("../../utils/users");
20
19
  const testUser = (0, users_1.getTestUser)('eleventhUser');
21
20
  _8_9_1.test.describe.configure({ mode: 'parallel' });
@@ -415,12 +414,16 @@ _8_9_1.test.describe('Web Modeler User Flow Tests', () => {
415
414
  await (0, UtilitiesPage_1.assertLocatorVisibleWithRetry)(operateProcessInstancePage, operateProcessInstancePage.completedIcon, 'Completed icon', 60000, false, 5);
416
415
  });
417
416
  });
418
- //Skipped due to 25521: https://github.com/camunda/camunda-hub/issues/25521
419
- _8_9_1.test.skip('Form.js Integration with User Task and Public Form @tasklistV1', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, browser, }) => {
417
+ (0, _8_9_1.test)('Form.js Integration with User Task and Public Form @tasklistV1', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, taskDetailsPage, taskPanelPage, operateHomePage, operateProcessesPage, operateProcessInstancePage, browser, }) => {
420
418
  _8_9_1.test.slow();
421
419
  const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
422
420
  const processName = 'User_Task_Process_With_Public_Form' + randomString;
423
421
  const formName = 'Public form' + randomString;
422
+ // Unique per run so repeated runs in the shared project never collide and
423
+ // the start-event link resolves to exactly one form.
424
+ const publicFormId = 'Public_Form_' + randomString;
425
+ const publicFormFieldKey = 'Public_Form_Field_' + randomString;
426
+ const publicFormSubmission = 'Test submission from public link';
424
427
  await _8_9_1.test.step('Navigate to Web Modeler', async () => {
425
428
  await (0, test_1.expect)(homePage.camundaComponentsButton).toBeVisible({
426
429
  timeout: 120000,
@@ -439,10 +442,17 @@ _8_9_1.test.describe('Web Modeler User Flow Tests', () => {
439
442
  await modelerHomePage.clickFormOption();
440
443
  await modelerHomePage.enterFormName(formName);
441
444
  await (0, sleep_1.sleep)(10000);
445
+ // Set the form's own ID so the start-event link resolves to a deployed
446
+ // form; otherwise the public form 404s.
447
+ await formJsPage.fillFormId(publicFormId);
442
448
  await formJsPage.dragAndDrop(formJsPage.textField, formJsPage.formEditor);
443
449
  await formJsPage.clickGeneralPropertiesPanel();
444
- await formJsPage.fillKeyInput('Public_Form');
450
+ await formJsPage.fillFieldLabel(publicFormFieldKey);
451
+ await formJsPage.fillKeyInput(publicFormFieldKey);
445
452
  await (0, sleep_1.sleep)(10000);
453
+ // Deploy the form as its own cluster resource so Tasklist can serve the
454
+ // public start form; the BPMN deploy alone does not include it.
455
+ await formJsPage.deployForm(clusterName);
446
456
  });
447
457
  await _8_9_1.test.step('Add A BPMN Template To The Project', async () => {
448
458
  await modelerHomePage.clickProjectBreadcrumb();
@@ -451,7 +461,7 @@ _8_9_1.test.describe('Web Modeler User Flow Tests', () => {
451
461
  });
452
462
  await _8_9_1.test.step('Create BPMN Diagram with a User Task with an embedded AI Generated Form and Start Process Instance', async () => {
453
463
  await modelerCreatePage.modelCamundaUserTaskDiagram(processName, processName);
454
- await modelerCreatePage.linkFormToStartEvent('Public_Form', true);
464
+ await modelerCreatePage.linkFormToStartEvent(publicFormId, true);
455
465
  await modelerCreatePage.deployDiagram(clusterName);
456
466
  await (0, sleep_1.sleep)(5000);
457
467
  });
@@ -462,45 +472,49 @@ _8_9_1.test.describe('Web Modeler User Flow Tests', () => {
462
472
  publicFormLink = await modelerCreatePage.getPublicationLink();
463
473
  console.log('Captured public link:', publicFormLink);
464
474
  });
465
- await _8_9_1.test.step('Clear cookies and reset session', async () => {
466
- await (0, resetSession_1.resetSession)(browser, page);
467
- });
468
- await _8_9_1.test.step('Access public form after session reset', async () => {
469
- await page.goto(publicFormLink);
470
- await (0, test_1.expect)(page.getByLabel('Public_Form')).toBeVisible({
471
- timeout: 30000,
472
- });
473
- await page
474
- .getByLabel('Public_Form')
475
- .fill('Test submission from public link');
476
- await page.getByRole('button', { name: 'Submit' }).click();
477
- await (0, test_1.expect)(page.getByText('Form submitted successfully')).toBeVisible({
478
- timeout: 30000,
479
- });
480
- });
481
- await _8_9_1.test.step('View Process Instance in Operate and complete User Task in Tasklist', async () => {
482
- await (0, test_1.expect)(modelerCreatePage.viewProcessInstanceLink).toBeVisible({
483
- timeout: 180000,
484
- });
485
- await modelerCreatePage.clickViewProcessInstanceLink();
486
- const operateTab = await page.waitForEvent('popup', { timeout: 60000 });
487
- const operateTabAppsPage = new AppsPage_1.AppsPage(operateTab);
488
- const operateTabOperateProcessInstancePage = new OperateProcessInstancePage_1.OperateProcessInstancePage(operateTab);
489
- const operateTabTaskPanelPage = new TaskPanelPage_1.TaskPanelPage(operateTab);
490
- const operateTabTaskDetailsPage = new TaskDetailsPage_1.TaskDetailsPage(operateTab);
491
- await (0, test_1.expect)(operateTabOperateProcessInstancePage.activeIcon).toBeVisible({ timeout: 180000 });
492
- await operateTabAppsPage.clickCamundaApps();
493
- await operateTabAppsPage.clickTasklist(clusterName);
494
- await operateTabTaskPanelPage.openTask(processName);
495
- await operateTabTaskDetailsPage.clickAssignToMeButton();
496
- await (0, test_1.expect)(operateTabTaskDetailsPage.assignedToMeText).toBeVisible({
475
+ await _8_9_1.test.step('Access public form anonymously and submit', async () => {
476
+ // A public start form must be reachable without authentication, so open
477
+ // it in a fresh context; the main session stays logged in for the task
478
+ // completion step below.
479
+ const anonContext = await browser.newContext();
480
+ const anonPage = await anonContext.newPage();
481
+ const anonTaskDetailsPage = new TaskDetailsPage_1.TaskDetailsPage(anonPage);
482
+ console.log('Navigating to public form link:', publicFormLink);
483
+ // Re-navigate until the form renders to absorb brief Tasklist import lag
484
+ // after deploy.
485
+ await (0, test_1.expect)(async () => {
486
+ await anonPage.goto(publicFormLink, { waitUntil: 'domcontentloaded' });
487
+ await (0, test_1.expect)(anonTaskDetailsPage.textInput).toBeVisible({
488
+ timeout: 15000,
489
+ });
490
+ }).toPass({ timeout: 120000, intervals: [5000, 10000, 15000] });
491
+ await anonTaskDetailsPage.fillTextInput(publicFormSubmission);
492
+ await anonTaskDetailsPage.clickSubmitButton();
493
+ await (0, test_1.expect)(anonPage.getByRole('heading', { name: 'Success!' })).toBeVisible({ timeout: 30000 });
494
+ await anonContext.close();
495
+ });
496
+ await _8_9_1.test.step('Complete User Task in Tasklist', async () => {
497
+ // The main session is still authenticated, so go straight to Tasklist.
498
+ await appsPage.clickCamundaApps();
499
+ await appsPage.clickTasklist(clusterName);
500
+ await taskPanelPage.openTask(processName);
501
+ await taskDetailsPage.clickAssignToMeButton();
502
+ await (0, test_1.expect)(taskDetailsPage.assignedToMeText).toBeVisible({
497
503
  timeout: 60000,
498
504
  });
499
- await operateTabTaskDetailsPage.fillName('test user');
500
- await operateTabTaskDetailsPage.checkCheckbox();
501
- await operateTabTaskDetailsPage.fillDate('11/11/1999');
502
- await operateTabTaskDetailsPage.fillNumber('10');
503
- await operateTabTaskDetailsPage.clickCompleteTaskButton();
505
+ // The user task has no form; verify the value submitted via the public
506
+ // form is carried into the task variable, then complete it. The variable
507
+ // value is a JSON string, so it is wrapped in quotes.
508
+ await (0, test_1.expect)(page.getByTitle(`${publicFormFieldKey} Value`)).toHaveValue(`"${publicFormSubmission}"`, { timeout: 30000 });
509
+ await taskDetailsPage.clickCompleteTaskButton();
510
+ });
511
+ await _8_9_1.test.step('Assert Process Instance is Completed in Operate', async () => {
512
+ await appsPage.clickCamundaApps();
513
+ await appsPage.clickOperate(clusterName);
514
+ await operateHomePage.clickProcessesTab();
515
+ await operateProcessesPage.clickProcessCompletedCheckbox();
516
+ await operateProcessesPage.clickProcessInstanceLink(processName);
517
+ await operateProcessInstancePage.assertProcessCompleteStatusWithRetry(40000);
504
518
  });
505
519
  });
506
520
  (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.809",
3
+ "version": "0.0.810",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",