@camunda/e2e-test-suite 0.0.1049 → 0.0.1051
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/8.10/UtilitiesPage.d.ts +5 -0
- package/dist/pages/8.10/UtilitiesPage.js +44 -1
- package/dist/pages/SM-8.10/OCIdentityRolesPage.d.ts +1 -1
- package/dist/pages/SM-8.10/OCIdentityRolesPage.js +13 -5
- package/dist/tests/8.10/smoke-tests.spec.js +4 -4
- package/dist/tests/8.10/test-setup.spec.js +6 -10
- package/dist/tests/SM-8.10/identity-user-flows.spec.js +2 -1
- package/package.json +1 -1
|
@@ -18,6 +18,11 @@ export declare function loginWithRetry(page: Page, loginPage: LoginPage, testUse
|
|
|
18
18
|
username: string;
|
|
19
19
|
password: string;
|
|
20
20
|
}, timeout: number, maxRetries?: number): Promise<void>;
|
|
21
|
+
export declare function isSignedOut(page: Page): boolean;
|
|
22
|
+
export declare function withSessionRecovery(page: Page, loginPage: LoginPage, appsPage: AppsPage, modelerBanner: Locator, testUser: {
|
|
23
|
+
username: string;
|
|
24
|
+
password: string;
|
|
25
|
+
}, loginStagger: number, action: () => Promise<void>): Promise<void>;
|
|
21
26
|
export declare function modelDiagramFromFile(page: Page, modelerHomePage: ModelerHomePage, modelerCreatePage: ModelerCreatePage, processName: string, fileName?: string, nrOfRenamedUserTasks?: number, taskName?: string): Promise<void>;
|
|
22
27
|
export declare function modelRestConnector(modelerCreatePage: ModelerCreatePage, connectorSettingsPage: ConnectorSettingsPage, processName: string, url: string, auth: string, resultExpression: string, resultVariable?: string, basicAuthCredentials?: {
|
|
23
28
|
username: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.waitForLoadingToFinish = exports.assertTestUsesCorrectOrganizationFromModeler = exports.expectCountToBeOneOf = exports.createAPIClient = exports.modelAndRunConnectorsTimerEventDiagram = exports.modelAndRunConnectorsDocHandlingDiagram = exports.deleteCluster = exports.deleteAllUserGroups = exports.assertTestUsesCorrectOrganization = exports.assertLatestAlertEmail = exports.clickInvitationLinkInEmail = exports.enableAuthorizations = exports.disableRBA = exports.runMultipleProcesses = exports.runProcess = exports.completeTaskWithRetry = exports.assertPageTextWithRetry = exports.openAppTabWithRetry = exports.assertLocatorVisibleWithRetry = exports.modelRestConnector = exports.modelDiagramFromFile = exports.loginWithRetry = void 0;
|
|
3
|
+
exports.waitForLoadingToFinish = exports.assertTestUsesCorrectOrganizationFromModeler = exports.expectCountToBeOneOf = exports.createAPIClient = exports.modelAndRunConnectorsTimerEventDiagram = exports.modelAndRunConnectorsDocHandlingDiagram = exports.deleteCluster = exports.deleteAllUserGroups = exports.assertTestUsesCorrectOrganization = exports.assertLatestAlertEmail = exports.clickInvitationLinkInEmail = exports.enableAuthorizations = exports.disableRBA = exports.runMultipleProcesses = exports.runProcess = exports.completeTaskWithRetry = exports.assertPageTextWithRetry = exports.openAppTabWithRetry = exports.assertLocatorVisibleWithRetry = exports.modelRestConnector = exports.modelDiagramFromFile = exports.withSessionRecovery = exports.isSignedOut = exports.loginWithRetry = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const ModelerHomePage_1 = require("./ModelerHomePage");
|
|
6
6
|
const HomePage_1 = require("./HomePage");
|
|
@@ -191,6 +191,49 @@ async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 5
|
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
exports.loginWithRetry = loginWithRetry;
|
|
194
|
+
// True once the tab has been thrown out of the app and back to the IdP: the
|
|
195
|
+
// Modeler hand-off can commit `/login-callback?code=...` and then bounce
|
|
196
|
+
// straight back to `modeler.<host>/login` and on to `weblogin.<host>`, leaving
|
|
197
|
+
// an Auth0 form where the app used to be. Distinct from
|
|
198
|
+
// `AppsPage.isModelerAuthTransit`, which covers a hand-off still in flight.
|
|
199
|
+
function isSignedOut(page) {
|
|
200
|
+
try {
|
|
201
|
+
const { hostname, pathname } = new URL(page.url());
|
|
202
|
+
return (hostname.startsWith('weblogin.') ||
|
|
203
|
+
(hostname.startsWith('modeler.') && /^\/login\/?$/.test(pathname)));
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// Not a parsable URL yet (e.g. a tab still on about:blank).
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
exports.isSignedOut = isSignedOut;
|
|
211
|
+
// Runs `action`, and if it fails because the session was dropped mid-flow,
|
|
212
|
+
// signs back in, returns to the Modeler projects list and runs it once more.
|
|
213
|
+
//
|
|
214
|
+
// Without this the caller's own locator retries keep hunting for app controls
|
|
215
|
+
// on the Auth0 form and expire against a page that is not the app at all —
|
|
216
|
+
// reported as a misleading "Failed to click locator ... New project" rather
|
|
217
|
+
// than as the sign-out it actually was. Only a confirmed sign-out is retried;
|
|
218
|
+
// any other failure propagates untouched, so a genuinely broken control still
|
|
219
|
+
// fails the test.
|
|
220
|
+
async function withSessionRecovery(page, loginPage, appsPage, modelerBanner, testUser, loginStagger, action) {
|
|
221
|
+
try {
|
|
222
|
+
await action();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
if (!isSignedOut(page)) {
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
console.warn(`Session was dropped mid-flow (tab landed on ${page.url()}); ` +
|
|
230
|
+
'signing back in and retrying once.');
|
|
231
|
+
}
|
|
232
|
+
await loginWithRetry(page, loginPage, testUser, loginStagger);
|
|
233
|
+
await appsPage.openModelerWithRetry(modelerBanner);
|
|
234
|
+
await action();
|
|
235
|
+
}
|
|
236
|
+
exports.withSessionRecovery = withSessionRecovery;
|
|
194
237
|
async function modelDiagramFromFile(page, modelerHomePage, modelerCreatePage, processName, fileName = '', nrOfRenamedUserTasks = 0, taskName = '') {
|
|
195
238
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
196
239
|
await modelerHomePage.clickUploadFilesButton();
|
|
@@ -5,7 +5,7 @@ declare class OCIdentityRolesPage {
|
|
|
5
5
|
readonly assignMappingRuleButton: Locator;
|
|
6
6
|
readonly mappingSearchBox: Locator;
|
|
7
7
|
readonly assignMappingModal: Locator;
|
|
8
|
-
readonly
|
|
8
|
+
readonly assignMappingRuleOption: (name: string) => Locator;
|
|
9
9
|
readonly assignMappingModalAssignRuleButton: Locator;
|
|
10
10
|
readonly rolesList: Locator;
|
|
11
11
|
readonly roleCell: (name: string) => Locator;
|
|
@@ -13,7 +13,7 @@ class OCIdentityRolesPage {
|
|
|
13
13
|
assignMappingRuleButton;
|
|
14
14
|
mappingSearchBox;
|
|
15
15
|
assignMappingModal;
|
|
16
|
-
|
|
16
|
+
assignMappingRuleOption;
|
|
17
17
|
assignMappingModalAssignRuleButton;
|
|
18
18
|
rolesList;
|
|
19
19
|
roleCell;
|
|
@@ -55,8 +55,12 @@ class OCIdentityRolesPage {
|
|
|
55
55
|
this.createRoleButton = page.getByRole('button', {
|
|
56
56
|
name: /create role/i,
|
|
57
57
|
});
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
// The design-system assign-mapping-rule modal renders its result list in a
|
|
59
|
+
// Radix popover that portals to <body> as a sibling of the dialog, so the
|
|
60
|
+
// options are not inside assignMappingModal's DOM subtree - query them from
|
|
61
|
+
// the page. Each option repeats the id as both title and subtitle, so match
|
|
62
|
+
// on contained text rather than the accessible name.
|
|
63
|
+
this.assignMappingRuleOption = (name) => page.getByRole('option').filter({ hasText: name }).first();
|
|
60
64
|
this.assignMappingModalAssignRuleButton = this.assignMappingModal.getByRole('button', {
|
|
61
65
|
name: 'Assign mapping rule',
|
|
62
66
|
});
|
|
@@ -140,8 +144,12 @@ class OCIdentityRolesPage {
|
|
|
140
144
|
});
|
|
141
145
|
await this.assignMappingRuleButton.click({ timeout: 60000 });
|
|
142
146
|
await (0, test_1.expect)(this.assignMappingModal).toBeVisible({ timeout: 60000 });
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
// The design-system search input is a cmdk combobox that only issues
|
|
148
|
+
// its server-side query on real keystrokes, so type the id in rather
|
|
149
|
+
// than setting the value in one shot.
|
|
150
|
+
await this.mappingSearchBox.click();
|
|
151
|
+
await this.mappingSearchBox.pressSequentially(mappingId);
|
|
152
|
+
await this.assignMappingRuleOption(mappingId).click({ timeout: 30000 });
|
|
145
153
|
await this.assignMappingModalAssignRuleButton.click();
|
|
146
154
|
return;
|
|
147
155
|
}
|
|
@@ -27,7 +27,7 @@ _8_10_1.test.describe('Smoke Tests', () => {
|
|
|
27
27
|
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
28
28
|
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
29
29
|
});
|
|
30
|
-
(0, _8_10_1.test)('Most Common Flow User Flow With All Apps', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, }) => {
|
|
30
|
+
(0, _8_10_1.test)('Most Common Flow User Flow With All Apps', async ({ page, loginPage, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, }, testInfo) => {
|
|
31
31
|
_8_10_1.test.slow();
|
|
32
32
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
33
33
|
const formName = 'New form' + randomString;
|
|
@@ -60,7 +60,7 @@ _8_10_1.test.describe('Smoke Tests', () => {
|
|
|
60
60
|
// absent/flaky the folder is missing and clicking it hangs forever.
|
|
61
61
|
// createCrossComponentProjectFolder clicks into the folder when present
|
|
62
62
|
// (the normal path) and creates it only when it is genuinely missing.
|
|
63
|
-
await modelerHomePage.createCrossComponentProjectFolder();
|
|
63
|
+
await (0, UtilitiesPage_1.withSessionRecovery)(page, loginPage, appsPage, modelerHomePage.modelerPageBanner, testUser, (testInfo.workerIndex + 1) * 1000, () => modelerHomePage.createCrossComponentProjectFolder());
|
|
64
64
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
65
65
|
await modelerHomePage.clickFormOption();
|
|
66
66
|
await modelerHomePage.enterFormNameWithRetry(formName);
|
|
@@ -292,7 +292,7 @@ _8_10_1.test.describe('Smoke Tests', () => {
|
|
|
292
292
|
await optimizeReportPage.assertUserTaskInstanceCountWithRetry(2, appTab, countRetries, Math.floor(flowBudget(countRetries * constants_1.TIMEOUT.navigation) / countRetries));
|
|
293
293
|
});
|
|
294
294
|
});
|
|
295
|
-
(0, _8_10_1.test)('Most Common REST Connector User Flow', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, connectorSettingsPage, }) => {
|
|
295
|
+
(0, _8_10_1.test)('Most Common REST Connector User Flow', async ({ page, loginPage, homePage, modelerHomePage, appsPage, modelerCreatePage, connectorSettingsPage, }, testInfo) => {
|
|
296
296
|
_8_10_1.test.slow();
|
|
297
297
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
298
298
|
const processName = 'REST_Connector_Basic_Auth_Process' + randomString;
|
|
@@ -305,7 +305,7 @@ _8_10_1.test.describe('Smoke Tests', () => {
|
|
|
305
305
|
await _8_10_1.test.step('Open Cross Component Test Project and create a BPMN diagram template', async () => {
|
|
306
306
|
// See note in the flow above: ensure the per-user project exists rather
|
|
307
307
|
// than hanging on a click when the shared setup did not create it.
|
|
308
|
-
await modelerHomePage.createCrossComponentProjectFolder();
|
|
308
|
+
await (0, UtilitiesPage_1.withSessionRecovery)(page, loginPage, appsPage, modelerHomePage.modelerPageBanner, testUser, (testInfo.workerIndex + 1) * 1000, () => modelerHomePage.createCrossComponentProjectFolder());
|
|
309
309
|
await modelerHomePage.clickDiagramTypeDropdown();
|
|
310
310
|
await modelerHomePage.clickBpmnTemplateOption();
|
|
311
311
|
});
|
|
@@ -120,18 +120,14 @@ _8_10_1.test.describe('Cluster Setup Tests', () => {
|
|
|
120
120
|
await (0, test_1.expect)(homePage.camundaComponentsButton).toBeVisible({
|
|
121
121
|
timeout: 120000,
|
|
122
122
|
});
|
|
123
|
-
await appsPage.
|
|
124
|
-
await appsPage.clickModeler();
|
|
125
|
-
await (0, test_1.expect)(modelerHomePage.modelerPageBanner).toBeVisible({
|
|
126
|
-
timeout: 180000,
|
|
127
|
-
});
|
|
123
|
+
await appsPage.openModelerWithRetry(modelerHomePage.modelerPageBanner, 180000);
|
|
128
124
|
});
|
|
129
125
|
await _8_10_1.test.step('Create Cross Component Project Folder', async () => {
|
|
130
|
-
await
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
timeout: 60000
|
|
126
|
+
await (0, UtilitiesPage_1.withSessionRecovery)(page, loginPage, appsPage, modelerHomePage.modelerPageBanner, user, (testInfo.workerIndex + 1) * 1000, async () => {
|
|
127
|
+
await homePage.clickSkipCustomization();
|
|
128
|
+
await modelerHomePage.createCrossComponentProjectFolder();
|
|
129
|
+
await modelerHomePage.clickHomeBreadcrumb();
|
|
130
|
+
await (0, test_1.expect)(modelerHomePage.crossComponentProjectFolder).toBeVisible({ timeout: 60000 });
|
|
135
131
|
});
|
|
136
132
|
});
|
|
137
133
|
});
|
|
@@ -122,7 +122,8 @@ SM_8_10_1.test.describe('Identity User Flow Tests', () => {
|
|
|
122
122
|
});
|
|
123
123
|
});
|
|
124
124
|
});
|
|
125
|
-
|
|
125
|
+
// Skipped due to bug #61565: https://github.com/camunda/camunda/issues/61565
|
|
126
|
+
SM_8_10_1.test.skip('User Roles User Flow on Orchestration Cluster', async ({ page, navigationPage, ocIdentityMappingRulesPage, ocIdentityHomePage, ocIdentityRolesPage, taskPanelPage, operateHomePage, settingsPage, browser, keycloakLoginPage, keycloakAdminPage, managementIdentityPage, }) => {
|
|
126
127
|
if (node_process_1.default.env.IS_RBA === 'true' ||
|
|
127
128
|
node_process_1.default.env.IS_MT === 'true' ||
|
|
128
129
|
node_process_1.default.env.IS_LICENSE_KEY === 'true') {
|