@camunda/e2e-test-suite 0.0.934 → 0.0.936
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/KeycloakUtils.js +29 -6
- package/dist/pages/SM-8.10/ModelerHomePage.d.ts +1 -0
- package/dist/pages/SM-8.10/ModelerHomePage.js +28 -8
- package/dist/pages/SM-8.10/NavigationPage.d.ts +4 -0
- package/dist/pages/SM-8.10/NavigationPage.js +21 -0
- package/dist/pages/SM-8.8/ModelerHomePage.d.ts +1 -0
- package/dist/pages/SM-8.8/ModelerHomePage.js +28 -8
- package/dist/pages/SM-8.9/ModelerHomePage.d.ts +1 -0
- package/dist/pages/SM-8.9/ModelerHomePage.js +28 -8
- package/dist/tests/SM-8.10/identity-user-flows.spec.js +4 -5
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createKeycloakUser = exports.createUser = exports.setupKeycloakUser = exports.keycloakAdminCredentials = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
+
const sleep_1 = require("../../utils/sleep");
|
|
5
6
|
const keycloakAdminCredentials = () => {
|
|
6
7
|
return {
|
|
7
8
|
username: process.env.DISTRO_QA_E2E_TESTS_KEYCLOAK_USERNAME || 'admin',
|
|
@@ -33,13 +34,35 @@ async function createUser(navigationPage, identityPage, keycloakLoginPage, keycl
|
|
|
33
34
|
await createIdentityUser(navigationPage, identityPage, username);
|
|
34
35
|
}
|
|
35
36
|
exports.createUser = createUser;
|
|
37
|
+
// Keycloak occasionally serves "We are sorry... Unexpected error when
|
|
38
|
+
// handling authentication request to identity provider" instead of
|
|
39
|
+
// completing the admin login (the same transient 5xx NavigationPage.goTo's
|
|
40
|
+
// progressive backoff already guards against for app logins). This flow logs
|
|
41
|
+
// into the Keycloak admin console directly rather than through goTo, so it
|
|
42
|
+
// needs the same retry of the whole login sequence instead of failing the
|
|
43
|
+
// test outright on the first hit.
|
|
44
|
+
async function loginToKeycloakAdmin(navigationPage, keycloakLoginPage, keycloakAdminPage, maxRetries = 5) {
|
|
45
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
46
|
+
try {
|
|
47
|
+
await navigationPage.goToKeycloak();
|
|
48
|
+
await keycloakLoginPage.toBeVisible();
|
|
49
|
+
await keycloakLoginPage.fillUsername((0, exports.keycloakAdminCredentials)().username);
|
|
50
|
+
await keycloakLoginPage.fillPassword((0, exports.keycloakAdminCredentials)().password);
|
|
51
|
+
await keycloakLoginPage.clickLogin();
|
|
52
|
+
await keycloakAdminPage.toBeVisible();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (attempt >= maxRetries - 1) {
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
console.warn(`[KeycloakUtils] Keycloak admin login attempt ${attempt + 1} failed, retrying: ${error instanceof Error ? error.message : error}`);
|
|
60
|
+
await (0, sleep_1.sleep)(2000 * (attempt + 1));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
36
64
|
async function createKeycloakUser(navigationPage, keycloakLoginPage, keycloakAdminPage, username, password) {
|
|
37
|
-
await navigationPage
|
|
38
|
-
await keycloakLoginPage.toBeVisible();
|
|
39
|
-
await keycloakLoginPage.fillUsername((0, exports.keycloakAdminCredentials)().username);
|
|
40
|
-
await keycloakLoginPage.fillPassword((0, exports.keycloakAdminCredentials)().password);
|
|
41
|
-
await keycloakLoginPage.clickLogin();
|
|
42
|
-
await keycloakAdminPage.toBeVisible();
|
|
65
|
+
await loginToKeycloakAdmin(navigationPage, keycloakLoginPage, keycloakAdminPage);
|
|
43
66
|
await keycloakAdminPage.switchToCamundaPlatform();
|
|
44
67
|
await keycloakAdminPage.clickUsersTab();
|
|
45
68
|
await keycloakAdminPage.clickAddUser();
|
|
@@ -257,17 +257,37 @@ class ModelerHomePage {
|
|
|
257
257
|
async clickUploadFilesButton() {
|
|
258
258
|
await this.uploadFilesButton.click({ timeout: 60000 });
|
|
259
259
|
}
|
|
260
|
+
// Dismisses both Modeler overlays that can sit over the project list.
|
|
260
261
|
async clickMessageBanner() {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
.
|
|
265
|
-
|
|
266
|
-
|
|
262
|
+
// Maintenance/downtime banner
|
|
263
|
+
if (await this.overlayBecameVisible(this.messageBanner)) {
|
|
264
|
+
try {
|
|
265
|
+
await this.messageBanner.click();
|
|
266
|
+
}
|
|
267
|
+
catch {
|
|
268
|
+
// Banner dismissed itself between the probe and the click
|
|
269
|
+
}
|
|
267
270
|
}
|
|
268
|
-
|
|
269
|
-
|
|
271
|
+
// "New features" modal, dismissed after the banner rather than through an
|
|
272
|
+
// .or() chain: that chain stopped at whichever overlay matched first,
|
|
273
|
+
// leaving the other one on top to intercept the caller's next click.
|
|
274
|
+
if (await this.overlayBecameVisible(this.closeButton)) {
|
|
275
|
+
try {
|
|
276
|
+
await this.closeButton.click();
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
// Modal dismissed itself between the probe and the click
|
|
280
|
+
}
|
|
270
281
|
}
|
|
271
282
|
}
|
|
283
|
+
// Probe with waitFor, not isVisible: the "New features" modal renders lazily
|
|
284
|
+
// after page load, and isVisible resolves immediately — Playwright ignores
|
|
285
|
+
// its timeout option — so it misses an overlay that has yet to paint.
|
|
286
|
+
async overlayBecameVisible(overlay) {
|
|
287
|
+
return overlay
|
|
288
|
+
.waitFor({ state: 'visible', timeout: 2000 })
|
|
289
|
+
.then(() => true)
|
|
290
|
+
.catch(() => false);
|
|
291
|
+
}
|
|
272
292
|
}
|
|
273
293
|
exports.ModelerHomePage = ModelerHomePage;
|
|
@@ -30,6 +30,10 @@ declare class NavigationPage {
|
|
|
30
30
|
username: string;
|
|
31
31
|
password: string;
|
|
32
32
|
}): Promise<void>;
|
|
33
|
+
goToOptimizeWithoutAccess({ username, password, }?: {
|
|
34
|
+
username?: string;
|
|
35
|
+
password?: string;
|
|
36
|
+
}): Promise<void>;
|
|
33
37
|
goToKeycloak(maxRetries?: number): Promise<void>;
|
|
34
38
|
goToOCAdmin(sleepTimeout?: number, credentials?: {
|
|
35
39
|
username: string;
|
|
@@ -160,6 +160,27 @@ class NavigationPage {
|
|
|
160
160
|
async goToOptimize(sleepTimeout, credentials) {
|
|
161
161
|
await this.goTo(OPTIMIZE_CONTEXT_PATH, this.optimizePageBanner, sleepTimeout, credentials);
|
|
162
162
|
}
|
|
163
|
+
// `goTo` ends by asserting the app banner, so it cannot be used to reach
|
|
164
|
+
// Optimize as a user without the Optimize role: that request ends on a
|
|
165
|
+
// `text/plain` 403 page carrying neither the banner nor a login form, and
|
|
166
|
+
// every retry burns a full 60s timeout. Navigate and log in only; the
|
|
167
|
+
// caller asserts what the denied page shows.
|
|
168
|
+
async goToOptimizeWithoutAccess({ username = IDENTITY_FIRSTUSER_USERNAME, password = IDENTITY_FIRSTUSER_PASSWORD, } = {}) {
|
|
169
|
+
await this.page.goto(OPTIMIZE_CONTEXT_PATH, {
|
|
170
|
+
timeout: 60000,
|
|
171
|
+
waitUntil: 'domcontentloaded',
|
|
172
|
+
});
|
|
173
|
+
let gatewayReloads = 0;
|
|
174
|
+
while (gatewayReloads < 8 && (await this.isGatewayErrorPage())) {
|
|
175
|
+
await (0, sleep_1.sleep)(constants_1._1_SECOND_IN_MS * 5);
|
|
176
|
+
await this.page.goto(OPTIMIZE_CONTEXT_PATH, {
|
|
177
|
+
timeout: 60000,
|
|
178
|
+
waitUntil: 'domcontentloaded',
|
|
179
|
+
});
|
|
180
|
+
gatewayReloads++;
|
|
181
|
+
}
|
|
182
|
+
await new LoginPage_1.LoginPage(this.page).login(username, password);
|
|
183
|
+
}
|
|
163
184
|
async goToKeycloak(maxRetries = 5) {
|
|
164
185
|
const keycloakUrl = process.env.KEYCLOAK_URL
|
|
165
186
|
? `${process.env.KEYCLOAK_URL}/auth`
|
|
@@ -46,6 +46,7 @@ declare class ModelerHomePage {
|
|
|
46
46
|
clickManageButton(): Promise<void>;
|
|
47
47
|
clickUploadFilesButton(): Promise<void>;
|
|
48
48
|
clickMessageBanner(): Promise<void>;
|
|
49
|
+
private overlayBecameVisible;
|
|
49
50
|
clickIdpApplicationTemplateOption(): Promise<void>;
|
|
50
51
|
enterIdpApplicationName(name: string): Promise<void>;
|
|
51
52
|
selectCluster(clusterName: string): Promise<void>;
|
|
@@ -247,18 +247,38 @@ class ModelerHomePage {
|
|
|
247
247
|
async clickUploadFilesButton() {
|
|
248
248
|
await this.uploadFilesButton.click({ timeout: 60000 });
|
|
249
249
|
}
|
|
250
|
+
// Dismisses both Modeler overlays that can sit over the project list.
|
|
250
251
|
async clickMessageBanner() {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
.
|
|
255
|
-
|
|
256
|
-
|
|
252
|
+
// Maintenance/downtime banner
|
|
253
|
+
if (await this.overlayBecameVisible(this.messageBanner)) {
|
|
254
|
+
try {
|
|
255
|
+
await this.messageBanner.click();
|
|
256
|
+
}
|
|
257
|
+
catch {
|
|
258
|
+
// Banner dismissed itself between the probe and the click
|
|
259
|
+
}
|
|
257
260
|
}
|
|
258
|
-
|
|
259
|
-
|
|
261
|
+
// "New features" modal, dismissed after the banner rather than through an
|
|
262
|
+
// .or() chain: that chain stopped at whichever overlay matched first,
|
|
263
|
+
// leaving the other one on top to intercept the caller's next click.
|
|
264
|
+
if (await this.overlayBecameVisible(this.closeButton)) {
|
|
265
|
+
try {
|
|
266
|
+
await this.closeButton.click();
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
// Modal dismissed itself between the probe and the click
|
|
270
|
+
}
|
|
260
271
|
}
|
|
261
272
|
}
|
|
273
|
+
// Probe with waitFor, not isVisible: the "New features" modal renders lazily
|
|
274
|
+
// after page load, and isVisible resolves immediately — Playwright ignores
|
|
275
|
+
// its timeout option — so it misses an overlay that has yet to paint.
|
|
276
|
+
async overlayBecameVisible(overlay) {
|
|
277
|
+
return overlay
|
|
278
|
+
.waitFor({ state: 'visible', timeout: 2000 })
|
|
279
|
+
.then(() => true)
|
|
280
|
+
.catch(() => false);
|
|
281
|
+
}
|
|
262
282
|
async clickIdpApplicationTemplateOption() {
|
|
263
283
|
await this.idpTemplateOption.click({ timeout: 120000 });
|
|
264
284
|
}
|
|
@@ -240,17 +240,37 @@ class ModelerHomePage {
|
|
|
240
240
|
async clickUploadFilesButton() {
|
|
241
241
|
await this.uploadFilesButton.click({ timeout: 60000 });
|
|
242
242
|
}
|
|
243
|
+
// Dismisses both Modeler overlays that can sit over the project list.
|
|
243
244
|
async clickMessageBanner() {
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
.
|
|
248
|
-
|
|
249
|
-
|
|
245
|
+
// Maintenance/downtime banner
|
|
246
|
+
if (await this.overlayBecameVisible(this.messageBanner)) {
|
|
247
|
+
try {
|
|
248
|
+
await this.messageBanner.click();
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
// Banner dismissed itself between the probe and the click
|
|
252
|
+
}
|
|
250
253
|
}
|
|
251
|
-
|
|
252
|
-
|
|
254
|
+
// "New features" modal, dismissed after the banner rather than through an
|
|
255
|
+
// .or() chain: that chain stopped at whichever overlay matched first,
|
|
256
|
+
// leaving the other one on top to intercept the caller's next click.
|
|
257
|
+
if (await this.overlayBecameVisible(this.closeButton)) {
|
|
258
|
+
try {
|
|
259
|
+
await this.closeButton.click();
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// Modal dismissed itself between the probe and the click
|
|
263
|
+
}
|
|
253
264
|
}
|
|
254
265
|
}
|
|
266
|
+
// Probe with waitFor, not isVisible: the "New features" modal renders lazily
|
|
267
|
+
// after page load, and isVisible resolves immediately — Playwright ignores
|
|
268
|
+
// its timeout option — so it misses an overlay that has yet to paint.
|
|
269
|
+
async overlayBecameVisible(overlay) {
|
|
270
|
+
return overlay
|
|
271
|
+
.waitFor({ state: 'visible', timeout: 2000 })
|
|
272
|
+
.then(() => true)
|
|
273
|
+
.catch(() => false);
|
|
274
|
+
}
|
|
255
275
|
}
|
|
256
276
|
exports.ModelerHomePage = ModelerHomePage;
|
|
@@ -17,8 +17,7 @@ SM_8_10_1.test.describe('Identity User Flow Tests', () => {
|
|
|
17
17
|
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
18
18
|
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
19
19
|
});
|
|
20
|
-
|
|
21
|
-
SM_8_10_1.test.skip('User Roles User Flow on Management Identity @tasklistV2', async ({ page, navigationPage, optimizeHomePage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, modelerHomePage, settingsPage, browser, }) => {
|
|
20
|
+
(0, SM_8_10_1.test)('User Roles User Flow on Management Identity @tasklistV2', async ({ page, navigationPage, optimizeHomePage, managementIdentityPage, keycloakLoginPage, keycloakAdminPage, modelerHomePage, settingsPage, browser, }) => {
|
|
22
21
|
if (node_process_1.default.env.IS_RBA === 'true' ||
|
|
23
22
|
node_process_1.default.env.IS_MT === 'true' ||
|
|
24
23
|
node_process_1.default.env.IS_LICENSE_KEY === 'true') {
|
|
@@ -69,11 +68,11 @@ SM_8_10_1.test.describe('Identity User Flow Tests', () => {
|
|
|
69
68
|
});
|
|
70
69
|
if (node_process_1.default.env.IS_OPTIMIZE !== 'false') {
|
|
71
70
|
await SM_8_10_1.test.step('Ensure Optimize is not Accessible', async () => {
|
|
72
|
-
await navigationPage.
|
|
73
|
-
await (0, test_1.expect)(
|
|
71
|
+
await navigationPage.goToOptimizeWithoutAccess(credentials);
|
|
72
|
+
await (0, test_1.expect)(page.getByText('User has no authorization to access Optimize. Please check your Identity configuration')).toBeVisible({
|
|
74
73
|
timeout: 60000,
|
|
75
74
|
});
|
|
76
|
-
await (0, test_1.expect)(
|
|
75
|
+
await (0, test_1.expect)(optimizeHomePage.optimizeBanner).not.toBeVisible({
|
|
77
76
|
timeout: 60000,
|
|
78
77
|
});
|
|
79
78
|
});
|