@camunda/e2e-test-suite 0.0.1044 → 0.0.1046
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.
- package/dist/pages/SM-8.10/ModelerCreatePage.js +16 -4
- package/dist/pages/SM-8.10/ModelerHomePage.js +17 -0
- package/dist/pages/SM-8.10/OCTenantPage.d.ts +2 -0
- package/dist/pages/SM-8.10/OCTenantPage.js +21 -5
- package/dist/pages/SM-8.10/OperateProcessInstancePage.js +2 -2
- package/dist/tests/SM-8.10/mt-enabled-user-flows.spec.js +16 -7
- package/package.json +1 -1
|
@@ -870,11 +870,23 @@ class ModelerCreatePage {
|
|
|
870
870
|
// the kebab once they render, so a mouse click lands on the tag instead.
|
|
871
871
|
// Open the menu from the keyboard -- same control, reached the way a
|
|
872
872
|
// keyboard user reaches it, and unaffected by what paints over it.
|
|
873
|
+
//
|
|
874
|
+
// The header also keeps settling after the editor paints -- license tags
|
|
875
|
+
// mount into that same ml-auto sibling and the breadcrumb label swaps to
|
|
876
|
+
// the persisted diagram name -- and either re-render unmounts an already
|
|
877
|
+
// open Radix menu, so re-open it on each attempt instead of clicking into
|
|
878
|
+
// a menu that may already be gone.
|
|
873
879
|
const diagramActions = this.moreActionsButton.last();
|
|
874
|
-
await
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
880
|
+
await (0, test_1.expect)(async () => {
|
|
881
|
+
if (await this.renameMenuItem.isVisible()) {
|
|
882
|
+
await this.page.keyboard.press('Escape');
|
|
883
|
+
await (0, test_1.expect)(this.renameMenuItem).toBeHidden({ timeout: 5000 });
|
|
884
|
+
}
|
|
885
|
+
await diagramActions.focus();
|
|
886
|
+
await diagramActions.press('Enter');
|
|
887
|
+
await this.renameMenuItem.click({ timeout: 15000 });
|
|
888
|
+
await (0, test_1.expect)(this.renameInput).toBeVisible({ timeout: 10000 });
|
|
889
|
+
}).toPass({ timeout: 120000, intervals: [1000, 2000, 5000] });
|
|
878
890
|
await this.renameInput.fill(name);
|
|
879
891
|
await this.renameSubmitButton.click();
|
|
880
892
|
await (0, test_1.expect)(this.renameInput).toBeHidden({ timeout: 10000 });
|
|
@@ -386,6 +386,23 @@ class ModelerHomePage {
|
|
|
386
386
|
// open would otherwise have the next Enter close it again.
|
|
387
387
|
async renameViaMoreActions(name) {
|
|
388
388
|
const entityActions = this.moreActionsButton.last();
|
|
389
|
+
// The header keeps settling after the editor paints: the license tags
|
|
390
|
+
// mount into the ml-auto sibling and the breadcrumb label swaps from its
|
|
391
|
+
// placeholder to the persisted entity name. Either re-render shifts and
|
|
392
|
+
// then unmounts the open Radix menu ("element is not stable", then
|
|
393
|
+
// "element was detached from the DOM"), and the menu item never comes
|
|
394
|
+
// back because the menu itself closed. Re-open the menu on each attempt
|
|
395
|
+
// rather than clicking into one that may already be gone.
|
|
396
|
+
await (0, test_1.expect)(async () => {
|
|
397
|
+
if (await this.renameMenuItem.isVisible()) {
|
|
398
|
+
await this.page.keyboard.press('Escape');
|
|
399
|
+
await (0, test_1.expect)(this.renameMenuItem).toBeHidden({ timeout: 5000 });
|
|
400
|
+
}
|
|
401
|
+
await entityActions.focus();
|
|
402
|
+
await entityActions.press('Enter');
|
|
403
|
+
await this.renameMenuItem.click({ timeout: 15000 });
|
|
404
|
+
await (0, test_1.expect)(this.renameInput).toBeVisible({ timeout: 10000 });
|
|
405
|
+
}).toPass({ timeout: 120000, intervals: [1000, 2000, 5000] });
|
|
389
406
|
await (0, test_1.expect)(async () => {
|
|
390
407
|
await this.page.keyboard.press('Escape');
|
|
391
408
|
await entityActions.focus();
|
|
@@ -23,6 +23,7 @@ declare class OCTenantPage {
|
|
|
23
23
|
readonly assignRoleButton: Locator;
|
|
24
24
|
readonly roleIdSearchBox: Locator;
|
|
25
25
|
readonly assignRoleSubButton: Locator;
|
|
26
|
+
readonly assignRoleModal: Locator;
|
|
26
27
|
readonly cancelButton: Locator;
|
|
27
28
|
readonly gotItButton: Locator;
|
|
28
29
|
readonly filterTableSearchbox: Locator;
|
|
@@ -64,6 +65,7 @@ declare class OCTenantPage {
|
|
|
64
65
|
clickRoleIdSearchBox(): Promise<void>;
|
|
65
66
|
fillRoleIdSearchBox(roleId: string, roleIdentifier: string): Promise<void>;
|
|
66
67
|
clickAssignRoleSubButton(): Promise<void>;
|
|
68
|
+
private isRoleAssigned;
|
|
67
69
|
assignRoleToTenant(roleId: string, roleIdentifier: string): Promise<void>;
|
|
68
70
|
}
|
|
69
71
|
export { OCTenantPage };
|
|
@@ -27,6 +27,7 @@ class OCTenantPage {
|
|
|
27
27
|
assignRoleButton;
|
|
28
28
|
roleIdSearchBox;
|
|
29
29
|
assignRoleSubButton;
|
|
30
|
+
assignRoleModal;
|
|
30
31
|
cancelButton;
|
|
31
32
|
gotItButton;
|
|
32
33
|
filterTableSearchbox;
|
|
@@ -72,9 +73,10 @@ class OCTenantPage {
|
|
|
72
73
|
this.roleIdSearchBox = page.getByRole('searchbox', {
|
|
73
74
|
name: 'Search by Role ID',
|
|
74
75
|
});
|
|
75
|
-
this.
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
this.assignRoleModal = page.getByLabel('Assign role');
|
|
77
|
+
this.assignRoleSubButton = this.assignRoleModal.getByRole('button', {
|
|
78
|
+
name: 'Assign role',
|
|
79
|
+
});
|
|
78
80
|
this.cancelButton = page
|
|
79
81
|
.getByRole('dialog')
|
|
80
82
|
.getByRole('button', { name: 'Cancel' });
|
|
@@ -263,7 +265,10 @@ class OCTenantPage {
|
|
|
263
265
|
await this.roleIdSearchBox.click();
|
|
264
266
|
}
|
|
265
267
|
async fillRoleIdSearchBox(roleId, roleIdentifier) {
|
|
266
|
-
|
|
268
|
+
// Scoped to the modal: the tenant's own roles table sits behind it and
|
|
269
|
+
// carries the same role text, so an unscoped match resolves to that row
|
|
270
|
+
// and its click is intercepted by the modal overlay.
|
|
271
|
+
const result = this.assignRoleModal.getByText(roleIdentifier).first();
|
|
267
272
|
// The dropdown matches against the roles fetched with an empty search
|
|
268
273
|
// filter, so clearing the box re-triggers that fetch before retyping.
|
|
269
274
|
await (0, test_1.expect)(async () => {
|
|
@@ -277,10 +282,21 @@ class OCTenantPage {
|
|
|
277
282
|
async clickAssignRoleSubButton() {
|
|
278
283
|
await this.assignRoleSubButton.click();
|
|
279
284
|
}
|
|
285
|
+
async isRoleAssigned(roleId) {
|
|
286
|
+
return this.row(roleId)
|
|
287
|
+
.waitFor({ state: 'visible', timeout: 15000 })
|
|
288
|
+
.then(() => true)
|
|
289
|
+
.catch(() => false);
|
|
290
|
+
}
|
|
280
291
|
async assignRoleToTenant(roleId, roleIdentifier) {
|
|
281
292
|
await this.clickRolesTab();
|
|
282
293
|
await this.page.waitForLoadState('networkidle');
|
|
283
|
-
|
|
294
|
+
// The roles table renders from its own fetch, which `networkidle` can
|
|
295
|
+
// resolve ahead of, so an immediate `isVisible()` reads the table as empty
|
|
296
|
+
// and reopens the modal for a role that is already assigned. The assign
|
|
297
|
+
// dropdown never offers an already-assigned role, so that attempt can
|
|
298
|
+
// never converge.
|
|
299
|
+
if (await this.isRoleAssigned(roleId)) {
|
|
284
300
|
console.log(`Role ${roleId} is already assigned to tenant`);
|
|
285
301
|
return;
|
|
286
302
|
}
|
|
@@ -47,14 +47,14 @@ class OperateProcessInstancePage {
|
|
|
47
47
|
return; // Exit the function if the expectation is met
|
|
48
48
|
}
|
|
49
49
|
catch (error) {
|
|
50
|
-
// If the
|
|
50
|
+
// If the completed icon isn't found, reload the page and try again
|
|
51
51
|
retryCount++;
|
|
52
52
|
console.log(`Attempt ${retryCount} failed. Retrying...`);
|
|
53
53
|
await this.page.reload();
|
|
54
54
|
await this.page.waitForLoadState('domcontentloaded');
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
throw new Error(`
|
|
57
|
+
throw new Error(`Completed icon not visible after ${maxRetries} attempts.`);
|
|
58
58
|
}
|
|
59
59
|
async activeIconAssertion() {
|
|
60
60
|
let retryCount = 0;
|
|
@@ -449,19 +449,28 @@ if (process.env.IS_MT === 'true') {
|
|
|
449
449
|
await modelerCreatePage.runProcessInstance('', tenantName2);
|
|
450
450
|
});
|
|
451
451
|
await SM_8_10_1.test.step('View Process Instances in Operate, and Assert Process Complete in Operate with Correct Tenant', async () => {
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
452
|
+
// Re-entered through `goToOperate` on every attempt: this flow reaches
|
|
453
|
+
// Operate ~10 minutes in, and when the session's token refresh fails
|
|
454
|
+
// the instance route answers with an error document instead of the app
|
|
455
|
+
// shell. The reload loop inside `completedIconAssertion` only
|
|
456
|
+
// re-requests that same document, so the session has to be
|
|
457
|
+
// re-established before the icon can be asserted at all.
|
|
458
|
+
const openCompletedInstance = async (processName) => {
|
|
459
|
+
await (0, test_1.expect)(async () => {
|
|
460
|
+
await navigationPage.goToOperate();
|
|
461
|
+
await operateHomePage.clickProcessesTab();
|
|
462
|
+
await operateProcessesPage.clickProcessInstanceLink(processName, 'completed');
|
|
463
|
+
await operateProcessInstancePage.completedIconAssertion();
|
|
464
|
+
}).toPass({ timeout: 600000, intervals: [5000] });
|
|
465
|
+
};
|
|
466
|
+
await openCompletedInstance(processName1);
|
|
456
467
|
await (0, expectTextWithRetry_1.expectTextWithRetry)(page, '"Awesome!"', {
|
|
457
468
|
postAction: async () => {
|
|
458
469
|
await page.reload();
|
|
459
470
|
},
|
|
460
471
|
});
|
|
461
472
|
await operateProcessInstancePage.tenantNameAssertion(tenantName1);
|
|
462
|
-
await
|
|
463
|
-
await operateProcessesPage.clickProcessInstanceLink(processName2, 'completed');
|
|
464
|
-
await operateProcessInstancePage.completedIconAssertion();
|
|
473
|
+
await openCompletedInstance(processName2);
|
|
465
474
|
await (0, expectTextWithRetry_1.expectTextWithRetry)(page, '"Awesome!"', {
|
|
466
475
|
postAction: async () => {
|
|
467
476
|
await page.reload();
|