@camunda/e2e-test-suite 0.0.915 → 0.0.917
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.7/UtlitiesPage.d.ts +3 -1
- package/dist/pages/SM-8.7/UtlitiesPage.js +37 -1
- package/dist/test-setup.js +19 -5
- package/dist/tests/8.8/hto-user-flows.spec.js +5 -6
- package/dist/tests/SM-8.7/hto-user-flows.spec.js +2 -10
- package/dist/utils/consoleApiHelpers.d.ts +2 -2
- package/dist/utils/consoleApiHelpers.js +43 -11
- package/package.json +1 -1
|
@@ -2,12 +2,14 @@ import { IdentityPage } from '../SM-8.7/IdentityPage';
|
|
|
2
2
|
import { NavigationPage } from '../SM-8.7/NavigationPage';
|
|
3
3
|
import { ModelerHomePage } from './ModelerHomePage';
|
|
4
4
|
import { ModelerCreatePage } from './ModelerCreatePage';
|
|
5
|
-
import { Locator, Page } from '@playwright/test';
|
|
5
|
+
import { BrowserContext, Locator, Page } from '@playwright/test';
|
|
6
6
|
import { TaskDetailsPage } from '../SM-8.7/TaskDetailsPage';
|
|
7
7
|
import { TaskPanelPage } from '../SM-8.7/TaskPanelPage';
|
|
8
|
+
import { LoginPage } from '../SM-8.7/LoginPage';
|
|
8
9
|
import { ConnectorSettingsPage } from '../SM-8.7/ConnectorSettingsPage';
|
|
9
10
|
import { ConnectorMarketplacePage } from '../SM-8.7/ConnectorMarketplacePage';
|
|
10
11
|
import { ConnectorTemplatePage } from './ConnectorTemplatePage';
|
|
12
|
+
export declare function loginToTasklistWithRetry(page: Page, context: BrowserContext, loginPage: LoginPage, taskPanelPage: TaskPanelPage, username: string, password: string, maxAttempts?: number, attemptTimeout?: number): Promise<void>;
|
|
11
13
|
export declare function deleteAllUserGroups(navigationPage: NavigationPage, identityPage: IdentityPage): Promise<void>;
|
|
12
14
|
export declare function runMultipleProcesses(modelerHomePage: ModelerHomePage, modelerCreatePage: ModelerCreatePage, numberOfProcesses: number, processName: string, processId?: string): Promise<void>;
|
|
13
15
|
export declare function createAndRunProcess(modelerHomePage: ModelerHomePage, modelerCreatePage: ModelerCreatePage, processName: string, processId?: string): Promise<void>;
|
|
@@ -1,9 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.modelDiagramFromFile = exports.modelAndRunConnectorsTimerEventDiagram = exports.assertPageTextWithRetry = exports.assertLocatorVisibleWithRetry = exports.modelWebhookConnector = exports.modelIntermediateWebhookConnector = exports.modelRestConnector = exports.completeTaskWithRetry = exports.createAndRunProcess = exports.runMultipleProcesses = exports.deleteAllUserGroups = void 0;
|
|
3
|
+
exports.modelDiagramFromFile = exports.modelAndRunConnectorsTimerEventDiagram = exports.assertPageTextWithRetry = exports.assertLocatorVisibleWithRetry = exports.modelWebhookConnector = exports.modelIntermediateWebhookConnector = exports.modelRestConnector = exports.completeTaskWithRetry = exports.createAndRunProcess = exports.runMultipleProcesses = exports.deleteAllUserGroups = exports.loginToTasklistWithRetry = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const fileUpload_1 = require("../../utils/fileUpload");
|
|
6
6
|
const sleep_1 = require("../../utils/sleep");
|
|
7
|
+
// Tasklist renders "No permission for Tasklist" as a terminal page: it reads the
|
|
8
|
+
// permissions off the token minted at login and never re-evaluates them, so a
|
|
9
|
+
// user whose Identity role assignment has not propagated yet stays stuck there.
|
|
10
|
+
// Recovering therefore needs a fresh authentication, not a longer wait.
|
|
11
|
+
async function loginToTasklistWithRetry(page, context, loginPage, taskPanelPage, username, password, maxAttempts = 3, attemptTimeout = 60000) {
|
|
12
|
+
const noTasklistPermission = page.getByText('No permission for Tasklist - Please check your configuration.');
|
|
13
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
14
|
+
await loginPage.fillUsername(username);
|
|
15
|
+
await (0, test_1.expect)(loginPage.usernameInput).toHaveValue(username);
|
|
16
|
+
await loginPage.fillPassword(password);
|
|
17
|
+
await loginPage.clickLoginButton();
|
|
18
|
+
if (attempt === maxAttempts) {
|
|
19
|
+
await (0, test_1.expect)(taskPanelPage.tasklistBanner).toBeVisible({
|
|
20
|
+
timeout: attemptTimeout,
|
|
21
|
+
});
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const reachedTasklist = await taskPanelPage.tasklistBanner
|
|
25
|
+
.waitFor({ state: 'visible', timeout: attemptTimeout })
|
|
26
|
+
.then(() => true)
|
|
27
|
+
.catch(() => false);
|
|
28
|
+
if (reachedTasklist) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const permissionDenied = await noTasklistPermission
|
|
32
|
+
.isVisible()
|
|
33
|
+
.catch(() => false);
|
|
34
|
+
console.warn(`loginToTasklistWithRetry: attempt ${attempt} for "${username}" did not ` +
|
|
35
|
+
`reach Tasklist${permissionDenied ? ' (no-permission page)' : ''}. ` +
|
|
36
|
+
're-authenticating to obtain a freshly minted token.');
|
|
37
|
+
await context.clearCookies();
|
|
38
|
+
await page.goto('/tasklist', { waitUntil: 'domcontentloaded' });
|
|
39
|
+
await loginPage.detectLoginForm();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.loginToTasklistWithRetry = loginToTasklistWithRetry;
|
|
7
43
|
async function deleteAllUserGroups(navigationPage, identityPage) {
|
|
8
44
|
await navigationPage.goToIdentity();
|
|
9
45
|
await identityPage.clickGroupsTab();
|
package/dist/test-setup.js
CHANGED
|
@@ -10,11 +10,25 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
10
10
|
const constants_1 = require("./utils/constants");
|
|
11
11
|
async function captureScreenshot(page, testInfo) {
|
|
12
12
|
const screenshotPath = `test-results/screenshots/screenshot-${(0, crypto_1.randomUUID)()}.png`;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
try {
|
|
14
|
+
await page.screenshot({
|
|
15
|
+
path: screenshotPath,
|
|
16
|
+
fullPage: true,
|
|
17
|
+
timeout: 60000,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
catch (fullPageError) {
|
|
21
|
+
console.warn(`captureScreenshot: full-page capture failed (${fullPageError}). ` +
|
|
22
|
+
'Falling back to a viewport-only screenshot.');
|
|
23
|
+
try {
|
|
24
|
+
await page.screenshot({ path: screenshotPath, timeout: 30000 });
|
|
25
|
+
}
|
|
26
|
+
catch (viewportError) {
|
|
27
|
+
console.warn(`captureScreenshot: viewport capture also failed (${viewportError}). ` +
|
|
28
|
+
'Continuing without a screenshot; the test verdict is unaffected.');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
18
32
|
await testInfo.attach('screenshot', {
|
|
19
33
|
path: screenshotPath,
|
|
20
34
|
contentType: 'image/png',
|
|
@@ -474,12 +474,11 @@ _8_8_1.test.describe('HTO User Flow Tests', () => {
|
|
|
474
474
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
475
475
|
const processName = 'User_Task_Process_With_Public_Form' + randomString;
|
|
476
476
|
const formName = 'Public form' + randomString;
|
|
477
|
-
//
|
|
478
|
-
//
|
|
479
|
-
//
|
|
480
|
-
//
|
|
481
|
-
//
|
|
482
|
-
// cluster rather than sharing one that can never satisfy both.
|
|
477
|
+
// This assertion needs a genuinely v2-upgraded backend, and the switch to
|
|
478
|
+
// v2 is irreversible, so it keeps its own dedicated cluster instead of
|
|
479
|
+
// relying on the mode of the shared "Test Cluster" (which follows the
|
|
480
|
+
// Playwright project the setup ran under -- v1 in the chromium-v1 leg, so
|
|
481
|
+
// that job-worker-based user tasks keep working for the rest of this file).
|
|
483
482
|
const v2ClusterName = 'Public Form V2 Cluster';
|
|
484
483
|
await _8_8_1.test.step('Create Dedicated Tasklist V2 Cluster', async () => {
|
|
485
484
|
const clusterUuid = await (0, consoleApiHelpers_1.ensureClusterViaApi)(page, v2ClusterName);
|
|
@@ -335,11 +335,7 @@ SM_8_7_1.test.describe.parallel('HTO User Flow Tests', () => {
|
|
|
335
335
|
await SM_8_7_1.test.step('Logout and Login with "lisa" User and Check Tasks in Tasklist', async () => {
|
|
336
336
|
await settingsPage.clickOpenSettingsButton();
|
|
337
337
|
await settingsPage.clickLogoutButton();
|
|
338
|
-
await
|
|
339
|
-
await (0, test_1.expect)(loginPage.usernameInput).toHaveValue(navigationPage.user1);
|
|
340
|
-
await loginPage.fillPassword('lisa');
|
|
341
|
-
await loginPage.clickLoginButton();
|
|
342
|
-
await (0, test_1.expect)(taskPanelPage.tasklistBanner).toBeVisible({ timeout: 120000 });
|
|
338
|
+
await (0, UtlitiesPage_1.loginToTasklistWithRetry)(page, context, loginPage, taskPanelPage, navigationPage.user1, 'lisa');
|
|
343
339
|
});
|
|
344
340
|
await SM_8_7_1.test.step('Navigate to Tasklist and Assert User Tasks ', async () => {
|
|
345
341
|
await (0, test_1.expect)(page.getByText(`${userTaskName}1`)).toBeVisible({
|
|
@@ -352,11 +348,7 @@ SM_8_7_1.test.describe.parallel('HTO User Flow Tests', () => {
|
|
|
352
348
|
await SM_8_7_1.test.step('Logout and Login with "bart" User and Check Tasks in Tasklist', async () => {
|
|
353
349
|
await settingsPage.clickOpenSettingsButton();
|
|
354
350
|
await settingsPage.clickLogoutButton();
|
|
355
|
-
await
|
|
356
|
-
await (0, test_1.expect)(loginPage.usernameInput).toHaveValue(navigationPage.user2);
|
|
357
|
-
await loginPage.fillPassword('bart');
|
|
358
|
-
await loginPage.clickLoginButton();
|
|
359
|
-
await (0, test_1.expect)(taskPanelPage.tasklistBanner).toBeVisible({ timeout: 120000 });
|
|
351
|
+
await (0, UtlitiesPage_1.loginToTasklistWithRetry)(page, context, loginPage, taskPanelPage, navigationPage.user2, 'bart');
|
|
360
352
|
});
|
|
361
353
|
await SM_8_7_1.test.step('Navigate to Tasklist and Assert User Tasks ', async () => {
|
|
362
354
|
await (0, test_1.expect)(page.getByText(`${userTaskName}1`)).not.toBeVisible({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Page } from '@playwright/test';
|
|
2
2
|
export declare function deleteClusterViaApi(page: Page, clusterName: string): Promise<void>;
|
|
3
|
-
export declare function createClusterViaApi(page: Page, clusterName: string, region?: string): Promise<string>;
|
|
4
|
-
export declare function ensureClusterViaApi(page: Page, clusterName: string, region?: string): Promise<string>;
|
|
3
|
+
export declare function createClusterViaApi(page: Page, clusterName: string, region?: string, tasklistV2Enabled?: boolean): Promise<string>;
|
|
4
|
+
export declare function ensureClusterViaApi(page: Page, clusterName: string, region?: string, tasklistV2Enabled?: boolean): Promise<string>;
|
|
5
5
|
export declare function ensureTasklistV2Enabled(page: Page, clusterUuid: string): Promise<void>;
|
|
6
6
|
export declare function waitForClusterHealthyViaApi(page: Page, clusterUuid: string, timeoutMs?: number): Promise<void>;
|
|
7
7
|
export declare function waitForClusterRestartHealthyViaApi(page: Page, clusterUuid: string, timeoutMs?: number): Promise<void>;
|
|
@@ -233,7 +233,33 @@ function requestedGenerationName() {
|
|
|
233
233
|
return undefined;
|
|
234
234
|
return clusterVersion;
|
|
235
235
|
}
|
|
236
|
-
|
|
236
|
+
// Which Tasklist mode a cluster must be created in is decided by the Playwright
|
|
237
|
+
// project the setup ran under, exactly as the UI path already does it in
|
|
238
|
+
// ClusterPage.determineTasklistAPI(): chromium-v1 selects "Tasklist API v1
|
|
239
|
+
// (legacy)", chromium-v2 leaves the v2 default. Mirror that here so the
|
|
240
|
+
// chromium-v2 leg does not end up driving a v1-mode backend.
|
|
241
|
+
//
|
|
242
|
+
// For generations below 8.10 Console turns this into
|
|
243
|
+
// CAMUNDA_TASKLIST_V2_MODE_ENABLED on Tasklist and the gateway, so 8.8/8.9 are
|
|
244
|
+
// the versions where it changes what is under test; 8.10+ is v2-only and
|
|
245
|
+
// ignores the field, and 8.7 predates the mode entirely (TASKLIST_VERSION is
|
|
246
|
+
// unset there, which resolves to v1 as before).
|
|
247
|
+
function resolveTasklistV2Enabled() {
|
|
248
|
+
let projectName = '';
|
|
249
|
+
try {
|
|
250
|
+
projectName = test_1.test.info().project.name;
|
|
251
|
+
}
|
|
252
|
+
catch {
|
|
253
|
+
// Called outside a running test (no test.info() available); fall back to
|
|
254
|
+
// the env var the SaaS workflows export from matrix.tasklist_version.
|
|
255
|
+
}
|
|
256
|
+
if (projectName.includes('v1'))
|
|
257
|
+
return false;
|
|
258
|
+
if (projectName.includes('v2'))
|
|
259
|
+
return true;
|
|
260
|
+
return (process.env.TASKLIST_VERSION ?? '').trim().toLowerCase() === 'v2';
|
|
261
|
+
}
|
|
262
|
+
async function createClusterViaApi(page, clusterName, region = 'GCP', tasklistV2Enabled = resolveTasklistV2Enabled()) {
|
|
237
263
|
const orgId = getOrgId();
|
|
238
264
|
// Some trigger flows (e.g. playwright_saas_pr_trigger_monorepo.yml) create a
|
|
239
265
|
// throwaway cluster generation per run, built from that specific commit's
|
|
@@ -276,13 +302,14 @@ async function createClusterViaApi(page, clusterName, region = 'GCP') {
|
|
|
276
302
|
k8sContextId,
|
|
277
303
|
autoUpdate: true,
|
|
278
304
|
stageLabel: 'dev',
|
|
279
|
-
//
|
|
280
|
-
//
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
|
|
305
|
+
// Always sent explicitly rather than omitted: Console defaults an unset
|
|
306
|
+
// field to v2-enabled for any generation >= 8.8, and the switch to v2 is
|
|
307
|
+
// one-way -- a cluster that ends up v2-enabled can never be brought back
|
|
308
|
+
// to v1 for the rest of its life. v2 cannot run job-worker-based user
|
|
309
|
+
// tasks, draft variables, or public start forms, so the v1 leg
|
|
310
|
+
// (@tasklistV1-tagged suites) depends on this being false, and the v2 leg
|
|
311
|
+
// equally depends on it being true.
|
|
312
|
+
tasklistV2Enabled,
|
|
286
313
|
});
|
|
287
314
|
if (createResponse.status() !== 200 && createResponse.status() !== 201) {
|
|
288
315
|
throw new Error(`Failed to create cluster "${clusterName}": ` +
|
|
@@ -300,11 +327,12 @@ async function createClusterViaApi(page, clusterName, region = 'GCP') {
|
|
|
300
327
|
if (!clusterId) {
|
|
301
328
|
throw new Error(`Cluster creation response missing UUID: ${JSON.stringify(result)}`);
|
|
302
329
|
}
|
|
303
|
-
console.log(`Created cluster via API: clusterId=${clusterId} namespace=${clusterId}-zeebe
|
|
330
|
+
console.log(`Created cluster via API: clusterId=${clusterId} namespace=${clusterId}-zeebe ` +
|
|
331
|
+
`orgId=${orgId} name="${clusterName}" tasklistMode=${tasklistV2Enabled ? 'v2' : 'v1'}`);
|
|
304
332
|
return clusterId;
|
|
305
333
|
}
|
|
306
334
|
exports.createClusterViaApi = createClusterViaApi;
|
|
307
|
-
async function ensureClusterViaApi(page, clusterName, region = 'GCP') {
|
|
335
|
+
async function ensureClusterViaApi(page, clusterName, region = 'GCP', tasklistV2Enabled = resolveTasklistV2Enabled()) {
|
|
308
336
|
// Versions with more than one Tasklist-mode Playwright project (e.g. 8.8,
|
|
309
337
|
// 8.9's chromium-v1/chromium-v2) run test-setup.spec.ts once per project,
|
|
310
338
|
// concurrently, against the same org -- and both target a cluster with
|
|
@@ -319,11 +347,15 @@ async function ensureClusterViaApi(page, clusterName, region = 'GCP') {
|
|
|
319
347
|
// setup already created it. Adopt it instead of destroying it -- whichever
|
|
320
348
|
// project's setup gets here first "wins" and creates it, the other one
|
|
321
349
|
// just reuses it.
|
|
350
|
+
//
|
|
351
|
+
// The nightly runs the two Tasklist-mode legs in separate orgs (c8_org_1 for
|
|
352
|
+
// v1, c8_org_2 for v2), so an adopted cluster always carries the mode this
|
|
353
|
+
// leg asked for.
|
|
322
354
|
const existing = await findClusterByName(page, clusterName);
|
|
323
355
|
if (existing) {
|
|
324
356
|
return existing.uuid;
|
|
325
357
|
}
|
|
326
|
-
return createClusterViaApi(page, clusterName, region);
|
|
358
|
+
return createClusterViaApi(page, clusterName, region, tasklistV2Enabled);
|
|
327
359
|
}
|
|
328
360
|
exports.ensureClusterViaApi = ensureClusterViaApi;
|
|
329
361
|
async function ensureTasklistV2Enabled(page, clusterUuid) {
|