@camunda/e2e-test-suite 0.0.843 → 0.0.845
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.8/ClusterPage.js +6 -1
- package/dist/pages/8.8/FormJsPage.js +1 -1
- package/dist/pages/8.8/ModelerCreatePage.d.ts +1 -1
- package/dist/pages/8.8/ModelerCreatePage.js +49 -21
- package/dist/pages/8.8/ModelerHomePage.js +2 -2
- package/dist/pages/8.8/TaskPanelPage.js +6 -1
- package/dist/pages/8.8/UtilitiesPage.js +6 -1
- package/dist/tests/8.8/access-user-role-management.spec.js +1 -1
- package/dist/tests/8.8/console-user-flows.spec.js +11 -0
- package/dist/tests/8.8/hto-user-flows.spec.js +14 -1
- package/dist/tests/8.8/test-setup.spec.js +20 -7
- package/dist/utils/consoleApiHelpers.d.ts +1 -0
- package/dist/utils/consoleApiHelpers.js +23 -1
- package/package.json +1 -1
|
@@ -105,12 +105,17 @@ class ClusterPage {
|
|
|
105
105
|
.filter({ hasNotText: 'Generation' }); //Filter out header row
|
|
106
106
|
this.tasklistV1Api = page.getByText('Tasklist API v1 (legacy)');
|
|
107
107
|
this.tasklistV2Api = page.getByText('Tasklist API v2');
|
|
108
|
-
this.cluster = (clusterName) => this.clustersList
|
|
108
|
+
this.cluster = (clusterName) => this.clustersList
|
|
109
|
+
.filter({
|
|
110
|
+
has: page.getByRole('link', { name: clusterName, exact: true }),
|
|
111
|
+
})
|
|
112
|
+
.first();
|
|
109
113
|
this.clusterHealthiness = (clusterName) => this.cluster(clusterName).getByText(`Healthy`, {
|
|
110
114
|
exact: true,
|
|
111
115
|
});
|
|
112
116
|
this.clusterLink = (clusterName) => this.cluster(clusterName).getByRole('link', {
|
|
113
117
|
name: clusterName,
|
|
118
|
+
exact: true,
|
|
114
119
|
});
|
|
115
120
|
this.clusterVersion = (clusterName, versionText) => this.cluster(clusterName).getByText(versionText);
|
|
116
121
|
}
|
|
@@ -118,7 +118,7 @@ class FormJsPage {
|
|
|
118
118
|
await cluster.click();
|
|
119
119
|
await (0, test_1.expect)(this.dialog
|
|
120
120
|
.locator('label')
|
|
121
|
-
.filter({ hasText: clusterName })
|
|
121
|
+
.filter({ hasText: new RegExp(`^${clusterName}`) })
|
|
122
122
|
.getByRole('switch')).toBeChecked({ timeout: 30000 });
|
|
123
123
|
await (0, test_1.expect)(this.dialog).toHaveText(healthyRegex, {
|
|
124
124
|
timeout: healthCheckTimeout,
|
|
@@ -138,7 +138,7 @@ declare class ModelerCreatePage {
|
|
|
138
138
|
clickStartInstanceSubButton(): Promise<void>;
|
|
139
139
|
runProcessInstance(clusterName: string, variables?: string, formVariables?: {
|
|
140
140
|
[key: string]: string;
|
|
141
|
-
}, textToVisible?: string): Promise<void>;
|
|
141
|
+
}, textToVisible?: string, expectRejection?: boolean): Promise<void>;
|
|
142
142
|
selectCluster(clusterName: string): Promise<void>;
|
|
143
143
|
clickViewProcessInstanceLink(): Promise<void>;
|
|
144
144
|
clickNameInput(): Promise<void>;
|
|
@@ -554,12 +554,16 @@ class ModelerCreatePage {
|
|
|
554
554
|
await this.deployAndRunSubButton.click({ timeout: 30000 }); //will be available from alpha7
|
|
555
555
|
}
|
|
556
556
|
}
|
|
557
|
-
async runProcessInstance(clusterName, variables = '', formVariables = {}, textToVisible = '') {
|
|
558
|
-
// After a 8.7->8.8 upgrade,
|
|
559
|
-
//
|
|
560
|
-
//
|
|
561
|
-
//
|
|
562
|
-
//
|
|
557
|
+
async runProcessInstance(clusterName, variables = '', formVariables = {}, textToVisible = '', expectRejection = false) {
|
|
558
|
+
// After a 8.7->8.8 upgrade, or right after a cluster is freshly created
|
|
559
|
+
// (test-setup.spec.ts now deletes+recreates "Test Cluster"/"AWS Cluster"
|
|
560
|
+
// via the Console API on every run instead of reusing a long-lived one),
|
|
561
|
+
// orchestration-cluster authorization commands propagate across
|
|
562
|
+
// partitions for a short window; deploy & run is rejected with FORBIDDEN
|
|
563
|
+
// until the deployer's grant lands. Detect that rejection and retry
|
|
564
|
+
// through the propagation window, rather than returning a
|
|
565
|
+
// silently-failed run — this used to only matter for migration runs,
|
|
566
|
+
// but a just-created cluster hits the same window on every run now.
|
|
563
567
|
const isMigration = process.env.IS_MIGRATION === 'true';
|
|
564
568
|
const maxRetries = isMigration ? 20 : 10;
|
|
565
569
|
const retryDelayMs = 20000;
|
|
@@ -592,14 +596,19 @@ class ModelerCreatePage {
|
|
|
592
596
|
});
|
|
593
597
|
}
|
|
594
598
|
await this.clickStartInstanceSubButton();
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
599
|
+
const deployRejected = await this.deployErrorMessage
|
|
600
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
601
|
+
.then(() => true)
|
|
602
|
+
.catch(() => false);
|
|
603
|
+
if (deployRejected) {
|
|
604
|
+
// Some callers (e.g. under-privileged role flows) deliberately expect
|
|
605
|
+
// the deploy to be rejected -- that rejection is the assertion under
|
|
606
|
+
// test, not a transient propagation window to retry through. Return
|
|
607
|
+
// immediately so the caller's own UI assertion on the rejection can run.
|
|
608
|
+
if (expectRejection) {
|
|
609
|
+
return;
|
|
602
610
|
}
|
|
611
|
+
throw new Error('Deploy & run rejected; authorization may still be propagating');
|
|
603
612
|
}
|
|
604
613
|
return;
|
|
605
614
|
}
|
|
@@ -617,19 +626,38 @@ class ModelerCreatePage {
|
|
|
617
626
|
await (0, test_1.expect)(this.dialog).toBeVisible({ timeout: 30000 });
|
|
618
627
|
const healthCheckTimeout = 30000;
|
|
619
628
|
const healthyRegex = new RegExp(`${clusterName}.*?HealthydevManage`);
|
|
620
|
-
const
|
|
621
|
-
await (0, test_1.expect)(cluster).toBeVisible({ timeout: 30000 });
|
|
622
|
-
await cluster.click();
|
|
623
|
-
await (0, test_1.expect)(this.dialog
|
|
629
|
+
const clusterLabel = this.dialog
|
|
624
630
|
.locator('label')
|
|
625
|
-
.filter({ hasText: clusterName })
|
|
626
|
-
|
|
631
|
+
.filter({ hasText: new RegExp(`^${clusterName}`) });
|
|
632
|
+
await (0, test_1.expect)(clusterLabel).toBeVisible({ timeout: 30000 });
|
|
633
|
+
await clusterLabel.click();
|
|
634
|
+
await (0, test_1.expect)(clusterLabel.getByRole('switch')).toBeChecked({
|
|
635
|
+
timeout: 30000,
|
|
636
|
+
});
|
|
627
637
|
await (0, test_1.expect)(this.dialog).toHaveText(healthyRegex, {
|
|
628
638
|
timeout: healthCheckTimeout,
|
|
629
639
|
});
|
|
630
640
|
}
|
|
631
641
|
async clickViewProcessInstanceLink() {
|
|
632
|
-
|
|
642
|
+
// The notification containing this link keeps detaching and re-rendering
|
|
643
|
+
// continuously (observed as "element was detached from the DOM, retrying"
|
|
644
|
+
// recurring for the entire length of a 60s attempt, not just a one-off
|
|
645
|
+
// glitch), so waiting longer for it to "stabilize" doesn't help -- there
|
|
646
|
+
// may be no stable window at all. Skip the actionability/stability wait
|
|
647
|
+
// with force, and iterate quickly so more attempts land inside whatever
|
|
648
|
+
// brief windows do exist, instead of a few very long, equally-doomed ones.
|
|
649
|
+
const maxRetries = 10;
|
|
650
|
+
for (let retries = 0; retries < maxRetries; retries++) {
|
|
651
|
+
try {
|
|
652
|
+
await this.viewProcessInstanceLink.click({ force: true, timeout: 5000 });
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
catch (error) {
|
|
656
|
+
console.error(`Click attempt ${retries + 1} failed: ${error}`);
|
|
657
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
throw new Error(`Failed to click "View process instance" after ${maxRetries} attempts.`);
|
|
633
661
|
}
|
|
634
662
|
async clickNameInput() {
|
|
635
663
|
await this.nameInput.click({ timeout: 60000 });
|
|
@@ -1133,7 +1161,7 @@ class ModelerCreatePage {
|
|
|
1133
1161
|
// before saving. This handles environments with multiple clusters.
|
|
1134
1162
|
const clusterLabel = configureEnvDialog
|
|
1135
1163
|
.locator('label')
|
|
1136
|
-
.filter({ hasText: clusterName });
|
|
1164
|
+
.filter({ hasText: new RegExp(`^${clusterName}`) });
|
|
1137
1165
|
const clusterSwitch = clusterLabel.getByRole('switch');
|
|
1138
1166
|
await (0, test_1.expect)(clusterLabel).toBeVisible({ timeout });
|
|
1139
1167
|
const alreadyChecked = (await clusterSwitch.getAttribute('aria-checked')) === 'true';
|
|
@@ -301,7 +301,7 @@ class ModelerHomePage {
|
|
|
301
301
|
async selectCluster(clusterName) {
|
|
302
302
|
//Select the correct cluster if multiple exist
|
|
303
303
|
const baseClusterName = clusterName.split('(')[0].trim();
|
|
304
|
-
const cluster = this.dialog.getByText(
|
|
304
|
+
const cluster = this.dialog.getByText(new RegExp(`^${baseClusterName}`));
|
|
305
305
|
await (0, test_1.expect)(cluster).toBeVisible({
|
|
306
306
|
timeout: 30000,
|
|
307
307
|
});
|
|
@@ -309,7 +309,7 @@ class ModelerHomePage {
|
|
|
309
309
|
await (0, test_1.expect)(this.dialog
|
|
310
310
|
.locator('label')
|
|
311
311
|
.filter({
|
|
312
|
-
hasText: clusterName,
|
|
312
|
+
hasText: new RegExp(`^${clusterName}`),
|
|
313
313
|
})
|
|
314
314
|
.getByRole('switch')).toBeChecked({ timeout: 30000 });
|
|
315
315
|
}
|
|
@@ -32,7 +32,12 @@ class TaskPanelPage {
|
|
|
32
32
|
}
|
|
33
33
|
async openTask(name) {
|
|
34
34
|
let attempts = 0;
|
|
35
|
-
|
|
35
|
+
// Tasklist's importer can lag well behind Zeebe under heavy concurrent
|
|
36
|
+
// load from the sibling chromium-v1/chromium-v2 projects sharing one
|
|
37
|
+
// cluster -- trace evidence from failing runs showed other tests' tasks
|
|
38
|
+
// only appearing 15-17 minutes after creation. 10 x 120s gives 20 minutes
|
|
39
|
+
// of budget, comfortably covering that observed lag.
|
|
40
|
+
const maxAttempts = 10;
|
|
36
41
|
while (attempts < maxAttempts) {
|
|
37
42
|
try {
|
|
38
43
|
const task = this.availableTasks.getByText(name, { exact: true }).first();
|
|
@@ -34,6 +34,12 @@ async function forceLogoutIfNeeded(page) {
|
|
|
34
34
|
exports.forceLogoutIfNeeded = forceLogoutIfNeeded;
|
|
35
35
|
async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 3) {
|
|
36
36
|
let lastError;
|
|
37
|
+
// Stagger the first navigation across parallel workers. Without this, every
|
|
38
|
+
// worker's initial page.goto('/') fires within the same second -- with 18+
|
|
39
|
+
// workers logging in at once, that burst is enough to make the navigation
|
|
40
|
+
// itself time out well before any login form ever renders. Retries already
|
|
41
|
+
// back off via randomSleep below, so this only needs to run once.
|
|
42
|
+
await (0, sleep_1.sleep)(timeout);
|
|
37
43
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
38
44
|
try {
|
|
39
45
|
await page.context().clearCookies();
|
|
@@ -58,7 +64,6 @@ async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 3
|
|
|
58
64
|
await page
|
|
59
65
|
.waitForLoadState('networkidle', { timeout: 30000 })
|
|
60
66
|
.catch(() => { });
|
|
61
|
-
await (0, sleep_1.sleep)(timeout);
|
|
62
67
|
await (0, test_1.expect)(loginPage.loginMessage.or(loginPage.passwordHeading)).toBeVisible({ timeout: 60000 });
|
|
63
68
|
await loginPage.loginWithTestUser(testUser);
|
|
64
69
|
return;
|
|
@@ -215,7 +215,7 @@ _8_8_1.test.describe('User Roles User Flow', () => {
|
|
|
215
215
|
await modelerCreatePage.clickAppendElementButton();
|
|
216
216
|
await modelerCreatePage.clickAppendEndEventButton();
|
|
217
217
|
await (0, sleep_1.sleep)(20000);
|
|
218
|
-
await modelerCreatePage.runProcessInstance(clusterName);
|
|
218
|
+
await modelerCreatePage.runProcessInstance(clusterName, '', {}, '', true);
|
|
219
219
|
await (0, test_1.expect)(page.getByText('The diagram failed to deploy & run')).toBeVisible({ timeout: 60000 });
|
|
220
220
|
await modelerCreatePage.clickCloseButton();
|
|
221
221
|
});
|
|
@@ -69,6 +69,17 @@ _8_8_1.test.describe('Console User Flow Tests @tasklistV2', () => {
|
|
|
69
69
|
await (0, UtilitiesPage_1.assertLocatorVisibleWithRetry)(operateTabProcessInstancePage, operateTabProcessInstancePage.completedIcon, 'completed icon in Operate', 60000);
|
|
70
70
|
});
|
|
71
71
|
});
|
|
72
|
+
(0, _8_8_1.test)('Create Cluster', async ({ homePage, clusterPage }) => {
|
|
73
|
+
_8_8_1.test.slow();
|
|
74
|
+
const newClusterName = 'UI Test Cluster';
|
|
75
|
+
await _8_8_1.test.step('Navigate to clusters and create cluster', async () => {
|
|
76
|
+
await homePage.clickClusters();
|
|
77
|
+
await clusterPage.createCluster(newClusterName);
|
|
78
|
+
});
|
|
79
|
+
await _8_8_1.test.step('Assert cluster is healthy', async () => {
|
|
80
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(newClusterName, 300000, 1500000);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
72
83
|
(0, _8_8_1.test)('Alert Trigger Flow - Email Notification', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, clusterPage, clusterDetailsPage, connectorSettingsPage, operateHomePage, operateProcessesPage, operateProcessInstancePage, }) => {
|
|
73
84
|
_8_8_1.test.slow();
|
|
74
85
|
const processName = 'Email_Alert_Process' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
@@ -13,6 +13,7 @@ const UtilitiesPage_1 = require("../../pages/8.8/UtilitiesPage");
|
|
|
13
13
|
const sleep_1 = require("../../utils/sleep");
|
|
14
14
|
const fileUpload_1 = require("../../utils/fileUpload");
|
|
15
15
|
const resetSession_1 = require("../../utils/resetSession");
|
|
16
|
+
const consoleApiHelpers_1 = require("../../utils/consoleApiHelpers");
|
|
16
17
|
const expectTextWithPagination_1 = require("../../utils/assertionHelpers/expectTextWithPagination");
|
|
17
18
|
const expectTextWithRetry_1 = require("../../utils/assertionHelpers/expectTextWithRetry");
|
|
18
19
|
const users_1 = require("../../utils/users");
|
|
@@ -473,6 +474,18 @@ _8_8_1.test.describe('HTO User Flow Tests', () => {
|
|
|
473
474
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
474
475
|
const processName = 'User_Task_Process_With_Public_Form' + randomString;
|
|
475
476
|
const formName = 'Public form' + randomString;
|
|
477
|
+
// Public start forms are a v1-only feature; the shared "Test Cluster"
|
|
478
|
+
// used by the rest of this file is deliberately kept on v1 (via
|
|
479
|
+
// createClusterViaApi's tasklistV2Enabled: false) so job-worker-based
|
|
480
|
+
// user tasks keep working there. This assertion needs the opposite --
|
|
481
|
+
// a genuinely v2-upgraded backend -- so it gets its own dedicated
|
|
482
|
+
// cluster rather than sharing one that can never satisfy both.
|
|
483
|
+
const v2ClusterName = 'Public Form V2 Cluster';
|
|
484
|
+
await _8_8_1.test.step('Create Dedicated Tasklist V2 Cluster', async () => {
|
|
485
|
+
const clusterUuid = await (0, consoleApiHelpers_1.ensureClusterViaApi)(page, v2ClusterName);
|
|
486
|
+
await (0, consoleApiHelpers_1.ensureTasklistV2Enabled)(page, clusterUuid);
|
|
487
|
+
await (0, consoleApiHelpers_1.waitForClusterHealthyViaApi)(page, clusterUuid);
|
|
488
|
+
});
|
|
476
489
|
await _8_8_1.test.step('Navigate to Web Modeler', async () => {
|
|
477
490
|
await (0, test_1.expect)(homePage.camundaComponentsButton).toBeVisible({
|
|
478
491
|
timeout: 120000,
|
|
@@ -503,7 +516,7 @@ _8_8_1.test.describe('HTO User Flow Tests', () => {
|
|
|
503
516
|
await modelerCreatePage.modelCamundaUserTaskDiagram(processName, processName);
|
|
504
517
|
await modelerCreatePage.linkFormToStartEvent(formName);
|
|
505
518
|
await modelerCreatePage.enablePublicAccessIfDisabled();
|
|
506
|
-
await modelerCreatePage.deployDiagram(
|
|
519
|
+
await modelerCreatePage.deployDiagram(v2ClusterName);
|
|
507
520
|
await (0, sleep_1.sleep)(5000);
|
|
508
521
|
});
|
|
509
522
|
let publicFormLink;
|
|
@@ -7,6 +7,7 @@ const sleep_1 = require("../../utils/sleep");
|
|
|
7
7
|
const connectorSecrets_1 = require("../../utils/connectorSecrets");
|
|
8
8
|
const UtilitiesPage_1 = require("../../pages/8.8/UtilitiesPage");
|
|
9
9
|
const users_1 = require("../../utils/users");
|
|
10
|
+
const consoleApiHelpers_1 = require("../../utils/consoleApiHelpers");
|
|
10
11
|
_8_8_1.test.describe.configure({ mode: 'parallel' });
|
|
11
12
|
_8_8_1.test.describe('Cluster Setup Tests', () => {
|
|
12
13
|
_8_8_1.test.afterEach(async ({ page }, testInfo) => {
|
|
@@ -31,9 +32,15 @@ _8_8_1.test.describe('Cluster Setup Tests', () => {
|
|
|
31
32
|
const clusterName = 'Test Cluster';
|
|
32
33
|
const apiClientName = 'Test_API_Client' + (await (0, _setup_1.generateRandomStringAsync)(3));
|
|
33
34
|
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, users_1.testUsers.mainUser, (testInfo.workerIndex + 1) * 1000);
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
if (process.env.IS_PROD === 'true') {
|
|
36
|
+
await clusterPage.createCluster(clusterName);
|
|
37
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(clusterName);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const clusterUuid = await (0, consoleApiHelpers_1.ensureClusterViaApi)(page, clusterName);
|
|
41
|
+
await (0, consoleApiHelpers_1.waitForClusterHealthyViaApi)(page, clusterUuid);
|
|
42
|
+
await homePage.clickClusters();
|
|
43
|
+
}
|
|
37
44
|
await clusterPage.clickClusterLink(clusterName);
|
|
38
45
|
await clusterDetailsPage.assertComponentsHealth();
|
|
39
46
|
if (process.env.IS_AG !== 'true' && process.env.IS_MIGRATION !== 'true') {
|
|
@@ -53,10 +60,16 @@ _8_8_1.test.describe('Cluster Setup Tests', () => {
|
|
|
53
60
|
_8_8_1.test.slow();
|
|
54
61
|
const clusterName = 'AWS Cluster';
|
|
55
62
|
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, users_1.testUsers.mainUser, (testInfo.workerIndex + 1) * 1000);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
63
|
+
if (process.env.IS_PROD === 'true') {
|
|
64
|
+
await clusterPage.createCluster(clusterName, 'AWS');
|
|
65
|
+
// AWS clusters on SaaS INT routinely need 10+ min to reach Healthy.
|
|
66
|
+
await clusterPage.assertClusterHealthyStatusWithRetry(clusterName, 300000, 1500000);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
const clusterUuid = await (0, consoleApiHelpers_1.ensureClusterViaApi)(page, clusterName, 'AWS');
|
|
70
|
+
await (0, consoleApiHelpers_1.waitForClusterHealthyViaApi)(page, clusterUuid, 1500000);
|
|
71
|
+
await homePage.clickClusters();
|
|
72
|
+
}
|
|
60
73
|
await clusterPage.clickClusterLink(clusterName);
|
|
61
74
|
await clusterDetailsPage.assertComponentsHealth();
|
|
62
75
|
if (process.env.IS_AG !== 'true') {
|
|
@@ -2,4 +2,5 @@ import { Page } from '@playwright/test';
|
|
|
2
2
|
export declare function deleteClusterViaApi(page: Page, clusterName: string): Promise<void>;
|
|
3
3
|
export declare function createClusterViaApi(page: Page, clusterName: string, region?: string): Promise<string>;
|
|
4
4
|
export declare function ensureClusterViaApi(page: Page, clusterName: string, region?: string): Promise<string>;
|
|
5
|
+
export declare function ensureTasklistV2Enabled(page: Page, clusterUuid: string): Promise<void>;
|
|
5
6
|
export declare function waitForClusterHealthyViaApi(page: Page, clusterUuid: string, timeoutMs?: number): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.waitForClusterHealthyViaApi = exports.ensureClusterViaApi = exports.createClusterViaApi = exports.deleteClusterViaApi = void 0;
|
|
3
|
+
exports.waitForClusterHealthyViaApi = exports.ensureTasklistV2Enabled = exports.ensureClusterViaApi = exports.createClusterViaApi = exports.deleteClusterViaApi = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const sleep_1 = require("./sleep");
|
|
6
6
|
const PLAN_TYPE_ID = '574cde5f-54ae-43c1-851a-e6fb4f03423a';
|
|
@@ -169,6 +169,28 @@ async function ensureClusterViaApi(page, clusterName, region = 'GCP') {
|
|
|
169
169
|
return createClusterViaApi(page, clusterName, region);
|
|
170
170
|
}
|
|
171
171
|
exports.ensureClusterViaApi = ensureClusterViaApi;
|
|
172
|
+
async function ensureTasklistV2Enabled(page, clusterUuid) {
|
|
173
|
+
// Console's cluster settings UI frames this as a one-time "Upgrade to
|
|
174
|
+
// Tasklist v2" action performed after creation (new clusters start on v1),
|
|
175
|
+
// not something reliably controllable via the create payload alone. Call
|
|
176
|
+
// the same update endpoint that action uses, explicitly, so a dedicated
|
|
177
|
+
// cluster genuinely ends up v2-enabled regardless of the create call's own
|
|
178
|
+
// default. This is irreversible -- only use it on a cluster dedicated to
|
|
179
|
+
// tests that specifically require a real v2-upgraded backend, never on a
|
|
180
|
+
// cluster shared with anything that needs v1 (e.g. job-worker-based user
|
|
181
|
+
// tasks, draft variables, public start forms).
|
|
182
|
+
const token = await getUserToken(page);
|
|
183
|
+
const orgId = getOrgId();
|
|
184
|
+
const response = await page.request.patch(`${getConsoleBaseUrl()}/api/orgs/${orgId}/clusters/${clusterUuid}`, {
|
|
185
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
186
|
+
data: { tasklistV2Enabled: true },
|
|
187
|
+
});
|
|
188
|
+
if (response.status() !== 200 && response.status() !== 204) {
|
|
189
|
+
throw new Error(`Failed to upgrade cluster "${clusterUuid}" to Tasklist v2: ` +
|
|
190
|
+
`HTTP ${response.status()} - ${await response.text()}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
exports.ensureTasklistV2Enabled = ensureTasklistV2Enabled;
|
|
172
194
|
async function waitForClusterHealthyViaApi(page, clusterUuid, timeoutMs = 1500000) {
|
|
173
195
|
const orgId = getOrgId();
|
|
174
196
|
const url = `${getConsoleBaseUrl()}/api/orgs/${orgId}/clusters/${clusterUuid}`;
|