@camunda/e2e-test-suite 0.0.451 → 0.0.453
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/ClusterPage.js +1 -0
- package/dist/pages/SM-8.10/ManagementIdentityPage.js +4 -3
- package/dist/pages/SM-8.10/ModelerCreatePage.d.ts +1 -0
- package/dist/pages/SM-8.10/ModelerCreatePage.js +48 -20
- package/dist/pages/SM-8.10/NavigationPage.js +29 -17
- package/dist/pages/SM-8.10/OCIdentityHomePage.js +4 -3
- package/dist/pages/SM-8.10/OCTenantPage.js +3 -5
- package/dist/pages/SM-8.10/OperateHomePage.js +4 -2
- package/dist/pages/SM-8.10/OperateProcessesPage.d.ts +1 -0
- package/dist/pages/SM-8.10/OperateProcessesPage.js +18 -23
- package/dist/pages/SM-8.10/TaskPanelPage.js +2 -3
- package/dist/pages/SM-8.8/ModelerCreatePage.d.ts +1 -0
- package/dist/pages/SM-8.8/ModelerCreatePage.js +22 -20
- package/dist/pages/SM-8.8/OCTenantPage.js +3 -5
- package/dist/pages/SM-8.8/OperateHomePage.js +1 -1
- package/dist/pages/SM-8.8/OperateProcessesPage.js +3 -3
- package/dist/pages/SM-8.8/TaskPanelPage.js +2 -2
- package/dist/pages/SM-8.9/ClusterPage.js +1 -0
- package/dist/pages/SM-8.9/ManagementIdentityPage.js +4 -3
- package/dist/pages/SM-8.9/ModelerCreatePage.d.ts +1 -0
- package/dist/pages/SM-8.9/ModelerCreatePage.js +52 -20
- package/dist/pages/SM-8.9/NavigationPage.js +29 -17
- package/dist/pages/SM-8.9/OCIdentityHomePage.js +4 -3
- package/dist/pages/SM-8.9/OCTenantPage.js +3 -5
- package/dist/pages/SM-8.9/OperateHomePage.js +33 -8
- package/dist/pages/SM-8.9/OperateProcessesPage.js +5 -3
- package/dist/pages/SM-8.9/TaskPanelPage.js +2 -3
- package/dist/tests/SM-8.10/connectors-user-flows.spec.js +15 -8
- package/dist/tests/SM-8.10/hto-user-flows.spec.js +7 -6
- package/dist/tests/SM-8.10/mt-enabled-user-flows.spec.js +41 -38
- package/dist/tests/SM-8.10/rba-enabled-user-flows.spec.js +0 -7
- package/dist/tests/SM-8.8/connectors-user-flows.spec.js +14 -6
- package/dist/tests/SM-8.8/migration-path-user-flows.spec.js +3 -3
- package/dist/tests/SM-8.8/mt-enabled-user-flows.spec.js +40 -38
- package/dist/tests/SM-8.9/connectors-user-flows.spec.js +15 -8
- package/dist/tests/SM-8.9/mt-enabled-user-flows.spec.js +40 -38
- package/dist/utils/resetSession.js +4 -2
- package/package.json +1 -1
|
@@ -22,6 +22,7 @@ class ClusterPage {
|
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
async assertCustomTagsAreVisible(tags) {
|
|
25
|
+
await this.page.waitForLoadState('networkidle');
|
|
25
26
|
for (const tag of tags) {
|
|
26
27
|
await (0, test_1.expect)(this.clustersList.getByText(tag, { exact: true })).toBeVisible({
|
|
27
28
|
timeout: 60000,
|
|
@@ -28,9 +28,10 @@ class ManagementIdentityPage {
|
|
|
28
28
|
orchestrationCheckbox;
|
|
29
29
|
constructor(page) {
|
|
30
30
|
this.page = page;
|
|
31
|
-
this.identityBanner = page
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
this.identityBanner = page
|
|
32
|
+
.locator('a')
|
|
33
|
+
.filter({ hasText: /^Camunda logo\s*Management Identity$/ })
|
|
34
|
+
.first();
|
|
34
35
|
this.usersLink = page.locator('a').filter({ hasText: 'Users' });
|
|
35
36
|
this.tenantTab = page
|
|
36
37
|
.getByRole('link', { name: 'Tenants' })
|
|
@@ -134,6 +134,7 @@ declare class ModelerCreatePage {
|
|
|
134
134
|
clickDeployButton(): Promise<void>;
|
|
135
135
|
clickDeploySubButton(): Promise<void>;
|
|
136
136
|
clickCancelButton(): Promise<void>;
|
|
137
|
+
private recoverModelerSession;
|
|
137
138
|
clickRestConnectorOption(): Promise<void>;
|
|
138
139
|
clickMarketPlaceButton(): Promise<void>;
|
|
139
140
|
completeDeploymentEndpointConfiguration(): Promise<void>;
|
|
@@ -334,6 +334,7 @@ class ModelerCreatePage {
|
|
|
334
334
|
.click({ timeout: 90000 });
|
|
335
335
|
}
|
|
336
336
|
async runProcessInstance(variables = '', tenant = '') {
|
|
337
|
+
await this.page.waitForTimeout(2000); // the canvas autosaves. This can take a second to save.
|
|
337
338
|
const maxRetries = 3;
|
|
338
339
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
339
340
|
try {
|
|
@@ -608,29 +609,48 @@ class ModelerCreatePage {
|
|
|
608
609
|
async clickCancelButton() {
|
|
609
610
|
await this.cancelButton.click();
|
|
610
611
|
}
|
|
612
|
+
async recoverModelerSession() {
|
|
613
|
+
const url = this.page.url().split('?')[0];
|
|
614
|
+
await this.page.context().clearCookies();
|
|
615
|
+
await this.page.goto(url, { timeout: 30000, waitUntil: 'domcontentloaded' });
|
|
616
|
+
const username = process.env.DEMO_USER_EMAIL || 'demo';
|
|
617
|
+
const password = process.env.DISTRO_QA_E2E_TESTS_IDENTITY_FIRSTUSER_PASSWORD || 'demo';
|
|
618
|
+
const loginInput = this.page.locator('#username');
|
|
619
|
+
if (await loginInput.isVisible({ timeout: 5000 }).catch(() => false)) {
|
|
620
|
+
await loginInput.fill(username);
|
|
621
|
+
await this.page.locator('#password').fill(password);
|
|
622
|
+
await this.page.locator('#kc-login').click();
|
|
623
|
+
}
|
|
624
|
+
await (0, test_1.expect)(this.secondElement).toBeVisible({ timeout: 60000 });
|
|
625
|
+
}
|
|
611
626
|
async clickRestConnectorOption() {
|
|
612
627
|
const maxRetries = 4;
|
|
613
628
|
for (let retries = 0; retries < maxRetries; retries++) {
|
|
614
629
|
try {
|
|
615
630
|
if (retries === 0) {
|
|
616
631
|
// First attempt
|
|
617
|
-
await this.restConnectorOption.
|
|
632
|
+
await (0, test_1.expect)(this.restConnectorOption).toBeVisible({ timeout: 60000 });
|
|
633
|
+
await this.restConnectorOption.click({ timeout: 60000 });
|
|
618
634
|
}
|
|
619
635
|
else if (retries === 1 || retries === 2) {
|
|
620
|
-
//
|
|
621
|
-
await this.
|
|
636
|
+
// Recover session cleanly instead of page.reload()
|
|
637
|
+
await this.recoverModelerSession();
|
|
622
638
|
await this.secondElement.click({ timeout: 60000 });
|
|
623
639
|
await this.changeTypeButton.click({ force: true, timeout: 60000 });
|
|
640
|
+
await (0, test_1.expect)(this.restConnectorOption).toBeVisible({ timeout: 90000 });
|
|
624
641
|
await this.restConnectorOption.click({ timeout: 90000 });
|
|
625
642
|
}
|
|
626
643
|
else {
|
|
627
|
-
//
|
|
644
|
+
// Fourth attempt: install via marketplace (real product flow)
|
|
645
|
+
await this.recoverModelerSession();
|
|
646
|
+
await this.secondElement.click({ timeout: 60000 });
|
|
647
|
+
await this.changeTypeButton.click({ force: true, timeout: 60000 });
|
|
628
648
|
await this.clickMarketPlaceButton();
|
|
629
|
-
const
|
|
630
|
-
await
|
|
649
|
+
const marketplace = new ConnectorMarketplacePage_1.ConnectorMarketplacePage(this.page);
|
|
650
|
+
await marketplace.clickSearchForConnectorTextbox();
|
|
631
651
|
await (0, sleep_1.sleep)(5000);
|
|
632
|
-
await
|
|
633
|
-
await
|
|
652
|
+
await marketplace.fillSearchForConnectorTextbox('REST Connector');
|
|
653
|
+
await marketplace.downloadConnectorToProject();
|
|
634
654
|
await this.restConnectorOption.click({ timeout: 120000 });
|
|
635
655
|
}
|
|
636
656
|
return;
|
|
@@ -863,18 +883,26 @@ class ModelerCreatePage {
|
|
|
863
883
|
await this.intermediateBoundaryEvent.click({ timeout: 60000 });
|
|
864
884
|
}
|
|
865
885
|
async clickIntermediateWebhookConnectorOption() {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
886
|
+
const max = 3;
|
|
887
|
+
for (let i = 0; i < max; i++) {
|
|
888
|
+
try {
|
|
889
|
+
await (0, test_1.expect)(this.intermediateWebhookConnectorOption).toBeVisible({
|
|
890
|
+
timeout: 30000,
|
|
891
|
+
});
|
|
892
|
+
await this.intermediateWebhookConnectorOption.click({ timeout: 30000 });
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
catch (err) {
|
|
896
|
+
console.error(`clickIntermediateWebhookConnectorOption attempt ${i + 1} failed: ${err}`);
|
|
897
|
+
if (i === max - 1)
|
|
898
|
+
throw err;
|
|
899
|
+
await this.page.reload();
|
|
900
|
+
await this.page.waitForLoadState('networkidle');
|
|
901
|
+
// Wait for modeler canvas to render after reload before re-selecting
|
|
902
|
+
await (0, test_1.expect)(this.secondElement).toBeVisible({ timeout: 60000 });
|
|
903
|
+
await this.secondElement.click({ force: true, timeout: 30000 });
|
|
904
|
+
await this.changeTypeButton.click({ force: true, timeout: 30000 });
|
|
905
|
+
}
|
|
878
906
|
}
|
|
879
907
|
}
|
|
880
908
|
async clickCorrelationKeyProcessInput() {
|
|
@@ -6,6 +6,9 @@ const LoginPage_1 = require("./LoginPage");
|
|
|
6
6
|
const sleep_1 = require("../../utils/sleep");
|
|
7
7
|
const constants_1 = require("../../utils/constants");
|
|
8
8
|
const ORCHESTRATION_CONTEXT_PATH = process.env.ORCHESTRATION_CONTEXT_PATH ?? '/orchestration';
|
|
9
|
+
const NORMALIZED_ORCHESTRATION_CONTEXT_PATH = ORCHESTRATION_CONTEXT_PATH.startsWith('/')
|
|
10
|
+
? ORCHESTRATION_CONTEXT_PATH
|
|
11
|
+
: `/${ORCHESTRATION_CONTEXT_PATH}`;
|
|
9
12
|
const MODELER_CONTEXT_PATH = process.env.MODELER_CONTEXT_PATH ?? '/modeler';
|
|
10
13
|
const OPTIMIZE_CONTEXT_PATH = process.env.OPTIMIZE_CONTEXT_PATH ?? '/optimize';
|
|
11
14
|
const CONSOLE_CONTEXT_PATH = process.env.CONSOLE_CONTEXT_PATH ?? '/console';
|
|
@@ -37,36 +40,45 @@ class NavigationPage {
|
|
|
37
40
|
name: 'Camunda logo Optimize',
|
|
38
41
|
});
|
|
39
42
|
// TODO: Drop support for Identity once we fully rename it to Admin
|
|
40
|
-
this.identityPageBanner = page
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
this.identityPageBanner = page
|
|
44
|
+
.locator('a')
|
|
45
|
+
.filter({ hasText: /^Camunda logo\s*(Identity|Admin)$/ })
|
|
46
|
+
.first();
|
|
43
47
|
this.consolePageBanner = page.getByRole('link', {
|
|
44
48
|
name: 'Camunda logo Console',
|
|
45
49
|
});
|
|
46
|
-
this.managementIdentityPageBanner = page
|
|
47
|
-
|
|
48
|
-
|
|
50
|
+
this.managementIdentityPageBanner = page
|
|
51
|
+
.locator('a')
|
|
52
|
+
.filter({ hasText: /^Camunda logo\s*Management Identity$/ })
|
|
53
|
+
.first();
|
|
49
54
|
this.keyboardPageBanner = page.locator('#keycloak-bg');
|
|
50
55
|
}
|
|
51
56
|
async goTo(url, banner, sleepTimeout, { username = IDENTITY_FIRSTUSER_USERNAME, password = IDENTITY_FIRSTUSER_PASSWORD, } = {}, maxRetries = 3) {
|
|
52
57
|
const startTime = Date.now();
|
|
53
|
-
let timeout = constants_1._1_SECOND_IN_MS *
|
|
58
|
+
let timeout = constants_1._1_SECOND_IN_MS * 10;
|
|
54
59
|
if (url === '/modeler') {
|
|
55
|
-
timeout = constants_1._1_SECOND_IN_MS *
|
|
60
|
+
timeout = constants_1._1_SECOND_IN_MS * 20;
|
|
56
61
|
}
|
|
57
62
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
58
63
|
try {
|
|
59
64
|
if (sleepTimeout) {
|
|
60
65
|
await (0, sleep_1.sleep)(sleepTimeout);
|
|
61
66
|
}
|
|
62
|
-
await this.page.goto(url, {
|
|
67
|
+
await this.page.goto(url, {
|
|
68
|
+
timeout: 30000,
|
|
69
|
+
waitUntil: 'domcontentloaded',
|
|
70
|
+
});
|
|
63
71
|
const loginPage = new LoginPage_1.LoginPage(this.page);
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
const loginEntryPoint = banner
|
|
73
|
+
.or(loginPage.usernameInput)
|
|
74
|
+
.or(loginPage.coreUsernameInput)
|
|
75
|
+
.or(loginPage.keycloakBanner)
|
|
76
|
+
.first();
|
|
77
|
+
await (0, test_1.expect)(loginEntryPoint).toBeVisible({ timeout: 30000 });
|
|
78
|
+
const isBannerVisible = await banner.isVisible().catch(() => false);
|
|
67
79
|
if (isBannerVisible) {
|
|
68
80
|
try {
|
|
69
|
-
await (0, test_1.expect)(
|
|
81
|
+
await (0, test_1.expect)(loginPage.usernameInput).toBeVisible({ timeout: 5000 });
|
|
70
82
|
await loginPage.login(username, password);
|
|
71
83
|
}
|
|
72
84
|
catch (error) {
|
|
@@ -77,7 +89,7 @@ class NavigationPage {
|
|
|
77
89
|
else {
|
|
78
90
|
await loginPage.login(username, password);
|
|
79
91
|
}
|
|
80
|
-
await (0, test_1.expect)(banner).toBeVisible();
|
|
92
|
+
await (0, test_1.expect)(banner).toBeVisible({ timeout: 60000 });
|
|
81
93
|
return;
|
|
82
94
|
}
|
|
83
95
|
catch (error) {
|
|
@@ -107,10 +119,10 @@ class NavigationPage {
|
|
|
107
119
|
await this.goTo(MODELER_CONTEXT_PATH, this.modelerPageBanner, sleepTimeout, credentials);
|
|
108
120
|
}
|
|
109
121
|
async goToTasklist(sleepTimeout, credentials) {
|
|
110
|
-
await this.goTo(`${
|
|
122
|
+
await this.goTo(`${NORMALIZED_ORCHESTRATION_CONTEXT_PATH}/tasklist`, this.tasklistPageBanner, sleepTimeout, credentials);
|
|
111
123
|
}
|
|
112
124
|
async goToOperate(sleepTimeout, credentials) {
|
|
113
|
-
await this.goTo(`${
|
|
125
|
+
await this.goTo(`${NORMALIZED_ORCHESTRATION_CONTEXT_PATH}/operate`, this.operatePageBanner, sleepTimeout, credentials);
|
|
114
126
|
}
|
|
115
127
|
async goToOptimize(sleepTimeout, credentials) {
|
|
116
128
|
await this.goTo(OPTIMIZE_CONTEXT_PATH, this.optimizePageBanner, sleepTimeout, credentials);
|
|
@@ -123,7 +135,7 @@ class NavigationPage {
|
|
|
123
135
|
await (0, test_1.expect)(this.keyboardPageBanner).toBeVisible({ timeout: 30000 });
|
|
124
136
|
}
|
|
125
137
|
async goToOCAdmin(sleepTimeout, credentials) {
|
|
126
|
-
await this.goTo(`${
|
|
138
|
+
await this.goTo(`${NORMALIZED_ORCHESTRATION_CONTEXT_PATH}/admin`, this.identityPageBanner, sleepTimeout, credentials);
|
|
127
139
|
}
|
|
128
140
|
async goToConsole(sleepTimeout, credentials) {
|
|
129
141
|
await this.goTo(CONSOLE_CONTEXT_PATH, this.consolePageBanner, sleepTimeout, credentials);
|
|
@@ -18,9 +18,10 @@ class OCIdentityHomePage {
|
|
|
18
18
|
licenseKeyTagCommercial;
|
|
19
19
|
constructor(page) {
|
|
20
20
|
this.page = page;
|
|
21
|
-
this.adminBanner = page
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
this.adminBanner = page
|
|
22
|
+
.locator('a')
|
|
23
|
+
.filter({ hasText: /^Camunda logo\s*Admin$/ })
|
|
24
|
+
.first();
|
|
24
25
|
this.groupsTab = page
|
|
25
26
|
.getByRole('banner')
|
|
26
27
|
.locator('a')
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OCTenantPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
-
const sleep_1 = require("../../utils/sleep");
|
|
6
5
|
const findLocatorInPaginatedList_1 = require("../../utils/findLocatorInPaginatedList");
|
|
7
6
|
const expectTextWithPagination_1 = require("../../utils/assertionHelpers/expectTextWithPagination");
|
|
8
7
|
class OCTenantPage {
|
|
@@ -149,7 +148,6 @@ class OCTenantPage {
|
|
|
149
148
|
await this.fillTenantDescriptionInput('This is a test');
|
|
150
149
|
await this.clickCreateTenantSubButton();
|
|
151
150
|
await this.assertTenantCreated();
|
|
152
|
-
await (0, sleep_1.sleep)(30000);
|
|
153
151
|
}
|
|
154
152
|
async assertTenantCreated() {
|
|
155
153
|
try {
|
|
@@ -178,7 +176,7 @@ class OCTenantPage {
|
|
|
178
176
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
179
177
|
try {
|
|
180
178
|
await this.page.reload();
|
|
181
|
-
await
|
|
179
|
+
await this.page.waitForLoadState('networkidle');
|
|
182
180
|
const tenant = this.page.getByText(tenantName).first();
|
|
183
181
|
await (0, findLocatorInPaginatedList_1.findLocatorInPaginatedList)(this.page, tenant);
|
|
184
182
|
await tenant.click({
|
|
@@ -259,14 +257,14 @@ class OCTenantPage {
|
|
|
259
257
|
}
|
|
260
258
|
async fillRoleIdSearchBox(roleId, roleIdentifier) {
|
|
261
259
|
await this.roleIdSearchBox.fill(roleId);
|
|
262
|
-
await this.page.getByText(roleIdentifier).click();
|
|
260
|
+
await this.page.getByText(roleIdentifier).click({ force: true });
|
|
263
261
|
}
|
|
264
262
|
async clickAssignRoleSubButton() {
|
|
265
263
|
await this.assignRoleSubButton.click();
|
|
266
264
|
}
|
|
267
265
|
async assignRoleToTenant(roleId, roleIdentifier) {
|
|
268
266
|
await this.clickRolesTab();
|
|
269
|
-
await
|
|
267
|
+
await this.page.waitForLoadState('networkidle');
|
|
270
268
|
if (await this.row(roleId).isVisible()) {
|
|
271
269
|
console.log(`Role ${roleId} is already assigned to tenant`);
|
|
272
270
|
return;
|
|
@@ -50,7 +50,7 @@ class OperateHomePage {
|
|
|
50
50
|
}
|
|
51
51
|
async clickProcessesTab() {
|
|
52
52
|
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.processesTab, {
|
|
53
|
-
totalTimeout:
|
|
53
|
+
totalTimeout: 60000,
|
|
54
54
|
});
|
|
55
55
|
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.processPageHeading, {
|
|
56
56
|
preAction: async () => {
|
|
@@ -66,7 +66,9 @@ class OperateHomePage {
|
|
|
66
66
|
}
|
|
67
67
|
async clickEditVariableButton(variableName) {
|
|
68
68
|
const editVariableButton = 'variable-' + variableName;
|
|
69
|
-
|
|
69
|
+
const button = this.page.getByTestId(editVariableButton).getByLabel('Edit');
|
|
70
|
+
await (0, test_1.expect)(button).toBeVisible({ timeout: 30000 });
|
|
71
|
+
await button.click();
|
|
70
72
|
}
|
|
71
73
|
async clickVariableValueInput() {
|
|
72
74
|
await this.variableValueInput.click();
|
|
@@ -20,6 +20,7 @@ declare class OperateProcessesPage {
|
|
|
20
20
|
private uncheckActiveCheckbox;
|
|
21
21
|
private toggleActiveCheckboxOn;
|
|
22
22
|
private toggleCompletedCheckbox;
|
|
23
|
+
private applyProcessStateFilter;
|
|
23
24
|
private checkTableForProcess;
|
|
24
25
|
clickProcessActiveCheckbox(): Promise<void>;
|
|
25
26
|
clickProcessCompletedCheckbox(): Promise<void>;
|
|
@@ -109,18 +109,26 @@ class OperateProcessesPage {
|
|
|
109
109
|
await (0, sleep_1.sleep)(200);
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
|
+
async applyProcessStateFilter(type) {
|
|
113
|
+
if (type === 'active') {
|
|
114
|
+
await this.toggleActiveCheckboxOn();
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
await this.toggleCompletedCheckbox();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
112
120
|
async checkTableForProcess(processName) {
|
|
113
121
|
try {
|
|
114
122
|
const processTable = this.page.locator('[aria-label="Process Instances Panel"]');
|
|
115
123
|
await (0, test_1.expect)(processTable).toBeVisible({ timeout: constants_1._1_SECOND_IN_MS * 4 });
|
|
116
|
-
const timeout = env_1.isOpenSearch ? constants_1.
|
|
124
|
+
const timeout = env_1.isOpenSearch ? constants_1._1_MINUTE_IN_MS : constants_1._1_SECOND_IN_MS * 20;
|
|
117
125
|
const row = this.page.locator(`tr:has-text("${processName}")`).first();
|
|
118
126
|
await (0, test_1.expect)(row).toBeVisible({ timeout });
|
|
119
127
|
const link = row.locator('a').first();
|
|
120
|
-
await (0, test_1.expect)(link).toBeVisible({ timeout: constants_1.
|
|
128
|
+
await (0, test_1.expect)(link).toBeVisible({ timeout: constants_1._1_SECOND_IN_MS * 2 });
|
|
121
129
|
await link.scrollIntoViewIfNeeded();
|
|
122
|
-
await link.click({ timeout: constants_1.
|
|
123
|
-
await (0, test_1.expect)(this.page.getByText('Instance History').first()).toBeVisible({ timeout: constants_1._1_SECOND_IN_MS *
|
|
130
|
+
await link.click({ timeout: constants_1._1_SECOND_IN_MS * 2 });
|
|
131
|
+
await (0, test_1.expect)(this.page.getByText('Instance History').first()).toBeVisible({ timeout: constants_1._1_SECOND_IN_MS * 10 });
|
|
124
132
|
if (await this.whatsNewPopUp.isVisible()) {
|
|
125
133
|
await this.gotItButton.click();
|
|
126
134
|
}
|
|
@@ -193,22 +201,15 @@ class OperateProcessesPage {
|
|
|
193
201
|
});
|
|
194
202
|
}
|
|
195
203
|
async clickProcessInstanceLink(processName, type = 'active') {
|
|
204
|
+
await this.applyProcessStateFilter(type);
|
|
196
205
|
if (await this.checkTableForProcess(processName)) {
|
|
197
206
|
return;
|
|
198
207
|
}
|
|
199
|
-
const MAX_ATTEMPTS =
|
|
200
|
-
const TOTAL_TIMEOUT_MS = constants_1._1_MINUTE_IN_MS *
|
|
208
|
+
const MAX_ATTEMPTS = 30;
|
|
209
|
+
const TOTAL_TIMEOUT_MS = constants_1._1_MINUTE_IN_MS * 6;
|
|
201
210
|
let attempt = 0;
|
|
202
211
|
let lastError;
|
|
203
212
|
const startTime = Date.now();
|
|
204
|
-
if (type === 'active') {
|
|
205
|
-
await this.toggleActiveCheckboxOn();
|
|
206
|
-
}
|
|
207
|
-
else {
|
|
208
|
-
await this.toggleCompletedCheckbox();
|
|
209
|
-
}
|
|
210
|
-
// Capture URL after filters are applied so we can navigate back here
|
|
211
|
-
// if a reload redirects away from Operate.
|
|
212
213
|
const operateUrl = this.page.url();
|
|
213
214
|
while (Date.now() - startTime < TOTAL_TIMEOUT_MS &&
|
|
214
215
|
attempt < MAX_ATTEMPTS) {
|
|
@@ -222,15 +223,14 @@ class OperateProcessesPage {
|
|
|
222
223
|
catch (err) {
|
|
223
224
|
lastError = err instanceof Error ? err.message : err;
|
|
224
225
|
console.log(`clickProcessInstanceLink attempt ${attempt}: ${String(lastError)}`);
|
|
226
|
+
await (0, sleep_1.sleep)(constants_1._1_SECOND_IN_MS * 3);
|
|
225
227
|
await this.page
|
|
226
228
|
.reload({ timeout: 30000 })
|
|
227
229
|
.catch(() => console.log('Page reload timed out, continuing...'));
|
|
228
230
|
await this.page
|
|
229
231
|
.waitForLoadState('networkidle', { timeout: 30000 })
|
|
230
232
|
.catch(() => console.log('waitForLoadState networkidle timed out, continuing...'));
|
|
231
|
-
// After reload, the page may redirect away from Operate
|
|
232
|
-
// Tasklist). Navigate back to the original Operate URL if that
|
|
233
|
-
// happens.
|
|
233
|
+
// After reload, the page may redirect away from Operate
|
|
234
234
|
if (!this.page.url().includes('/operate')) {
|
|
235
235
|
await this.page
|
|
236
236
|
.goto(operateUrl, { timeout: 30000 })
|
|
@@ -241,12 +241,7 @@ class OperateProcessesPage {
|
|
|
241
241
|
}
|
|
242
242
|
// Re-apply checkbox filter lost after reload
|
|
243
243
|
try {
|
|
244
|
-
|
|
245
|
-
await this.toggleActiveCheckboxOn();
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
await this.toggleCompletedCheckbox();
|
|
249
|
-
}
|
|
244
|
+
await this.applyProcessStateFilter(type);
|
|
250
245
|
}
|
|
251
246
|
catch (toggleErr) {
|
|
252
247
|
console.log(`Checkbox toggle failed after reload: ${String(toggleErr)}`);
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TaskPanelPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
-
const sleep_1 = require("../../utils/sleep");
|
|
6
5
|
const constants_1 = require("../../utils/constants");
|
|
7
6
|
class TaskPanelPage {
|
|
8
7
|
page;
|
|
@@ -56,7 +55,7 @@ class TaskPanelPage {
|
|
|
56
55
|
if (attempt < 30) {
|
|
57
56
|
console.warn(`Attempt ${attempt} failed. Reloading page...`);
|
|
58
57
|
await this.page.reload();
|
|
59
|
-
await
|
|
58
|
+
await this.page.waitForLoadState('networkidle');
|
|
60
59
|
}
|
|
61
60
|
else {
|
|
62
61
|
throw new Error(`Failed to open task "${name}" after ${attempt} attempts: ${error}`);
|
|
@@ -85,7 +84,7 @@ class TaskPanelPage {
|
|
|
85
84
|
await this.processesPageTab.click();
|
|
86
85
|
}
|
|
87
86
|
async taskCount(name) {
|
|
88
|
-
await
|
|
87
|
+
await this.page.waitForLoadState('networkidle');
|
|
89
88
|
return this.availableTasks.getByText(name, { exact: true }).count();
|
|
90
89
|
}
|
|
91
90
|
async clickTasksTab() {
|
|
@@ -134,6 +134,7 @@ declare class ModelerCreatePage {
|
|
|
134
134
|
clickDeployButton(): Promise<void>;
|
|
135
135
|
clickDeploySubButton(): Promise<void>;
|
|
136
136
|
clickCancelButton(): Promise<void>;
|
|
137
|
+
private recoverModelerSession;
|
|
137
138
|
clickRestConnectorOption(): Promise<void>;
|
|
138
139
|
clickMarketPlaceButton(): Promise<void>;
|
|
139
140
|
completeDeploymentEndpointConfiguration(): Promise<void>;
|
|
@@ -601,36 +601,38 @@ class ModelerCreatePage {
|
|
|
601
601
|
async clickCancelButton() {
|
|
602
602
|
await this.cancelButton.click();
|
|
603
603
|
}
|
|
604
|
+
async recoverModelerSession() {
|
|
605
|
+
const url = this.page.url().split('?')[0];
|
|
606
|
+
await this.page.context().clearCookies();
|
|
607
|
+
await this.page.goto(url, { timeout: 30000, waitUntil: 'domcontentloaded' });
|
|
608
|
+
const username = process.env.DEMO_USER_EMAIL || 'demo';
|
|
609
|
+
const password = process.env.DISTRO_QA_E2E_TESTS_IDENTITY_FIRSTUSER_PASSWORD || 'demo';
|
|
610
|
+
const loginInput = this.page.locator('#username');
|
|
611
|
+
if (await loginInput.isVisible({ timeout: 5000 }).catch(() => false)) {
|
|
612
|
+
await loginInput.fill(username);
|
|
613
|
+
await this.page.locator('#password').fill(password);
|
|
614
|
+
await this.page.locator('#kc-login').click();
|
|
615
|
+
}
|
|
616
|
+
await (0, test_1.expect)(this.secondElement).toBeVisible({ timeout: 60000 });
|
|
617
|
+
}
|
|
604
618
|
async clickRestConnectorOption() {
|
|
605
619
|
const maxRetries = 4;
|
|
606
620
|
for (let retries = 0; retries < maxRetries; retries++) {
|
|
607
621
|
try {
|
|
608
622
|
if (retries === 0) {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
if (!isAlreadyVisible) {
|
|
613
|
-
await this.changeTypeButton.click({ force: true, timeout: 30000 });
|
|
614
|
-
}
|
|
623
|
+
await (0, test_1.expect)(this.restConnectorOption).toBeVisible({ timeout: 60000 });
|
|
624
|
+
await this.restConnectorOption.scrollIntoViewIfNeeded();
|
|
625
|
+
await this.restConnectorOption.click({ timeout: 60000, force: true });
|
|
615
626
|
}
|
|
616
627
|
else {
|
|
617
|
-
//
|
|
618
|
-
|
|
619
|
-
await this.page.reload();
|
|
628
|
+
// Recover session cleanly instead of page.reload()
|
|
629
|
+
await this.recoverModelerSession();
|
|
620
630
|
await this.secondElement.click({ force: true, timeout: 60000 });
|
|
621
631
|
await this.changeTypeButton.click({ force: true, timeout: 60000 });
|
|
632
|
+
await (0, test_1.expect)(this.restConnectorOption).toBeVisible({ timeout: 90000 });
|
|
633
|
+
await this.restConnectorOption.scrollIntoViewIfNeeded();
|
|
634
|
+
await this.restConnectorOption.click({ timeout: 90000, force: true });
|
|
622
635
|
}
|
|
623
|
-
// Use a longer timeout to allow the connector to finish registering
|
|
624
|
-
// after a marketplace download before giving up.
|
|
625
|
-
await (0, test_1.expect)(this.restConnectorOption).toBeVisible({
|
|
626
|
-
timeout: 60000,
|
|
627
|
-
});
|
|
628
|
-
await this.restConnectorOption.scrollIntoViewIfNeeded();
|
|
629
|
-
// force: true bypasses context-pad overlays that can intercept clicks
|
|
630
|
-
await this.restConnectorOption.click({
|
|
631
|
-
timeout: 60000,
|
|
632
|
-
force: true,
|
|
633
|
-
});
|
|
634
636
|
return;
|
|
635
637
|
}
|
|
636
638
|
catch (error) {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.OCTenantPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
-
const sleep_1 = require("../../utils/sleep");
|
|
6
5
|
const findLocatorInPaginatedList_1 = require("../../utils/findLocatorInPaginatedList");
|
|
7
6
|
const expectTextWithPagination_1 = require("../../utils/assertionHelpers/expectTextWithPagination");
|
|
8
7
|
class OCTenantPage {
|
|
@@ -150,7 +149,6 @@ class OCTenantPage {
|
|
|
150
149
|
await this.fillTenantDescriptionInput('This is a test');
|
|
151
150
|
await this.clickCreateTenantSubButton();
|
|
152
151
|
await this.assertTenantCreated();
|
|
153
|
-
await (0, sleep_1.sleep)(30000);
|
|
154
152
|
}
|
|
155
153
|
async assertTenantCreated() {
|
|
156
154
|
try {
|
|
@@ -178,7 +176,7 @@ class OCTenantPage {
|
|
|
178
176
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
179
177
|
try {
|
|
180
178
|
await this.page.reload();
|
|
181
|
-
await
|
|
179
|
+
await this.page.waitForLoadState('networkidle');
|
|
182
180
|
const tenant = this.page.getByText(tenantName).first();
|
|
183
181
|
await (0, findLocatorInPaginatedList_1.findLocatorInPaginatedList)(this.page, tenant);
|
|
184
182
|
await tenant.click({
|
|
@@ -259,14 +257,14 @@ class OCTenantPage {
|
|
|
259
257
|
}
|
|
260
258
|
async fillRoleIdSearchBox(roleId, roleIdentifier) {
|
|
261
259
|
await this.roleIdSearchBox.fill(roleId);
|
|
262
|
-
await this.page.getByText(roleIdentifier).click();
|
|
260
|
+
await this.page.getByText(roleIdentifier).click({ force: true });
|
|
263
261
|
}
|
|
264
262
|
async clickAssignRoleSubButton() {
|
|
265
263
|
await this.assignRoleSubButton.click();
|
|
266
264
|
}
|
|
267
265
|
async assignRoleToTenant(roleId, roleIdentifier) {
|
|
268
266
|
await this.clickRolesTab();
|
|
269
|
-
await
|
|
267
|
+
await this.page.waitForLoadState('networkidle');
|
|
270
268
|
if (await this.row(roleId).isVisible()) {
|
|
271
269
|
console.log(`Role ${roleId} is already assigned to tenant`);
|
|
272
270
|
return;
|
|
@@ -44,7 +44,7 @@ class OperateHomePage {
|
|
|
44
44
|
}
|
|
45
45
|
async clickProcessesTab() {
|
|
46
46
|
await (0, clickLocatorWithRetry_1.clickLocatorWithRetry)(this.page, this.processesTab, {
|
|
47
|
-
totalTimeout:
|
|
47
|
+
totalTimeout: 60000,
|
|
48
48
|
});
|
|
49
49
|
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.processPageHeading, {
|
|
50
50
|
preAction: async () => {
|
|
@@ -155,8 +155,8 @@ class OperateProcessesPage {
|
|
|
155
155
|
if (await this.checkTableForProcess(processName)) {
|
|
156
156
|
return;
|
|
157
157
|
}
|
|
158
|
-
const MAX_ATTEMPTS =
|
|
159
|
-
const TOTAL_TIMEOUT_MS = constants_1._1_MINUTE_IN_MS *
|
|
158
|
+
const MAX_ATTEMPTS = 30;
|
|
159
|
+
const TOTAL_TIMEOUT_MS = constants_1._1_MINUTE_IN_MS * 6;
|
|
160
160
|
let attempt = 0;
|
|
161
161
|
let lastError;
|
|
162
162
|
const startTime = Date.now();
|
|
@@ -180,7 +180,7 @@ class OperateProcessesPage {
|
|
|
180
180
|
lastError = err instanceof Error ? err.message : err;
|
|
181
181
|
console.log(`Attempt ${attempt} failed for "${processName}". URL: ${this.page.url()}. Error: ${String(lastError)}. Reloading...`);
|
|
182
182
|
await this.page.reload();
|
|
183
|
-
await
|
|
183
|
+
await this.page.waitForLoadState('networkidle');
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
throw new Error(`Failed to open instance "${processName}" after ${MAX_ATTEMPTS} attempts. Last error: ${String(lastError)}`);
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TaskPanelPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
-
const sleep_1 = require("../../utils/sleep");
|
|
6
5
|
const constants_1 = require("../../utils/constants");
|
|
7
6
|
class TaskPanelPage {
|
|
8
7
|
page;
|
|
@@ -55,6 +54,7 @@ class TaskPanelPage {
|
|
|
55
54
|
if (attempt < 30) {
|
|
56
55
|
console.warn(`Attempt ${attempt} failed. Reloading page...`);
|
|
57
56
|
await this.page.reload();
|
|
57
|
+
await this.page.waitForLoadState('networkidle');
|
|
58
58
|
}
|
|
59
59
|
else {
|
|
60
60
|
throw new Error(`Failed to open task "${name}" after 3 attempts: ${error}`);
|
|
@@ -83,7 +83,7 @@ class TaskPanelPage {
|
|
|
83
83
|
await this.processesPageTab.click();
|
|
84
84
|
}
|
|
85
85
|
async taskCount(name) {
|
|
86
|
-
await
|
|
86
|
+
await this.page.waitForLoadState('networkidle');
|
|
87
87
|
return this.availableTasks.getByText(name, { exact: true }).count();
|
|
88
88
|
}
|
|
89
89
|
async clickTasksTab() {
|
|
@@ -22,6 +22,7 @@ class ClusterPage {
|
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
async assertCustomTagsAreVisible(tags) {
|
|
25
|
+
await this.page.waitForLoadState('networkidle');
|
|
25
26
|
for (const tag of tags) {
|
|
26
27
|
await (0, test_1.expect)(this.clustersList.getByText(tag, { exact: true })).toBeVisible({
|
|
27
28
|
timeout: 60000,
|
|
@@ -28,9 +28,10 @@ class ManagementIdentityPage {
|
|
|
28
28
|
orchestrationCheckbox;
|
|
29
29
|
constructor(page) {
|
|
30
30
|
this.page = page;
|
|
31
|
-
this.identityBanner = page
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
this.identityBanner = page
|
|
32
|
+
.locator('a')
|
|
33
|
+
.filter({ hasText: /^Camunda logo\s*Management Identity$/ })
|
|
34
|
+
.first();
|
|
34
35
|
this.usersLink = page.locator('a').filter({ hasText: 'Users' });
|
|
35
36
|
this.tenantTab = page
|
|
36
37
|
.getByRole('link', { name: 'Tenants' })
|
|
@@ -134,6 +134,7 @@ declare class ModelerCreatePage {
|
|
|
134
134
|
clickDeployButton(): Promise<void>;
|
|
135
135
|
clickDeploySubButton(): Promise<void>;
|
|
136
136
|
clickCancelButton(): Promise<void>;
|
|
137
|
+
private recoverModelerSession;
|
|
137
138
|
clickRestConnectorOption(): Promise<void>;
|
|
138
139
|
clickMarketPlaceButton(): Promise<void>;
|
|
139
140
|
completeDeploymentEndpointConfiguration(): Promise<void>;
|