@camunda/e2e-test-suite 0.0.1261 → 0.0.1263
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/ModelerHomePage.d.ts +2 -0
- package/dist/pages/SM-8.10/ModelerHomePage.js +21 -5
- package/dist/pages/SM-8.7/ModelerHomePage.js +8 -6
- package/dist/pages/SM-8.9/KeycloakAdminPage.js +4 -0
- package/dist/pages/SM-8.9/KeycloakUtils.js +10 -4
- package/dist/pages/SM-8.9/NavigationPage.d.ts +1 -0
- package/dist/pages/SM-8.9/NavigationPage.js +10 -1
- package/dist/tests/SM-8.7/console-user-flows.spec.js +2 -0
- package/dist/tests/SM-8.7/optimize-user-flows.spec.js +2 -0
- package/package.json +1 -1
|
@@ -23,6 +23,7 @@ declare class ModelerHomePage {
|
|
|
23
23
|
readonly workspaceWizardNameInput: Locator;
|
|
24
24
|
readonly workspaceWizardSubmitButton: Locator;
|
|
25
25
|
readonly workspaceWizardMembersStep: Locator;
|
|
26
|
+
readonly workspaceWizardEnvironmentsStep: Locator;
|
|
26
27
|
readonly moreActionsButton: Locator;
|
|
27
28
|
readonly renameMenuItem: Locator;
|
|
28
29
|
readonly renameInput: Locator;
|
|
@@ -52,6 +53,7 @@ declare class ModelerHomePage {
|
|
|
52
53
|
clickCreateNewProjectButton(): Promise<void>;
|
|
53
54
|
enterNewProjectName(name: string): Promise<void>;
|
|
54
55
|
private createWorkspaceViaWizard;
|
|
56
|
+
private finishWorkspaceWizard;
|
|
55
57
|
waitForModelerReady(timeoutMs?: number): Promise<void>;
|
|
56
58
|
createCrossComponentProjectFolder(credentials?: {
|
|
57
59
|
username: string;
|
|
@@ -51,6 +51,7 @@ class ModelerHomePage {
|
|
|
51
51
|
workspaceWizardNameInput;
|
|
52
52
|
workspaceWizardSubmitButton;
|
|
53
53
|
workspaceWizardMembersStep;
|
|
54
|
+
workspaceWizardEnvironmentsStep;
|
|
54
55
|
moreActionsButton;
|
|
55
56
|
renameMenuItem;
|
|
56
57
|
renameInput;
|
|
@@ -113,6 +114,7 @@ class ModelerHomePage {
|
|
|
113
114
|
this.workspaceWizardNameInput = page.locator('#workspace-name');
|
|
114
115
|
this.workspaceWizardSubmitButton = page.locator('[data-test="workspace-wizard-submit"]');
|
|
115
116
|
this.workspaceWizardMembersStep = page.locator('[data-test="step-members"]');
|
|
117
|
+
this.workspaceWizardEnvironmentsStep = page.locator('[data-test="step-environments"]');
|
|
116
118
|
// The rename kebab sits beside the breadcrumb in the app header. The
|
|
117
119
|
// editor's action bar is a <header> too, so it also carries the banner
|
|
118
120
|
// role -- getByRole('banner') alone matches three headers in the editor
|
|
@@ -271,16 +273,30 @@ class ModelerHomePage {
|
|
|
271
273
|
}
|
|
272
274
|
await this.renameViaMoreActions(name);
|
|
273
275
|
}
|
|
274
|
-
// Drives hub's
|
|
275
|
-
//
|
|
276
|
-
// second submit ("Create workspace") creates the workspace. Gate that second
|
|
277
|
-
// click on the Members step becoming active so the shared submit button is not
|
|
278
|
-
// clicked twice while still on General.
|
|
276
|
+
// Drives hub's workspace-creation wizard. Environments-enabled builds add an
|
|
277
|
+
// optional third step after Members; older builds create on the second submit.
|
|
279
278
|
async createWorkspaceViaWizard(name) {
|
|
280
279
|
await this.workspaceWizardNameInput.fill(name);
|
|
281
280
|
await this.workspaceWizardSubmitButton.click({ timeout: 60000 });
|
|
282
281
|
await (0, test_1.expect)(this.workspaceWizardMembersStep).toHaveAttribute('data-state', 'active', { timeout: 30000 });
|
|
283
282
|
await this.workspaceWizardSubmitButton.click({ timeout: 60000 });
|
|
283
|
+
await this.finishWorkspaceWizard();
|
|
284
|
+
}
|
|
285
|
+
async finishWorkspaceWizard() {
|
|
286
|
+
const needsEnvironmentSubmit = await Promise.race([
|
|
287
|
+
this.page
|
|
288
|
+
.waitForURL(/\/workspaces?\/[^/]+\/projects/, { timeout: 120000 })
|
|
289
|
+
.then(() => false),
|
|
290
|
+
(0, test_1.expect)(this.workspaceWizardEnvironmentsStep)
|
|
291
|
+
.toHaveAttribute('data-state', 'active', { timeout: 120000 })
|
|
292
|
+
.then(() => true),
|
|
293
|
+
]);
|
|
294
|
+
if (needsEnvironmentSubmit) {
|
|
295
|
+
await this.workspaceWizardSubmitButton.click({ timeout: 60000 });
|
|
296
|
+
await this.page.waitForURL(/\/workspaces?\/[^/]+\/projects/, {
|
|
297
|
+
timeout: 120000,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
284
300
|
}
|
|
285
301
|
// Wait for the Modeler project workspace to become interactive. The caller
|
|
286
302
|
// arrives here via goToModeler(), which has already loaded and authenticated
|
|
@@ -77,12 +77,14 @@ class ModelerHomePage {
|
|
|
77
77
|
await this.enterNewProjectName(this.defaultFolderName);
|
|
78
78
|
}
|
|
79
79
|
async clickCrossComponentProjectFolder() {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
// Coming back to the Modeler home page mid-flow re-fetches and re-renders
|
|
81
|
+
// the project list, so the tile is not on screen the moment navigation
|
|
82
|
+
// resolves. A bare 4s click raced that render; wait for the tile first,
|
|
83
|
+
// the way every other version of this page object already does.
|
|
84
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.crossComponentProjectFolder, {
|
|
85
|
+
visibilityTimeout: 30000,
|
|
86
|
+
});
|
|
87
|
+
await this.crossComponentProjectFolder.click({ timeout: 30000 });
|
|
86
88
|
}
|
|
87
89
|
async clickProcessDiagram(name) {
|
|
88
90
|
const process = this.rows.filter({ hasText: name }).getByTitle(name).first();
|
|
@@ -16,7 +16,11 @@ class KeycloakAdminPage {
|
|
|
16
16
|
async switchToCamundaPlatform() {
|
|
17
17
|
const realmSelector = this.page.getByTestId('nav-item-realms');
|
|
18
18
|
await realmSelector.click();
|
|
19
|
+
// The realm dropdown is rendered by the admin console after an async
|
|
20
|
+
// realm lookup, so a bare click races Playwright's default 10s action
|
|
21
|
+
// timeout on a loaded cluster. Wait for it explicitly instead.
|
|
19
22
|
const searchField = this.page.getByTestId('selectRealminput');
|
|
23
|
+
await (0, test_1.expect)(searchField).toBeVisible({ timeout: 30000 });
|
|
20
24
|
await searchField.click();
|
|
21
25
|
await this.page
|
|
22
26
|
.getByPlaceholder('Search')
|
|
@@ -45,10 +45,16 @@ async function loginToKeycloakAdmin(navigationPage, keycloakLoginPage, keycloakA
|
|
|
45
45
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
46
46
|
try {
|
|
47
47
|
await navigationPage.goToKeycloak();
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
// A failed attempt can still have authenticated: the submit click lands
|
|
49
|
+
// but its navigation outruns the action timeout, so the attempt throws
|
|
50
|
+
// while Keycloak keeps the master-realm session. Keycloak then serves
|
|
51
|
+
// the admin console straight away, and re-filling a login form that is
|
|
52
|
+
// no longer rendered makes every remaining attempt fail.
|
|
53
|
+
if (await keycloakLoginPage.keycloakBanner.isVisible()) {
|
|
54
|
+
await keycloakLoginPage.fillUsername((0, exports.keycloakAdminCredentials)().username);
|
|
55
|
+
await keycloakLoginPage.fillPassword((0, exports.keycloakAdminCredentials)().password);
|
|
56
|
+
await keycloakLoginPage.clickLogin();
|
|
57
|
+
}
|
|
52
58
|
await keycloakAdminPage.toBeVisible();
|
|
53
59
|
return;
|
|
54
60
|
}
|
|
@@ -8,6 +8,7 @@ declare class NavigationPage {
|
|
|
8
8
|
readonly identityPageBanner: Locator;
|
|
9
9
|
readonly consolePageBanner: Locator;
|
|
10
10
|
readonly keyboardPageBanner: Locator;
|
|
11
|
+
readonly keycloakAdminPageBanner: Locator;
|
|
11
12
|
readonly managementIdentityPageBanner: Locator;
|
|
12
13
|
constructor(page: Page);
|
|
13
14
|
private isRetriableNavigationNetworkError;
|
|
@@ -48,6 +48,7 @@ class NavigationPage {
|
|
|
48
48
|
identityPageBanner;
|
|
49
49
|
consolePageBanner;
|
|
50
50
|
keyboardPageBanner;
|
|
51
|
+
keycloakAdminPageBanner;
|
|
51
52
|
managementIdentityPageBanner;
|
|
52
53
|
constructor(page) {
|
|
53
54
|
this.page = page;
|
|
@@ -76,6 +77,7 @@ class NavigationPage {
|
|
|
76
77
|
.filter({ hasText: /^Camunda logo\s*Management Identity$/ })
|
|
77
78
|
.first();
|
|
78
79
|
this.keyboardPageBanner = page.locator('#keycloak-bg');
|
|
80
|
+
this.keycloakAdminPageBanner = page.locator('#kc-main-content-page-container');
|
|
79
81
|
}
|
|
80
82
|
isRetriableNavigationNetworkError(error) {
|
|
81
83
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -215,12 +217,19 @@ class NavigationPage {
|
|
|
215
217
|
async goToModelerWithoutAccess({ username = IDENTITY_FIRSTUSER_USERNAME, password = IDENTITY_FIRSTUSER_PASSWORD, } = {}) {
|
|
216
218
|
await this.goToWithoutAccess(MODELER_CONTEXT_PATH, username, password);
|
|
217
219
|
}
|
|
220
|
+
// Resolves once Keycloak has settled on either its login form or, when the
|
|
221
|
+
// master-realm SSO session is still valid, the admin console it serves
|
|
222
|
+
// instead. Asserting the login form alone makes every retry of an already
|
|
223
|
+
// authenticated session time out on a form Keycloak will never render.
|
|
218
224
|
async goToKeycloak() {
|
|
219
225
|
const keycloakUrl = process.env.KEYCLOAK_URL
|
|
220
226
|
? `${process.env.KEYCLOAK_URL}/auth`
|
|
221
227
|
: '/auth';
|
|
222
228
|
await this.page.goto(keycloakUrl);
|
|
223
|
-
await
|
|
229
|
+
await test_1.expect
|
|
230
|
+
.poll(async () => (await this.keyboardPageBanner.isVisible()) ||
|
|
231
|
+
(await this.keycloakAdminPageBanner.isVisible()), { timeout: 60000 })
|
|
232
|
+
.toBe(true);
|
|
224
233
|
}
|
|
225
234
|
async goToOCIdentity(sleepTimeout, credentials) {
|
|
226
235
|
await this.goTo(`${NORMALIZED_ORCHESTRATION_CONTEXT_PATH}/identity`, this.identityPageBanner, sleepTimeout, credentials);
|
|
@@ -19,6 +19,7 @@ SM_8_7_1.test.describe.parallel('Console User Flow Tests', () => {
|
|
|
19
19
|
(0, loggingUtils_1.cleanupTestLogging)();
|
|
20
20
|
});
|
|
21
21
|
(0, SM_8_7_1.test)('Custom Tags', async ({ consoleHomePage, clusterPage, navigationPage, context, }) => {
|
|
22
|
+
SM_8_7_1.test.slow();
|
|
22
23
|
await SM_8_7_1.test.step('Navigate to Clusters', async () => {
|
|
23
24
|
await context.clearCookies();
|
|
24
25
|
await navigationPage.goToConsole();
|
|
@@ -33,6 +34,7 @@ SM_8_7_1.test.describe.parallel('Console User Flow Tests', () => {
|
|
|
33
34
|
});
|
|
34
35
|
});
|
|
35
36
|
(0, SM_8_7_1.test)('Custom Properties', async ({ consoleHomePage, clusterPage, clusterDetailsPage, page, navigationPage, context, }) => {
|
|
37
|
+
SM_8_7_1.test.slow();
|
|
36
38
|
await SM_8_7_1.test.step('Navigate to Cluster Details', async () => {
|
|
37
39
|
await context.clearCookies();
|
|
38
40
|
await navigationPage.goToConsole();
|
|
@@ -23,6 +23,7 @@ SM_8_7_1.test.describe.parallel('Optimize User Flow Tests', () => {
|
|
|
23
23
|
(0, loggingUtils_1.cleanupTestLogging)();
|
|
24
24
|
});
|
|
25
25
|
(0, SM_8_7_1.test)('Process Import Flow', async ({ page, context, operateHomePage, modelerHomePage, navigationPage, modelerCreatePage, operateProcessesPage, operateProcessInstancePage, optimizeHomePage, optimizeDashboardPage, }) => {
|
|
26
|
+
SM_8_7_1.test.slow();
|
|
26
27
|
const processName = 'Optimize_Job_Worker_User_Task_Flow' +
|
|
27
28
|
(await (0, _setup_1.generateRandomStringAsync)(3));
|
|
28
29
|
await SM_8_7_1.test.step('Open Cross Component Test Project and Create a BPMN Diagram Template', async () => {
|
|
@@ -122,6 +123,7 @@ SM_8_7_1.test.describe.parallel('Optimize User Flow Tests', () => {
|
|
|
122
123
|
});
|
|
123
124
|
});
|
|
124
125
|
(0, SM_8_7_1.test)('New Instances Updated Flow', async ({ page, context, modelerHomePage, navigationPage, modelerCreatePage, operateHomePage, operateProcessesPage, operateProcessInstancePage, optimizeHomePage, optimizeCollectionsPage, optimizeReportPage, }) => {
|
|
126
|
+
SM_8_7_1.test.slow();
|
|
125
127
|
const reportName = await (0, _setup_1.generateRandomStringAsync)(5);
|
|
126
128
|
const processName = 'Optimize_Job_Worker_User_Task_Flow_Updated' +
|
|
127
129
|
(await (0, _setup_1.generateRandomStringAsync)(3));
|