@camunda/e2e-test-suite 0.0.572 → 0.0.574
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.9/UtilitiesPage.js +27 -4
- package/dist/pages/SM-8.9/ConnectorSettingsPage.js +3 -0
- package/dist/pages/SM-8.9/ModelerCreatePage.js +4 -1
- package/dist/pages/SM-8.9/UtilitiesPage.js +6 -0
- package/dist/tests/8.9/api-tests-v2.spec.js +1 -1
- package/dist/tests/8.9/operate-access-flow.spec.js +68 -7
- package/dist/tests/8.9/optimize-api-tests.spec.js +705 -59
- package/dist/utils/apiHelpers.js +41 -7
- package/dist/utils/utils.js +2 -2
- package/package.json +1 -1
|
@@ -9,21 +9,44 @@ const randomSleep_1 = require("../../utils/randomSleep");
|
|
|
9
9
|
const fileUpload_1 = require("../../utils/fileUpload");
|
|
10
10
|
const mailSlurpClient_1 = require("../../utils/mailSlurpClient");
|
|
11
11
|
async function loginWithRetry(page, loginPage, testUser, timeout, maxRetries = 3) {
|
|
12
|
+
let lastError;
|
|
12
13
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
13
14
|
try {
|
|
14
|
-
await page.
|
|
15
|
+
await page.context().clearCookies();
|
|
16
|
+
await page.goto('about:blank');
|
|
17
|
+
await page
|
|
18
|
+
.evaluate(() => {
|
|
19
|
+
try {
|
|
20
|
+
localStorage.clear();
|
|
21
|
+
}
|
|
22
|
+
catch (_) {
|
|
23
|
+
// storage may be unavailable in some contexts
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
sessionStorage.clear();
|
|
27
|
+
}
|
|
28
|
+
catch (_) {
|
|
29
|
+
// storage may be unavailable in some contexts
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
.catch(() => { });
|
|
33
|
+
await page.goto('/', { waitUntil: 'domcontentloaded', timeout: 60000 });
|
|
34
|
+
await page
|
|
35
|
+
.waitForLoadState('networkidle', { timeout: 30000 })
|
|
36
|
+
.catch(() => { });
|
|
15
37
|
await (0, sleep_1.sleep)(timeout);
|
|
16
38
|
await loginPage.loginWithTestUser(testUser);
|
|
17
39
|
return;
|
|
18
40
|
}
|
|
19
41
|
catch (error) {
|
|
42
|
+
lastError = error;
|
|
20
43
|
if (attempt < maxRetries - 1) {
|
|
21
|
-
console.warn(`Attempt ${attempt + 1} failed for logging in. Retrying
|
|
44
|
+
console.warn(`Attempt ${attempt + 1} failed for logging in. Retrying with clean session...`, error);
|
|
22
45
|
await (0, randomSleep_1.randomSleep)(10000, 20000);
|
|
23
46
|
}
|
|
24
47
|
else {
|
|
25
|
-
console.error(
|
|
26
|
-
throw new Error(`Login failed after ${maxRetries} attempts`);
|
|
48
|
+
console.error(lastError);
|
|
49
|
+
throw new Error(`Login failed after ${maxRetries} attempts: ${String(lastError)}`);
|
|
27
50
|
}
|
|
28
51
|
}
|
|
29
52
|
}
|
|
@@ -86,6 +86,9 @@ class ConnectorSettingsPage {
|
|
|
86
86
|
}
|
|
87
87
|
async fillUsernameInput(username) {
|
|
88
88
|
await this.usernameInput.fill(username, { timeout: 30000 });
|
|
89
|
+
// Press Tab to trigger blur, which commits the value and clears the
|
|
90
|
+
// "Username must not be empty." validation error in the FEEL expression field.
|
|
91
|
+
await this.usernameInput.press('Tab');
|
|
89
92
|
await (0, test_1.expect)(this.page.getByText('Username must not be empty.')).not.toBeVisible({ timeout: 30000 });
|
|
90
93
|
}
|
|
91
94
|
async clickPasswordInput() {
|
|
@@ -978,7 +978,10 @@ class ModelerCreatePage {
|
|
|
978
978
|
catch {
|
|
979
979
|
await this.nameInput.click();
|
|
980
980
|
await this.nameInput.fill(processName);
|
|
981
|
-
|
|
981
|
+
// Press Enter to commit the name into the BPMN model before focus moves
|
|
982
|
+
// away. Without this the value may not persist when the canvas element
|
|
983
|
+
// is clicked next (properties panel re-renders discarding uncommitted edits).
|
|
984
|
+
await this.nameInput.press('Enter');
|
|
982
985
|
}
|
|
983
986
|
}
|
|
984
987
|
async switchToImplementTab() {
|
|
@@ -149,6 +149,12 @@ async function modelRestConnector(modelerCreatePage, connectorSettingsPage, conn
|
|
|
149
149
|
await modelerCreatePage.enterDiagramName(processName);
|
|
150
150
|
await (0, sleep_1.sleep)(1000);
|
|
151
151
|
await modelerCreatePage.clickCanvas();
|
|
152
|
+
// Wait for the canvas click to register and the process-level General panel to
|
|
153
|
+
// become visible before interacting with it. Without this wait the panel may
|
|
154
|
+
// still reflect the previous element selection and the ID/name fills target
|
|
155
|
+
// the wrong (or a hidden) element, leaving the BPMN process name as the
|
|
156
|
+
// default "New BPMN diagram" when deployed.
|
|
157
|
+
await (0, test_1.expect)(modelerCreatePage.generalPanel).toBeVisible({ timeout: 60000 });
|
|
152
158
|
await modelerCreatePage.clickGeneralPropertiesPanel();
|
|
153
159
|
await modelerCreatePage.clickIdInput();
|
|
154
160
|
await modelerCreatePage.fillIdInput(processName);
|
|
@@ -6,7 +6,7 @@ _8_9_1.test.describe.configure({ mode: 'parallel' });
|
|
|
6
6
|
_8_9_1.test.describe('API V2 tests on SaaS cluster ', () => {
|
|
7
7
|
let bearerToken;
|
|
8
8
|
_8_9_1.test.beforeAll(async () => {
|
|
9
|
-
bearerToken = await (0, apiHelpers_1.authSaasAPI)();
|
|
9
|
+
bearerToken = await (0, apiHelpers_1.authSaasAPI)(process.env.ZEEBE_API_TOKEN_AUDIENCE);
|
|
10
10
|
});
|
|
11
11
|
(0, _8_9_1.test)('Get cluster topology', async ({ request }) => {
|
|
12
12
|
const topologyResponse = await request.get(`${process.env.ZEEBE_API_URL}/v2/topology`, {
|
|
@@ -4,6 +4,7 @@ const test_1 = require("@playwright/test");
|
|
|
4
4
|
const _8_9_1 = require("../../fixtures/8.9");
|
|
5
5
|
const UtilitiesPage_1 = require("../../pages/8.9/UtilitiesPage");
|
|
6
6
|
const _setup_1 = require("../../test-setup.js");
|
|
7
|
+
const apiHelpers_1 = require("../../utils/apiHelpers");
|
|
7
8
|
const users_1 = require("../../utils/users");
|
|
8
9
|
const urlHelpers_1 = require("../../utils/urlHelpers");
|
|
9
10
|
const testUser = (0, users_1.getTestUser)('twentySecondUser');
|
|
@@ -25,8 +26,9 @@ _8_9_1.test.describe('Operate access requires authentication @tasklistV2', () =>
|
|
|
25
26
|
await clusterDetailsPage.deleteAPIClientsIfExist(clientName);
|
|
26
27
|
}
|
|
27
28
|
});
|
|
28
|
-
(0, _8_9_1.test)('check that request POST /v2/process-definitions/search returns
|
|
29
|
-
clientName = `operate-
|
|
29
|
+
(0, _8_9_1.test)('check that request POST /v2/process-definitions/search returns 200 with valid credentials', async ({ homePage, clusterPage, clusterDetailsPage, clientCredentialsDetailsPage, request, }) => {
|
|
30
|
+
clientName = `operate-allow-${await (0, _setup_1.generateRandomStringAsync)(5)}`;
|
|
31
|
+
let operateUrl = '';
|
|
30
32
|
await _8_9_1.test.step('Add API Client to Cluster', async () => {
|
|
31
33
|
await homePage.clickClusters();
|
|
32
34
|
await clusterPage.clickClusterLink(clusterName);
|
|
@@ -35,22 +37,81 @@ _8_9_1.test.describe('Operate access requires authentication @tasklistV2', () =>
|
|
|
35
37
|
await clusterDetailsPage.clickCloseModalButton();
|
|
36
38
|
await (0, test_1.expect)(clusterDetailsPage.clientsList.filter({ hasText: clientName })).toBeVisible({ timeout: 6000 });
|
|
37
39
|
});
|
|
38
|
-
|
|
39
|
-
await _8_9_1.test.step('Capture Operate URL from client credentials page and close it', async () => {
|
|
40
|
+
await _8_9_1.test.step('Capture Operate URL', async () => {
|
|
40
41
|
await clusterDetailsPage.searchAndClickClientCredentialsLink(clientName);
|
|
41
42
|
operateUrl = await clientCredentialsDetailsPage.getOperateUrl();
|
|
42
43
|
(0, test_1.expect)(operateUrl).toMatch(/^https?:\/\//);
|
|
43
44
|
await clientCredentialsDetailsPage.goBack();
|
|
44
45
|
await clusterDetailsPage.clickAPITab();
|
|
45
46
|
});
|
|
46
|
-
await _8_9_1.test.step('POST search endpoint
|
|
47
|
+
await _8_9_1.test.step('POST search endpoint with valid Zeebe bearer token returns 200 or 405', async () => {
|
|
48
|
+
const validToken = await (0, apiHelpers_1.authSaasAPI)();
|
|
47
49
|
const sanitizedOperateUrl = (0, urlHelpers_1.sanitizeUrl)(operateUrl);
|
|
48
50
|
const response = await request.post(`${sanitizedOperateUrl}/v2/process-definitions/search`, {
|
|
51
|
+
headers: {
|
|
52
|
+
Authorization: validToken,
|
|
53
|
+
'Content-Type': 'application/json',
|
|
54
|
+
},
|
|
55
|
+
data: { filter: {}, size: 10 },
|
|
56
|
+
});
|
|
57
|
+
(0, test_1.expect)([200, 405]).toContain(response.status());
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
(0, _8_9_1.test)('check that POST /v2/user-tasks/search returns 401 without credentials', async ({ homePage, clusterPage, clusterDetailsPage, clientCredentialsDetailsPage, request, }) => {
|
|
61
|
+
clientName = `tasklist-deny-${await (0, _setup_1.generateRandomStringAsync)(5)}`;
|
|
62
|
+
let operateUrl = '';
|
|
63
|
+
await _8_9_1.test.step('Add API Client to Cluster', async () => {
|
|
64
|
+
await homePage.clickClusters();
|
|
65
|
+
await clusterPage.clickClusterLink(clusterName);
|
|
66
|
+
await clusterDetailsPage.clickAPITab();
|
|
67
|
+
await clusterDetailsPage.createAPIClient(clientName);
|
|
68
|
+
await clusterDetailsPage.clickCloseModalButton();
|
|
69
|
+
await (0, test_1.expect)(clusterDetailsPage.clientsList.filter({ hasText: clientName })).toBeVisible({ timeout: 6000 });
|
|
70
|
+
});
|
|
71
|
+
await _8_9_1.test.step('Capture Operate URL (base URL shared with Tasklist v2 endpoint)', async () => {
|
|
72
|
+
await clusterDetailsPage.searchAndClickClientCredentialsLink(clientName);
|
|
73
|
+
operateUrl = await clientCredentialsDetailsPage.getOperateUrl();
|
|
74
|
+
(0, test_1.expect)(operateUrl).toMatch(/^https?:\/\//);
|
|
75
|
+
await clientCredentialsDetailsPage.goBack();
|
|
76
|
+
await clusterDetailsPage.clickAPITab();
|
|
77
|
+
});
|
|
78
|
+
await _8_9_1.test.step('POST /v2/user-tasks/search without auth returns 401', async () => {
|
|
79
|
+
const sanitizedOperateUrl = (0, urlHelpers_1.sanitizeUrl)(operateUrl);
|
|
80
|
+
const response = await request.post(`${sanitizedOperateUrl}/v2/user-tasks/search`, {
|
|
49
81
|
data: { filter: {}, size: 10 },
|
|
50
82
|
});
|
|
51
83
|
(0, test_1.expect)(response.status()).toBe(401);
|
|
52
|
-
|
|
53
|
-
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
(0, _8_9_1.test)('check that POST /v2/process-definitions/search with wrong-audience token returns 401', async ({ homePage, clusterPage, clusterDetailsPage, clientCredentialsDetailsPage, request, }) => {
|
|
87
|
+
clientName = `operate-wrong-aud-${await (0, _setup_1.generateRandomStringAsync)(5)}`;
|
|
88
|
+
let operateUrl = '';
|
|
89
|
+
await _8_9_1.test.step('Add API Client to Cluster', async () => {
|
|
90
|
+
await homePage.clickClusters();
|
|
91
|
+
await clusterPage.clickClusterLink(clusterName);
|
|
92
|
+
await clusterDetailsPage.clickAPITab();
|
|
93
|
+
await clusterDetailsPage.createAPIClient(clientName);
|
|
94
|
+
await clusterDetailsPage.clickCloseModalButton();
|
|
95
|
+
await (0, test_1.expect)(clusterDetailsPage.clientsList.filter({ hasText: clientName })).toBeVisible({ timeout: 6000 });
|
|
96
|
+
});
|
|
97
|
+
await _8_9_1.test.step('Capture Operate URL', async () => {
|
|
98
|
+
await clusterDetailsPage.searchAndClickClientCredentialsLink(clientName);
|
|
99
|
+
operateUrl = await clientCredentialsDetailsPage.getOperateUrl();
|
|
100
|
+
(0, test_1.expect)(operateUrl).toMatch(/^https?:\/\//);
|
|
101
|
+
await clientCredentialsDetailsPage.goBack();
|
|
102
|
+
await clusterDetailsPage.clickAPITab();
|
|
103
|
+
});
|
|
104
|
+
await _8_9_1.test.step('Token scoped for Optimize audience rejected by Operate endpoint', async () => {
|
|
105
|
+
const optimizeToken = await (0, apiHelpers_1.authSaasAPI)(process.env.OPTIMIZE_API_TOKEN_AUDIENCE);
|
|
106
|
+
const sanitizedOperateUrl = (0, urlHelpers_1.sanitizeUrl)(operateUrl);
|
|
107
|
+
const response = await request.post(`${sanitizedOperateUrl}/v2/process-definitions/search`, {
|
|
108
|
+
headers: {
|
|
109
|
+
Authorization: optimizeToken,
|
|
110
|
+
'Content-Type': 'application/json',
|
|
111
|
+
},
|
|
112
|
+
data: { filter: {}, size: 10 },
|
|
113
|
+
});
|
|
114
|
+
(0, test_1.expect)([401, 403]).toContain(response.status());
|
|
54
115
|
});
|
|
55
116
|
});
|
|
56
117
|
});
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
4
|
-
/* eslint-disable prefer-const */
|
|
5
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
6
|
-
const _8_9_1 = require("../../fixtures/8.9");
|
|
7
3
|
const test_1 = require("@playwright/test");
|
|
4
|
+
const _8_9_1 = require("../../fixtures/8.9");
|
|
5
|
+
const constants_1 = require("../../utils/constants");
|
|
8
6
|
const apiHelpers_1 = require("../../utils/apiHelpers");
|
|
9
7
|
const randomName_1 = require("../../utils/randomName");
|
|
10
8
|
_8_9_1.test.describe.configure({ mode: 'parallel' });
|
|
@@ -13,10 +11,8 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
13
11
|
let optimizeBearerToken;
|
|
14
12
|
let collectionIdValue;
|
|
15
13
|
let dashboardIdValue;
|
|
16
|
-
let collectionScopeResponse;
|
|
17
14
|
let reportId;
|
|
18
15
|
let baseUrl;
|
|
19
|
-
let exportedEntities;
|
|
20
16
|
_8_9_1.test.beforeAll(async ({ browser, request }) => {
|
|
21
17
|
const page = await browser.newPage();
|
|
22
18
|
optimizeCookie = await (0, apiHelpers_1.getOptimizeCoockie)(page);
|
|
@@ -26,7 +22,8 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
26
22
|
name: await (0, randomName_1.randomNameAgregator)('Test Collection'),
|
|
27
23
|
optimizeCookie,
|
|
28
24
|
});
|
|
29
|
-
|
|
25
|
+
baseUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
26
|
+
await (0, apiHelpers_1.updateCollectionScope)(request, {
|
|
30
27
|
optimizeCookie,
|
|
31
28
|
collectionId: collectionIdValue,
|
|
32
29
|
data: [
|
|
@@ -56,11 +53,14 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
56
53
|
},
|
|
57
54
|
],
|
|
58
55
|
});
|
|
59
|
-
baseUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
60
56
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
57
|
+
_8_9_1.test.afterAll(async ({ request }) => {
|
|
58
|
+
if (collectionIdValue) {
|
|
59
|
+
await request.delete(`${baseUrl}/api/public/collection/${collectionIdValue}`, { headers: { Authorization: optimizeBearerToken } });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
(0, _8_9_1.test)('Get dashboard IDs returns 200 with id array', async ({ request }) => {
|
|
63
|
+
await _8_9_1.test.step('GET /api/public/dashboard?collectionId returns 200', async () => {
|
|
64
64
|
const response = await request.get(`${baseUrl}/api/public/dashboard?collectionId=${collectionIdValue}`, { headers: { Authorization: optimizeBearerToken } });
|
|
65
65
|
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
66
66
|
const body = await response.json();
|
|
@@ -69,19 +69,27 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
69
69
|
const dashboard = body[0];
|
|
70
70
|
(0, test_1.expect)(dashboard).toHaveProperty('id');
|
|
71
71
|
});
|
|
72
|
-
|
|
72
|
+
});
|
|
73
|
+
(0, _8_9_1.test)('Get dashboards without token returns 401', async ({ request }) => {
|
|
74
|
+
await _8_9_1.test.step('GET /api/public/dashboard without token (401)', async () => {
|
|
73
75
|
const response = await request.get(`${baseUrl}/api/public/dashboard?collectionId=${collectionIdValue}`);
|
|
74
76
|
(0, test_1.expect)(response.status()).toBe(401);
|
|
75
77
|
});
|
|
76
|
-
|
|
78
|
+
});
|
|
79
|
+
(0, _8_9_1.test)('Get dashboards with invalid token returns 401', async ({ request }) => {
|
|
80
|
+
await _8_9_1.test.step('GET /api/public/dashboard with invalid token (401)', async () => {
|
|
77
81
|
const response = await request.get(`${baseUrl}/api/public/dashboard?collectionId=${collectionIdValue}`, { headers: { Authorization: 'Bearer invalid_token' } });
|
|
78
82
|
(0, test_1.expect)(response.status()).toBe(401);
|
|
79
83
|
});
|
|
84
|
+
});
|
|
85
|
+
(0, _8_9_1.test)('GET /api/public/dashboard/force-internal-error returns 500', async ({ request, }) => {
|
|
80
86
|
await _8_9_1.test.step('Force internal server error (500)', async () => {
|
|
81
87
|
const response = await request.get(`${baseUrl}/api/public/dashboard/force-internal-error`, { headers: { Authorization: optimizeBearerToken } });
|
|
82
88
|
(0, test_1.expect)(response.status()).toBe(500);
|
|
83
89
|
});
|
|
84
|
-
|
|
90
|
+
});
|
|
91
|
+
(0, _8_9_1.test)('Export dashboard definitions successfully returns 200', async ({ request, }) => {
|
|
92
|
+
await _8_9_1.test.step('POST export dashboard definitions (200)', async () => {
|
|
85
93
|
const response = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
86
94
|
headers: {
|
|
87
95
|
Authorization: optimizeBearerToken,
|
|
@@ -93,14 +101,18 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
93
101
|
const body = await response.json();
|
|
94
102
|
(0, test_1.expect)(Array.isArray(body)).toBeTruthy();
|
|
95
103
|
});
|
|
96
|
-
|
|
104
|
+
});
|
|
105
|
+
(0, _8_9_1.test)('Export dashboards without token returns 401', async ({ request }) => {
|
|
106
|
+
await _8_9_1.test.step('POST export dashboards without token (401)', async () => {
|
|
97
107
|
const response = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
98
108
|
headers: { 'Content-Type': 'application/json' },
|
|
99
109
|
data: [dashboardIdValue],
|
|
100
110
|
});
|
|
101
111
|
(0, test_1.expect)(response.status()).toBe(401);
|
|
102
112
|
});
|
|
103
|
-
|
|
113
|
+
});
|
|
114
|
+
(0, _8_9_1.test)('Export dashboards with invalid token returns 401', async ({ request, }) => {
|
|
115
|
+
await _8_9_1.test.step('POST export dashboards with invalid token (401)', async () => {
|
|
104
116
|
const response = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
105
117
|
headers: {
|
|
106
118
|
Authorization: 'Bearer invalid_token',
|
|
@@ -110,7 +122,9 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
110
122
|
});
|
|
111
123
|
(0, test_1.expect)(response.status()).toBe(401);
|
|
112
124
|
});
|
|
113
|
-
|
|
125
|
+
});
|
|
126
|
+
(0, _8_9_1.test)('Export dashboard with invalid body returns 400', async ({ request }) => {
|
|
127
|
+
await _8_9_1.test.step('POST export dashboard with invalid body (400)', async () => {
|
|
114
128
|
const response = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
115
129
|
headers: {
|
|
116
130
|
Authorization: optimizeBearerToken,
|
|
@@ -120,7 +134,9 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
120
134
|
});
|
|
121
135
|
(0, test_1.expect)(response.status()).toBe(400);
|
|
122
136
|
});
|
|
123
|
-
|
|
137
|
+
});
|
|
138
|
+
(0, _8_9_1.test)('Export non-existent dashboard returns 404', async ({ request }) => {
|
|
139
|
+
await _8_9_1.test.step('POST export non-existent dashboard (404)', async () => {
|
|
124
140
|
const fakeDashboardId = 'nonexistent-dashboard-id';
|
|
125
141
|
const response = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
126
142
|
headers: {
|
|
@@ -131,45 +147,53 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
131
147
|
});
|
|
132
148
|
(0, test_1.expect)([401, 404]).toContain(response.status());
|
|
133
149
|
});
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
data: [dashboardIdValue],
|
|
141
|
-
});
|
|
142
|
-
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
150
|
+
});
|
|
151
|
+
(0, _8_9_1.test)('Delete dashboard and verify it is no longer retrievable', async ({ request, }) => {
|
|
152
|
+
const dashboardToDeleteId = await (0, apiHelpers_1.createDashboard)(request, {
|
|
153
|
+
name: await (0, randomName_1.randomNameAgregator)('Dashboard To Delete'),
|
|
154
|
+
optimizeCookie,
|
|
155
|
+
collectionId: collectionIdValue,
|
|
143
156
|
});
|
|
144
157
|
await _8_9_1.test.step('Delete dashboard successfully (200)', async () => {
|
|
145
|
-
const response = await request.delete(`${baseUrl}/api/public/dashboard/${
|
|
158
|
+
const response = await request.delete(`${baseUrl}/api/public/dashboard/${dashboardToDeleteId}`, { headers: { Authorization: optimizeBearerToken } });
|
|
146
159
|
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
147
160
|
});
|
|
148
|
-
await _8_9_1.test.step('Verify dashboard not found after deletion
|
|
149
|
-
|
|
150
|
-
|
|
161
|
+
await _8_9_1.test.step('Verify dashboard not found after deletion', async () => {
|
|
162
|
+
await (0, test_1.expect)(async () => {
|
|
163
|
+
const response = await request.get(`${baseUrl}/api/public/dashboard/${dashboardToDeleteId}`, { headers: { Authorization: optimizeBearerToken } });
|
|
164
|
+
(0, test_1.expect)([404, 410, 500]).toContain(response.status());
|
|
165
|
+
}).toPass({ ...constants_1.defaultAssertionOptions, timeout: 60000 });
|
|
151
166
|
});
|
|
152
|
-
|
|
167
|
+
});
|
|
168
|
+
(0, _8_9_1.test)('Delete dashboard with invalid token returns 401', async ({ request }) => {
|
|
169
|
+
await _8_9_1.test.step('DELETE /api/public/dashboard with invalid token (401)', async () => {
|
|
153
170
|
const response = await request.delete(`${baseUrl}/api/public/dashboard/${dashboardIdValue}`, { headers: { Authorization: 'Bearer invalid_token' } });
|
|
154
171
|
(0, test_1.expect)(response.status()).toBe(401);
|
|
155
172
|
});
|
|
156
|
-
|
|
173
|
+
});
|
|
174
|
+
(0, _8_9_1.test)('Delete non-existent dashboard returns 404', async ({ request }) => {
|
|
175
|
+
await _8_9_1.test.step('DELETE non-existent dashboard (404)', async () => {
|
|
157
176
|
const fakeDashboardId = 'nonexistent-dashboard-id';
|
|
158
177
|
const response = await request.delete(`${baseUrl}/api/public/dashboard/${fakeDashboardId}`, { headers: { Authorization: optimizeBearerToken } });
|
|
159
178
|
(0, test_1.expect)(response.status()).toBe(404);
|
|
160
179
|
});
|
|
161
180
|
});
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
await _8_9_1.test.step('Get reports successfully (200)', async () => {
|
|
181
|
+
(0, _8_9_1.test)('Get report IDs returns 200 with id array', async ({ request }) => {
|
|
182
|
+
await _8_9_1.test.step('GET /api/public/report?collectionId returns 200', async () => {
|
|
165
183
|
const response = await request.get(`${baseUrl}/api/public/report?collectionId=${collectionIdValue}`, { headers: { Authorization: optimizeBearerToken } });
|
|
166
184
|
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
185
|
+
const body = await response.json();
|
|
186
|
+
(0, test_1.expect)(Array.isArray(body)).toBeTruthy();
|
|
167
187
|
});
|
|
168
|
-
|
|
188
|
+
});
|
|
189
|
+
(0, _8_9_1.test)('Get reports with invalid token returns 401', async ({ request }) => {
|
|
190
|
+
await _8_9_1.test.step('GET /api/public/report with invalid token (401)', async () => {
|
|
169
191
|
const response = await request.get(`${baseUrl}/api/public/report?collectionId=${collectionIdValue}`, { headers: { Authorization: 'Bearer invalid_token' } });
|
|
170
192
|
(0, test_1.expect)(response.status()).toBe(401);
|
|
171
193
|
});
|
|
172
|
-
|
|
194
|
+
});
|
|
195
|
+
(0, _8_9_1.test)('Export reports successfully returns 200 with full payload', async ({ request, }) => {
|
|
196
|
+
await _8_9_1.test.step('POST export report definitions (200)', async () => {
|
|
173
197
|
const response = await request.post(`${baseUrl}/api/public/export/report/definition/json`, {
|
|
174
198
|
headers: {
|
|
175
199
|
Authorization: optimizeBearerToken,
|
|
@@ -186,7 +210,9 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
186
210
|
(0, test_1.expect)(body[0]).toHaveProperty('name');
|
|
187
211
|
(0, test_1.expect)(body[0]).toHaveProperty('collectionId');
|
|
188
212
|
});
|
|
189
|
-
|
|
213
|
+
});
|
|
214
|
+
(0, _8_9_1.test)('Export reports with invalid token returns 401', async ({ request }) => {
|
|
215
|
+
await _8_9_1.test.step('POST export reports with invalid token (401)', async () => {
|
|
190
216
|
const response = await request.post(`${baseUrl}/api/public/export/report/definition/json`, {
|
|
191
217
|
headers: {
|
|
192
218
|
Authorization: 'Bearer invalid_token',
|
|
@@ -196,7 +222,9 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
196
222
|
});
|
|
197
223
|
(0, test_1.expect)(response.status()).toBe(401);
|
|
198
224
|
});
|
|
199
|
-
|
|
225
|
+
});
|
|
226
|
+
(0, _8_9_1.test)('Export non-existent report returns 404', async ({ request }) => {
|
|
227
|
+
await _8_9_1.test.step('POST export non-existent report (404)', async () => {
|
|
200
228
|
const invalidReportId = '11111111-1111-1111-1111-111111111111';
|
|
201
229
|
const response = await request.post(`${baseUrl}/api/public/export/report/definition/json`, {
|
|
202
230
|
headers: {
|
|
@@ -207,21 +235,32 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
207
235
|
});
|
|
208
236
|
await (0, apiHelpers_1.assertResponseStatus)(response, 404);
|
|
209
237
|
});
|
|
238
|
+
});
|
|
239
|
+
(0, _8_9_1.test)('Delete report and verify it is no longer retrievable', async ({ request, }) => {
|
|
240
|
+
const reportToDeleteId = await (0, apiHelpers_1.createSingleProcessReport)(request, {
|
|
241
|
+
optimizeCookie,
|
|
242
|
+
collectionId: collectionIdValue,
|
|
243
|
+
name: await (0, randomName_1.randomNameAgregator)('Report To Delete'),
|
|
244
|
+
definitions: [
|
|
245
|
+
{
|
|
246
|
+
key: 'aProcess',
|
|
247
|
+
filter: [],
|
|
248
|
+
groupBy: { type: 'flowNodes', value: null },
|
|
249
|
+
distributedBy: { type: 'none', value: null },
|
|
250
|
+
view: { entity: 'flowNode', properties: ['duration'] },
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
});
|
|
210
254
|
await _8_9_1.test.step('Delete report successfully (200)', async () => {
|
|
211
|
-
const response = await request.delete(`${baseUrl}/api/public/report/${
|
|
255
|
+
const response = await request.delete(`${baseUrl}/api/public/report/${reportToDeleteId}`, { headers: { Authorization: optimizeBearerToken } });
|
|
212
256
|
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
213
257
|
});
|
|
214
|
-
await _8_9_1.test.step('Verify deleted report
|
|
215
|
-
const response = await request.get(`${baseUrl}/api/public/report/${
|
|
258
|
+
await _8_9_1.test.step('Verify deleted report is no longer retrievable (404 or 500)', async () => {
|
|
259
|
+
const response = await request.get(`${baseUrl}/api/public/report/${reportToDeleteId}`, { headers: { Authorization: optimizeBearerToken } });
|
|
216
260
|
(0, test_1.expect)([404, 500]).toContain(response.status());
|
|
217
261
|
});
|
|
218
|
-
await _8_9_1.test.step('Attempt delete report with invalid token (401)', async () => {
|
|
219
|
-
const response = await request.delete(`${baseUrl}/api/public/report/${reportId}`, { headers: { Authorization: 'Bearer invalid_token' } });
|
|
220
|
-
(0, test_1.expect)(response.status()).toBe(401);
|
|
221
|
-
});
|
|
222
262
|
});
|
|
223
|
-
|
|
224
|
-
_8_9_1.test.skip('Import entities successfully (200)', async ({ request }) => {
|
|
263
|
+
(0, _8_9_1.test)('Import entities successfully (200)', async ({ request }) => {
|
|
225
264
|
const exportResponse = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
226
265
|
headers: {
|
|
227
266
|
Authorization: optimizeBearerToken,
|
|
@@ -230,40 +269,55 @@ _8_9_1.test.describe('API optimize SaaS Tests', () => {
|
|
|
230
269
|
data: [dashboardIdValue],
|
|
231
270
|
});
|
|
232
271
|
await (0, apiHelpers_1.assertResponseStatus)(exportResponse, 200);
|
|
233
|
-
|
|
272
|
+
const entitiesToImport = await exportResponse.json();
|
|
234
273
|
const response = await request.post(`${baseUrl}/api/public/import?collectionId=${collectionIdValue}`, {
|
|
235
274
|
headers: {
|
|
236
275
|
Authorization: optimizeBearerToken,
|
|
237
276
|
'Content-Type': 'application/json',
|
|
238
277
|
},
|
|
239
|
-
data:
|
|
278
|
+
data: entitiesToImport,
|
|
240
279
|
});
|
|
241
280
|
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
242
281
|
});
|
|
243
|
-
|
|
244
|
-
|
|
282
|
+
(0, _8_9_1.test)('Import without token or invalid token returns 401', async ({ request, }) => {
|
|
283
|
+
const exportResponse = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
284
|
+
headers: {
|
|
285
|
+
Authorization: optimizeBearerToken,
|
|
286
|
+
'Content-Type': 'application/json',
|
|
287
|
+
},
|
|
288
|
+
data: [dashboardIdValue],
|
|
289
|
+
});
|
|
290
|
+
await (0, apiHelpers_1.assertResponseStatus)(exportResponse, 200);
|
|
291
|
+
const entitiesToImport = await exportResponse.json();
|
|
245
292
|
const response = await request.post(`${baseUrl}/api/public/import?collectionId=${collectionIdValue}`, {
|
|
246
293
|
headers: {
|
|
247
294
|
Authorization: 'Bearer invalid_token',
|
|
248
295
|
'Content-Type': 'application/json',
|
|
249
296
|
},
|
|
250
|
-
data:
|
|
297
|
+
data: entitiesToImport,
|
|
251
298
|
});
|
|
252
|
-
|
|
253
|
-
(0, test_1.expect)(status).toBe(401);
|
|
299
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
254
300
|
});
|
|
255
301
|
// Skipped due to bug 40497: https://github.com/camunda/camunda/issues/40497
|
|
256
302
|
_8_9_1.test.skip('Import to non-existent collection (404)', async ({ request }) => {
|
|
303
|
+
const exportResponse = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
304
|
+
headers: {
|
|
305
|
+
Authorization: optimizeBearerToken,
|
|
306
|
+
'Content-Type': 'application/json',
|
|
307
|
+
},
|
|
308
|
+
data: [dashboardIdValue],
|
|
309
|
+
});
|
|
310
|
+
await (0, apiHelpers_1.assertResponseStatus)(exportResponse, 200);
|
|
311
|
+
const entitiesToImport = await exportResponse.json();
|
|
257
312
|
const fakeCollectionId = 'nonexistent-collection-id';
|
|
258
313
|
const response = await request.post(`${baseUrl}/api/public/import?collectionId=${fakeCollectionId}`, {
|
|
259
314
|
headers: {
|
|
260
315
|
Authorization: optimizeBearerToken,
|
|
261
316
|
'Content-Type': 'application/json',
|
|
262
317
|
},
|
|
263
|
-
data:
|
|
318
|
+
data: entitiesToImport,
|
|
264
319
|
});
|
|
265
|
-
|
|
266
|
-
(0, test_1.expect)(status).toBe(404);
|
|
320
|
+
(0, test_1.expect)(response.status()).toBe(404);
|
|
267
321
|
});
|
|
268
322
|
});
|
|
269
323
|
_8_9_1.test.describe('API optimize SaaS Tests - Conditional Events', () => {
|
|
@@ -309,6 +363,11 @@ _8_9_1.test.describe('API optimize SaaS Tests - Conditional Events', () => {
|
|
|
309
363
|
});
|
|
310
364
|
baseUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
311
365
|
});
|
|
366
|
+
_8_9_1.test.afterAll(async ({ request }) => {
|
|
367
|
+
if (conditionalEventsCollectionId) {
|
|
368
|
+
await request.delete(`${baseUrl}/api/public/collection/${conditionalEventsCollectionId}`, { headers: { Authorization: optimizeBearerToken } });
|
|
369
|
+
}
|
|
370
|
+
});
|
|
312
371
|
(0, _8_9_1.test)('CE-OPT-09: Creating a Process Report for Conditional Events via API returns HTTP 200', async ({ request, }) => {
|
|
313
372
|
await _8_9_1.test.step('Create a process report for conditional-events-auto-process (200)', async () => {
|
|
314
373
|
const response = await request.post(`${baseUrl}/api/report/process/single`, {
|
|
@@ -435,3 +494,590 @@ _8_9_1.test.describe('API optimize SaaS Tests - Conditional Events', () => {
|
|
|
435
494
|
});
|
|
436
495
|
});
|
|
437
496
|
});
|
|
497
|
+
_8_9_1.test.describe('API optimize SaaS Tests - Health Readiness', () => {
|
|
498
|
+
let baseUrl;
|
|
499
|
+
_8_9_1.test.beforeAll(async () => {
|
|
500
|
+
baseUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
501
|
+
});
|
|
502
|
+
(0, _8_9_1.test)('Health readiness returns 200 when Optimize is ready', async ({ request, }) => {
|
|
503
|
+
await _8_9_1.test.step('GET /api/readyz returns 200 (no auth required)', async () => {
|
|
504
|
+
const response = await request.get(`${baseUrl}/api/readyz`);
|
|
505
|
+
(0, test_1.expect)(response.status()).toBe(200);
|
|
506
|
+
});
|
|
507
|
+
});
|
|
508
|
+
(0, _8_9_1.test)('Health readiness rejects requests that include an Authorization header', async ({ request, }) => {
|
|
509
|
+
await _8_9_1.test.step('GET /api/readyz with Authorization header should be rejected', async () => {
|
|
510
|
+
const token = await (0, apiHelpers_1.authSaasAPI)(process.env.OPTIMIZE_API_TOKEN_AUDIENCE);
|
|
511
|
+
const response = await request.get(`${baseUrl}/api/readyz`, {
|
|
512
|
+
headers: { Authorization: token },
|
|
513
|
+
});
|
|
514
|
+
(0, test_1.expect)([400, 401, 403]).toContain(response.status());
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
});
|
|
518
|
+
_8_9_1.test.describe('API optimize SaaS Tests - Sharing', () => {
|
|
519
|
+
let optimizeBearerToken;
|
|
520
|
+
let baseUrl;
|
|
521
|
+
_8_9_1.test.beforeAll(async () => {
|
|
522
|
+
optimizeBearerToken = await (0, apiHelpers_1.authSaasAPI)(process.env.OPTIMIZE_API_TOKEN_AUDIENCE);
|
|
523
|
+
baseUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
524
|
+
});
|
|
525
|
+
(0, _8_9_1.test)('Enable sharing with valid token returns 200 or 204', async ({ request, }) => {
|
|
526
|
+
await _8_9_1.test.step('POST /api/public/share/enable with valid token (200 or 204)', async () => {
|
|
527
|
+
const response = await request.post(`${baseUrl}/api/public/share/enable`, { headers: { Authorization: optimizeBearerToken } });
|
|
528
|
+
(0, test_1.expect)([200, 204]).toContain(response.status());
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
(0, _8_9_1.test)('Enable sharing without token returns 401', async ({ request }) => {
|
|
532
|
+
await _8_9_1.test.step('POST /api/public/share/enable without token (401)', async () => {
|
|
533
|
+
const response = await request.post(`${baseUrl}/api/public/share/enable`);
|
|
534
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
(0, _8_9_1.test)('Enable sharing with invalid token returns 401', async ({ request }) => {
|
|
538
|
+
await _8_9_1.test.step('POST /api/public/share/enable with invalid token (401)', async () => {
|
|
539
|
+
const response = await request.post(`${baseUrl}/api/public/share/enable`, { headers: { Authorization: 'Bearer invalid_token' } });
|
|
540
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
(0, _8_9_1.test)('Disable sharing with valid token returns 200 or 204', async ({ request, }) => {
|
|
544
|
+
await _8_9_1.test.step('POST /api/public/share/disable with valid token (200 or 204)', async () => {
|
|
545
|
+
const response = await request.post(`${baseUrl}/api/public/share/disable`, { headers: { Authorization: optimizeBearerToken } });
|
|
546
|
+
(0, test_1.expect)([200, 204]).toContain(response.status());
|
|
547
|
+
});
|
|
548
|
+
});
|
|
549
|
+
(0, _8_9_1.test)('Disable sharing without token returns 401', async ({ request }) => {
|
|
550
|
+
await _8_9_1.test.step('POST /api/public/share/disable without token (401)', async () => {
|
|
551
|
+
const response = await request.post(`${baseUrl}/api/public/share/disable`);
|
|
552
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
(0, _8_9_1.test)('Disable sharing with invalid token returns 401', async ({ request }) => {
|
|
556
|
+
await _8_9_1.test.step('POST /api/public/share/disable with invalid token (401)', async () => {
|
|
557
|
+
const response = await request.post(`${baseUrl}/api/public/share/disable`, { headers: { Authorization: 'Bearer invalid_token' } });
|
|
558
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
559
|
+
});
|
|
560
|
+
});
|
|
561
|
+
(0, _8_9_1.test)('Sharing toggle cycle: enable then disable is idempotent', async ({ request, }) => {
|
|
562
|
+
await _8_9_1.test.step('Enable sharing (200 or 204)', async () => {
|
|
563
|
+
const response = await request.post(`${baseUrl}/api/public/share/enable`, { headers: { Authorization: optimizeBearerToken } });
|
|
564
|
+
(0, test_1.expect)([200, 204]).toContain(response.status());
|
|
565
|
+
});
|
|
566
|
+
await _8_9_1.test.step('Disable sharing (200 or 204)', async () => {
|
|
567
|
+
const response = await request.post(`${baseUrl}/api/public/share/disable`, { headers: { Authorization: optimizeBearerToken } });
|
|
568
|
+
(0, test_1.expect)([200, 204]).toContain(response.status());
|
|
569
|
+
});
|
|
570
|
+
await _8_9_1.test.step('Re-enable sharing returns 200 or 204 (idempotent)', async () => {
|
|
571
|
+
const response = await request.post(`${baseUrl}/api/public/share/enable`, { headers: { Authorization: optimizeBearerToken } });
|
|
572
|
+
(0, test_1.expect)([200, 204]).toContain(response.status());
|
|
573
|
+
});
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
_8_9_1.test.describe('API optimize SaaS Tests - Dashboard and Report GET edge cases', () => {
|
|
577
|
+
let optimizeBearerToken;
|
|
578
|
+
let optimizeCookie;
|
|
579
|
+
let collectionId;
|
|
580
|
+
let baseUrl;
|
|
581
|
+
_8_9_1.test.beforeAll(async ({ browser, request }) => {
|
|
582
|
+
const page = await browser.newPage();
|
|
583
|
+
optimizeCookie = await (0, apiHelpers_1.getOptimizeCoockie)(page);
|
|
584
|
+
await page.close();
|
|
585
|
+
optimizeBearerToken = await (0, apiHelpers_1.authSaasAPI)(process.env.OPTIMIZE_API_TOKEN_AUDIENCE);
|
|
586
|
+
baseUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
587
|
+
collectionId = await (0, apiHelpers_1.createCollection)(request, {
|
|
588
|
+
name: await (0, randomName_1.randomNameAgregator)('GET Edge Cases Collection'),
|
|
589
|
+
optimizeCookie,
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
_8_9_1.test.afterAll(async ({ request }) => {
|
|
593
|
+
if (collectionId) {
|
|
594
|
+
await request.delete(`${baseUrl}/api/public/collection/${collectionId}`, {
|
|
595
|
+
headers: { Authorization: optimizeBearerToken },
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
});
|
|
599
|
+
(0, _8_9_1.test)('GET dashboards with valid token and collectionId returns 200 with id array', async ({ request, }) => {
|
|
600
|
+
await _8_9_1.test.step('GET /api/public/dashboard?collectionId returns 200', async () => {
|
|
601
|
+
const response = await request.get(`${baseUrl}/api/public/dashboard?collectionId=${collectionId}`, { headers: { Authorization: optimizeBearerToken } });
|
|
602
|
+
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
603
|
+
const body = await response.json();
|
|
604
|
+
(0, test_1.expect)(Array.isArray(body)).toBeTruthy();
|
|
605
|
+
});
|
|
606
|
+
});
|
|
607
|
+
(0, _8_9_1.test)('GET dashboards without collectionId param returns 400 or 500', async ({ request, }) => {
|
|
608
|
+
await _8_9_1.test.step('GET /api/public/dashboard without collectionId', async () => {
|
|
609
|
+
const response = await request.get(`${baseUrl}/api/public/dashboard`, {
|
|
610
|
+
headers: { Authorization: optimizeBearerToken },
|
|
611
|
+
});
|
|
612
|
+
(0, test_1.expect)([400, 500]).toContain(response.status());
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
(0, _8_9_1.test)('GET reports with valid token and collectionId returns 200 with id array', async ({ request, }) => {
|
|
616
|
+
await _8_9_1.test.step('GET /api/public/report?collectionId returns 200', async () => {
|
|
617
|
+
const response = await request.get(`${baseUrl}/api/public/report?collectionId=${collectionId}`, { headers: { Authorization: optimizeBearerToken } });
|
|
618
|
+
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
619
|
+
const body = await response.json();
|
|
620
|
+
(0, test_1.expect)(Array.isArray(body)).toBeTruthy();
|
|
621
|
+
});
|
|
622
|
+
});
|
|
623
|
+
(0, _8_9_1.test)('GET reports without collectionId param returns 400 or 500', async ({ request, }) => {
|
|
624
|
+
await _8_9_1.test.step('GET /api/public/report without collectionId', async () => {
|
|
625
|
+
const response = await request.get(`${baseUrl}/api/public/report`, {
|
|
626
|
+
headers: { Authorization: optimizeBearerToken },
|
|
627
|
+
});
|
|
628
|
+
(0, test_1.expect)([400, 500]).toContain(response.status());
|
|
629
|
+
});
|
|
630
|
+
});
|
|
631
|
+
});
|
|
632
|
+
_8_9_1.test.describe('API optimize SaaS Tests - Export edge cases', () => {
|
|
633
|
+
let optimizeBearerToken;
|
|
634
|
+
let optimizeCookie;
|
|
635
|
+
let collectionId;
|
|
636
|
+
let dashboardId1;
|
|
637
|
+
let dashboardId2;
|
|
638
|
+
let reportId1;
|
|
639
|
+
let reportId2;
|
|
640
|
+
let baseUrl;
|
|
641
|
+
_8_9_1.test.beforeAll(async ({ browser, request }) => {
|
|
642
|
+
const page = await browser.newPage();
|
|
643
|
+
optimizeCookie = await (0, apiHelpers_1.getOptimizeCoockie)(page);
|
|
644
|
+
await page.close();
|
|
645
|
+
optimizeBearerToken = await (0, apiHelpers_1.authSaasAPI)(process.env.OPTIMIZE_API_TOKEN_AUDIENCE);
|
|
646
|
+
baseUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
647
|
+
collectionId = await (0, apiHelpers_1.createCollection)(request, {
|
|
648
|
+
name: await (0, randomName_1.randomNameAgregator)('Export Edge Cases Collection'),
|
|
649
|
+
optimizeCookie,
|
|
650
|
+
});
|
|
651
|
+
dashboardId1 = await (0, apiHelpers_1.createDashboard)(request, {
|
|
652
|
+
name: await (0, randomName_1.randomNameAgregator)('Export Dashboard 1'),
|
|
653
|
+
optimizeCookie,
|
|
654
|
+
collectionId,
|
|
655
|
+
});
|
|
656
|
+
dashboardId2 = await (0, apiHelpers_1.createDashboard)(request, {
|
|
657
|
+
name: await (0, randomName_1.randomNameAgregator)('Export Dashboard 2'),
|
|
658
|
+
optimizeCookie,
|
|
659
|
+
collectionId,
|
|
660
|
+
});
|
|
661
|
+
reportId1 = await (0, apiHelpers_1.createSingleProcessReport)(request, {
|
|
662
|
+
optimizeCookie,
|
|
663
|
+
collectionId,
|
|
664
|
+
name: await (0, randomName_1.randomNameAgregator)('Export Report 1'),
|
|
665
|
+
definitions: [
|
|
666
|
+
{
|
|
667
|
+
key: 'aProcess',
|
|
668
|
+
filter: [],
|
|
669
|
+
groupBy: { type: 'none', value: null },
|
|
670
|
+
distributedBy: { type: 'none', value: null },
|
|
671
|
+
view: { entity: 'processInstance', properties: ['frequency'] },
|
|
672
|
+
},
|
|
673
|
+
],
|
|
674
|
+
});
|
|
675
|
+
reportId2 = await (0, apiHelpers_1.createSingleProcessReport)(request, {
|
|
676
|
+
optimizeCookie,
|
|
677
|
+
collectionId,
|
|
678
|
+
name: await (0, randomName_1.randomNameAgregator)('Export Report 2'),
|
|
679
|
+
definitions: [
|
|
680
|
+
{
|
|
681
|
+
key: 'aProcess',
|
|
682
|
+
filter: [],
|
|
683
|
+
groupBy: { type: 'none', value: null },
|
|
684
|
+
distributedBy: { type: 'none', value: null },
|
|
685
|
+
view: { entity: 'processInstance', properties: ['frequency'] },
|
|
686
|
+
},
|
|
687
|
+
],
|
|
688
|
+
});
|
|
689
|
+
});
|
|
690
|
+
_8_9_1.test.afterAll(async ({ request }) => {
|
|
691
|
+
if (collectionId) {
|
|
692
|
+
await request.delete(`${baseUrl}/api/public/collection/${collectionId}`, {
|
|
693
|
+
headers: { Authorization: optimizeBearerToken },
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
(0, _8_9_1.test)('Export multiple dashboards in a single call returns 200 with all definitions', async ({ request, }) => {
|
|
698
|
+
await _8_9_1.test.step('POST export with two dashboard IDs returns array of 2', async () => {
|
|
699
|
+
const response = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
700
|
+
headers: {
|
|
701
|
+
Authorization: optimizeBearerToken,
|
|
702
|
+
'Content-Type': 'application/json',
|
|
703
|
+
},
|
|
704
|
+
data: [dashboardId1, dashboardId2],
|
|
705
|
+
});
|
|
706
|
+
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
707
|
+
const body = await response.json();
|
|
708
|
+
(0, test_1.expect)(Array.isArray(body)).toBeTruthy();
|
|
709
|
+
(0, test_1.expect)(body.length).toBeGreaterThanOrEqual(2);
|
|
710
|
+
});
|
|
711
|
+
});
|
|
712
|
+
(0, _8_9_1.test)('Export multiple reports in a single call returns 200 with all definitions', async ({ request, }) => {
|
|
713
|
+
await _8_9_1.test.step('POST export with two report IDs returns array of 2', async () => {
|
|
714
|
+
const response = await request.post(`${baseUrl}/api/public/export/report/definition/json`, {
|
|
715
|
+
headers: {
|
|
716
|
+
Authorization: optimizeBearerToken,
|
|
717
|
+
'Content-Type': 'application/json',
|
|
718
|
+
},
|
|
719
|
+
data: [reportId1, reportId2],
|
|
720
|
+
});
|
|
721
|
+
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
722
|
+
const body = await response.json();
|
|
723
|
+
(0, test_1.expect)(Array.isArray(body)).toBeTruthy();
|
|
724
|
+
(0, test_1.expect)(body.length).toBeGreaterThanOrEqual(2);
|
|
725
|
+
});
|
|
726
|
+
});
|
|
727
|
+
(0, _8_9_1.test)('Export reports with empty array body returns 200 with empty array', async ({ request, }) => {
|
|
728
|
+
await _8_9_1.test.step('POST export/report with empty array body returns 200 []', async () => {
|
|
729
|
+
const response = await request.post(`${baseUrl}/api/public/export/report/definition/json`, {
|
|
730
|
+
headers: {
|
|
731
|
+
Authorization: optimizeBearerToken,
|
|
732
|
+
'Content-Type': 'application/json',
|
|
733
|
+
},
|
|
734
|
+
data: [],
|
|
735
|
+
});
|
|
736
|
+
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
737
|
+
const body = await response.json();
|
|
738
|
+
(0, test_1.expect)(Array.isArray(body)).toBeTruthy();
|
|
739
|
+
(0, test_1.expect)(body.length).toBe(0);
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
(0, _8_9_1.test)('Export dashboards with empty array body returns 200 with empty array', async ({ request, }) => {
|
|
743
|
+
await _8_9_1.test.step('POST export/dashboard with empty array body returns 200 []', async () => {
|
|
744
|
+
const response = await request.post(`${baseUrl}/api/public/export/dashboard/definition/json`, {
|
|
745
|
+
headers: {
|
|
746
|
+
Authorization: optimizeBearerToken,
|
|
747
|
+
'Content-Type': 'application/json',
|
|
748
|
+
},
|
|
749
|
+
data: [],
|
|
750
|
+
});
|
|
751
|
+
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
752
|
+
const body = await response.json();
|
|
753
|
+
(0, test_1.expect)(Array.isArray(body)).toBeTruthy();
|
|
754
|
+
(0, test_1.expect)(body.length).toBe(0);
|
|
755
|
+
});
|
|
756
|
+
});
|
|
757
|
+
});
|
|
758
|
+
_8_9_1.test.describe('API optimize SaaS Tests - Auth edge cases', () => {
|
|
759
|
+
let baseUrl;
|
|
760
|
+
_8_9_1.test.beforeAll(async () => {
|
|
761
|
+
baseUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
762
|
+
});
|
|
763
|
+
(0, _8_9_1.test)('Expired JWT token returns 401 on dashboard endpoint', async ({ request, }) => {
|
|
764
|
+
const expiredToken = 'Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.' +
|
|
765
|
+
'eyJzdWIiOiJ0ZXN0IiwiZXhwIjoxfQ.' +
|
|
766
|
+
'invalidsignature';
|
|
767
|
+
await _8_9_1.test.step('GET /api/public/dashboard with expired token returns 401', async () => {
|
|
768
|
+
const response = await request.get(`${baseUrl}/api/public/dashboard?collectionId=any`, { headers: { Authorization: expiredToken } });
|
|
769
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
770
|
+
});
|
|
771
|
+
});
|
|
772
|
+
(0, _8_9_1.test)('Malformed Bearer value (empty string) returns 401 on dashboard endpoint', async ({ request, }) => {
|
|
773
|
+
await _8_9_1.test.step('GET /api/public/dashboard with empty Bearer value returns 401', async () => {
|
|
774
|
+
const response = await request.get(`${baseUrl}/api/public/dashboard?collectionId=any`, { headers: { Authorization: 'Bearer ' } });
|
|
775
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
(0, _8_9_1.test)('Token with wrong audience returns 401 on dashboard endpoint', async ({ request, }) => {
|
|
779
|
+
await _8_9_1.test.step('Use a Zeebe-audience token against Optimize API and expect 401', async () => {
|
|
780
|
+
const wrongAudienceToken = await (0, apiHelpers_1.authSaasAPI)();
|
|
781
|
+
const response = await request.get(`${baseUrl}/api/public/dashboard?collectionId=any`, { headers: { Authorization: wrongAudienceToken } });
|
|
782
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
783
|
+
});
|
|
784
|
+
});
|
|
785
|
+
});
|
|
786
|
+
_8_9_1.test.describe('API V2 tests on SaaS cluster', () => {
|
|
787
|
+
let bearerToken;
|
|
788
|
+
const apiUrl = () => process.env.ZEEBE_API_URL;
|
|
789
|
+
_8_9_1.test.beforeAll(async () => {
|
|
790
|
+
bearerToken = await (0, apiHelpers_1.authSaasAPI)();
|
|
791
|
+
});
|
|
792
|
+
(0, _8_9_1.test)('GET /v2/topology returns 200', async ({ request }) => {
|
|
793
|
+
const response = await request.get(`${apiUrl()}/v2/topology`, {
|
|
794
|
+
headers: { Authorization: bearerToken, 'Content-Type': 'application/json' },
|
|
795
|
+
});
|
|
796
|
+
await (0, apiHelpers_1.assertResponseStatus)(response, 200);
|
|
797
|
+
});
|
|
798
|
+
(0, _8_9_1.test)('GET /v2/topology without token returns 401', async ({ request }) => {
|
|
799
|
+
const response = await request.get(`${apiUrl()}/v2/topology`, {
|
|
800
|
+
headers: { 'Content-Type': 'application/json' },
|
|
801
|
+
});
|
|
802
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
803
|
+
});
|
|
804
|
+
(0, _8_9_1.test)('POST /v2/process-definitions/search returns 200 with items array', async ({ request, }) => {
|
|
805
|
+
const response = await request.post(`${apiUrl()}/v2/process-definitions/search`, {
|
|
806
|
+
headers: {
|
|
807
|
+
Authorization: bearerToken,
|
|
808
|
+
'Content-Type': 'application/json',
|
|
809
|
+
},
|
|
810
|
+
data: { filter: {}, page: { limit: 10 } },
|
|
811
|
+
});
|
|
812
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
813
|
+
if (response.status() === 200) {
|
|
814
|
+
const body = await response.json();
|
|
815
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
816
|
+
(0, test_1.expect)(Array.isArray(body.items)).toBeTruthy();
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
(0, _8_9_1.test)('POST /v2/process-definitions/search without token returns 401', async ({ request, }) => {
|
|
820
|
+
const response = await request.post(`${apiUrl()}/v2/process-definitions/search`, {
|
|
821
|
+
headers: { 'Content-Type': 'application/json' },
|
|
822
|
+
data: { filter: {}, size: 10 },
|
|
823
|
+
});
|
|
824
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
825
|
+
});
|
|
826
|
+
(0, _8_9_1.test)('POST /v2/process-definitions/search with invalid token returns 401', async ({ request, }) => {
|
|
827
|
+
const response = await request.post(`${apiUrl()}/v2/process-definitions/search`, {
|
|
828
|
+
headers: {
|
|
829
|
+
Authorization: 'Bearer invalid_token',
|
|
830
|
+
'Content-Type': 'application/json',
|
|
831
|
+
},
|
|
832
|
+
data: { filter: {}, size: 10 },
|
|
833
|
+
});
|
|
834
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
835
|
+
});
|
|
836
|
+
(0, _8_9_1.test)('POST /v2/process-definitions/search with size 1 returns pagination cursor', async ({ request, }) => {
|
|
837
|
+
const response = await request.post(`${apiUrl()}/v2/process-definitions/search`, {
|
|
838
|
+
headers: {
|
|
839
|
+
Authorization: bearerToken,
|
|
840
|
+
'Content-Type': 'application/json',
|
|
841
|
+
},
|
|
842
|
+
data: { filter: {}, page: { limit: 1 } },
|
|
843
|
+
});
|
|
844
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
845
|
+
if (response.status() === 200) {
|
|
846
|
+
const body = await response.json();
|
|
847
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
848
|
+
(0, test_1.expect)(body.items.length).toBeLessThanOrEqual(1);
|
|
849
|
+
if (body.page?.totalItems > 1) {
|
|
850
|
+
(0, test_1.expect)(body).toHaveProperty('page');
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
});
|
|
854
|
+
(0, _8_9_1.test)('POST /v2/process-instances/search returns 200 with items array', async ({ request, }) => {
|
|
855
|
+
const response = await request.post(`${apiUrl()}/v2/process-instances/search`, {
|
|
856
|
+
headers: {
|
|
857
|
+
Authorization: bearerToken,
|
|
858
|
+
'Content-Type': 'application/json',
|
|
859
|
+
},
|
|
860
|
+
data: { filter: {}, page: { limit: 10 } },
|
|
861
|
+
});
|
|
862
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
863
|
+
if (response.status() === 200) {
|
|
864
|
+
const body = await response.json();
|
|
865
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
866
|
+
(0, test_1.expect)(Array.isArray(body.items)).toBeTruthy();
|
|
867
|
+
}
|
|
868
|
+
});
|
|
869
|
+
(0, _8_9_1.test)('POST /v2/process-instances/search filtered by state ACTIVE returns 200', async ({ request, }) => {
|
|
870
|
+
const response = await request.post(`${apiUrl()}/v2/process-instances/search`, {
|
|
871
|
+
headers: {
|
|
872
|
+
Authorization: bearerToken,
|
|
873
|
+
'Content-Type': 'application/json',
|
|
874
|
+
},
|
|
875
|
+
data: { filter: { state: 'ACTIVE' }, page: { limit: 10 } },
|
|
876
|
+
});
|
|
877
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
878
|
+
if (response.status() === 200) {
|
|
879
|
+
const body = await response.json();
|
|
880
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
881
|
+
}
|
|
882
|
+
});
|
|
883
|
+
(0, _8_9_1.test)('POST /v2/process-instances/search without token returns 401', async ({ request, }) => {
|
|
884
|
+
const response = await request.post(`${apiUrl()}/v2/process-instances/search`, {
|
|
885
|
+
headers: { 'Content-Type': 'application/json' },
|
|
886
|
+
data: { filter: {}, size: 10 },
|
|
887
|
+
});
|
|
888
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
889
|
+
});
|
|
890
|
+
(0, _8_9_1.test)('POST /v2/process-instances/search with invalid token returns 401', async ({ request, }) => {
|
|
891
|
+
const response = await request.post(`${apiUrl()}/v2/process-instances/search`, {
|
|
892
|
+
headers: {
|
|
893
|
+
Authorization: 'Bearer invalid_token',
|
|
894
|
+
'Content-Type': 'application/json',
|
|
895
|
+
},
|
|
896
|
+
data: { filter: {}, size: 10 },
|
|
897
|
+
});
|
|
898
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
899
|
+
});
|
|
900
|
+
(0, _8_9_1.test)('POST /v2/user-tasks/search returns 200 with items array', async ({ request, }) => {
|
|
901
|
+
const response = await request.post(`${apiUrl()}/v2/user-tasks/search`, {
|
|
902
|
+
headers: { Authorization: bearerToken, 'Content-Type': 'application/json' },
|
|
903
|
+
data: { filter: {}, page: { limit: 10 } },
|
|
904
|
+
});
|
|
905
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
906
|
+
if (response.status() === 200) {
|
|
907
|
+
const body = await response.json();
|
|
908
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
909
|
+
(0, test_1.expect)(Array.isArray(body.items)).toBeTruthy();
|
|
910
|
+
}
|
|
911
|
+
});
|
|
912
|
+
(0, _8_9_1.test)('POST /v2/user-tasks/search without token returns 401', async ({ request, }) => {
|
|
913
|
+
const response = await request.post(`${apiUrl()}/v2/user-tasks/search`, {
|
|
914
|
+
headers: { 'Content-Type': 'application/json' },
|
|
915
|
+
data: { filter: {}, size: 10 },
|
|
916
|
+
});
|
|
917
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
918
|
+
});
|
|
919
|
+
(0, _8_9_1.test)('POST /v2/user-tasks/search with invalid token returns 401', async ({ request, }) => {
|
|
920
|
+
const response = await request.post(`${apiUrl()}/v2/user-tasks/search`, {
|
|
921
|
+
headers: {
|
|
922
|
+
Authorization: 'Bearer invalid_token',
|
|
923
|
+
'Content-Type': 'application/json',
|
|
924
|
+
},
|
|
925
|
+
data: { filter: {}, size: 10 },
|
|
926
|
+
});
|
|
927
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
928
|
+
});
|
|
929
|
+
(0, _8_9_1.test)('POST /v2/variables/search returns 200 with items array', async ({ request, }) => {
|
|
930
|
+
const response = await request.post(`${apiUrl()}/v2/variables/search`, {
|
|
931
|
+
headers: { Authorization: bearerToken, 'Content-Type': 'application/json' },
|
|
932
|
+
data: { filter: {}, page: { limit: 10 } },
|
|
933
|
+
});
|
|
934
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
935
|
+
if (response.status() === 200) {
|
|
936
|
+
const body = await response.json();
|
|
937
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
938
|
+
(0, test_1.expect)(Array.isArray(body.items)).toBeTruthy();
|
|
939
|
+
}
|
|
940
|
+
});
|
|
941
|
+
(0, _8_9_1.test)('POST /v2/variables/search without token returns 401', async ({ request, }) => {
|
|
942
|
+
const response = await request.post(`${apiUrl()}/v2/variables/search`, {
|
|
943
|
+
headers: { 'Content-Type': 'application/json' },
|
|
944
|
+
data: { filter: {}, size: 10 },
|
|
945
|
+
});
|
|
946
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
947
|
+
});
|
|
948
|
+
(0, _8_9_1.test)('POST /v2/variables/search with invalid token returns 401', async ({ request, }) => {
|
|
949
|
+
const response = await request.post(`${apiUrl()}/v2/variables/search`, {
|
|
950
|
+
headers: {
|
|
951
|
+
Authorization: 'Bearer invalid_token',
|
|
952
|
+
'Content-Type': 'application/json',
|
|
953
|
+
},
|
|
954
|
+
data: { filter: {}, size: 10 },
|
|
955
|
+
});
|
|
956
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
957
|
+
});
|
|
958
|
+
(0, _8_9_1.test)('POST /v2/incidents/search returns 200 with items array', async ({ request, }) => {
|
|
959
|
+
const response = await request.post(`${apiUrl()}/v2/incidents/search`, {
|
|
960
|
+
headers: { Authorization: bearerToken, 'Content-Type': 'application/json' },
|
|
961
|
+
data: { filter: {}, page: { limit: 10 } },
|
|
962
|
+
});
|
|
963
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
964
|
+
if (response.status() === 200) {
|
|
965
|
+
const body = await response.json();
|
|
966
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
967
|
+
(0, test_1.expect)(Array.isArray(body.items)).toBeTruthy();
|
|
968
|
+
}
|
|
969
|
+
});
|
|
970
|
+
(0, _8_9_1.test)('POST /v2/incidents/search without token returns 401', async ({ request, }) => {
|
|
971
|
+
const response = await request.post(`${apiUrl()}/v2/incidents/search`, {
|
|
972
|
+
headers: { 'Content-Type': 'application/json' },
|
|
973
|
+
data: { filter: {}, size: 10 },
|
|
974
|
+
});
|
|
975
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
976
|
+
});
|
|
977
|
+
(0, _8_9_1.test)('POST /v2/incidents/search with invalid token returns 401', async ({ request, }) => {
|
|
978
|
+
const response = await request.post(`${apiUrl()}/v2/incidents/search`, {
|
|
979
|
+
headers: {
|
|
980
|
+
Authorization: 'Bearer invalid_token',
|
|
981
|
+
'Content-Type': 'application/json',
|
|
982
|
+
},
|
|
983
|
+
data: { filter: {}, size: 10 },
|
|
984
|
+
});
|
|
985
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
986
|
+
});
|
|
987
|
+
(0, _8_9_1.test)('POST /v2/decision-definitions/search returns 200 with items array', async ({ request, }) => {
|
|
988
|
+
const response = await request.post(`${apiUrl()}/v2/decision-definitions/search`, {
|
|
989
|
+
headers: {
|
|
990
|
+
Authorization: bearerToken,
|
|
991
|
+
'Content-Type': 'application/json',
|
|
992
|
+
},
|
|
993
|
+
data: { filter: {}, page: { limit: 10 } },
|
|
994
|
+
});
|
|
995
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
996
|
+
if (response.status() === 200) {
|
|
997
|
+
const body = await response.json();
|
|
998
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
999
|
+
(0, test_1.expect)(Array.isArray(body.items)).toBeTruthy();
|
|
1000
|
+
}
|
|
1001
|
+
});
|
|
1002
|
+
(0, _8_9_1.test)('POST /v2/decision-definitions/search without token returns 401', async ({ request, }) => {
|
|
1003
|
+
const response = await request.post(`${apiUrl()}/v2/decision-definitions/search`, {
|
|
1004
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1005
|
+
data: { filter: {}, size: 10 },
|
|
1006
|
+
});
|
|
1007
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
1008
|
+
});
|
|
1009
|
+
(0, _8_9_1.test)('POST /v2/decision-definitions/search with invalid token returns 401', async ({ request, }) => {
|
|
1010
|
+
const response = await request.post(`${apiUrl()}/v2/decision-definitions/search`, {
|
|
1011
|
+
headers: {
|
|
1012
|
+
Authorization: 'Bearer invalid_token',
|
|
1013
|
+
'Content-Type': 'application/json',
|
|
1014
|
+
},
|
|
1015
|
+
data: { filter: {}, size: 10 },
|
|
1016
|
+
});
|
|
1017
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
1018
|
+
});
|
|
1019
|
+
(0, _8_9_1.test)('POST /v2/decision-instances/search returns 200 with items array', async ({ request, }) => {
|
|
1020
|
+
const response = await request.post(`${apiUrl()}/v2/decision-instances/search`, {
|
|
1021
|
+
headers: {
|
|
1022
|
+
Authorization: bearerToken,
|
|
1023
|
+
'Content-Type': 'application/json',
|
|
1024
|
+
},
|
|
1025
|
+
data: { filter: {}, page: { limit: 10 } },
|
|
1026
|
+
});
|
|
1027
|
+
(0, test_1.expect)([200, 400, 405]).toContain(response.status());
|
|
1028
|
+
if (response.status() === 200) {
|
|
1029
|
+
const body = await response.json();
|
|
1030
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
1031
|
+
(0, test_1.expect)(Array.isArray(body.items)).toBeTruthy();
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
(0, _8_9_1.test)('POST /v2/decision-instances/search without token returns 401', async ({ request, }) => {
|
|
1035
|
+
const response = await request.post(`${apiUrl()}/v2/decision-instances/search`, {
|
|
1036
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1037
|
+
data: { filter: {}, size: 10 },
|
|
1038
|
+
});
|
|
1039
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
1040
|
+
});
|
|
1041
|
+
(0, _8_9_1.test)('POST /v2/decision-instances/search with invalid token returns 401', async ({ request, }) => {
|
|
1042
|
+
const response = await request.post(`${apiUrl()}/v2/decision-instances/search`, {
|
|
1043
|
+
headers: {
|
|
1044
|
+
Authorization: 'Bearer invalid_token',
|
|
1045
|
+
'Content-Type': 'application/json',
|
|
1046
|
+
},
|
|
1047
|
+
data: { filter: {}, size: 10 },
|
|
1048
|
+
});
|
|
1049
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
1050
|
+
});
|
|
1051
|
+
(0, _8_9_1.test)('POST /v2/flownode-instances/search returns 200 with items array', async ({ request, }) => {
|
|
1052
|
+
const response = await request.post(`${apiUrl()}/v2/flownode-instances/search`, {
|
|
1053
|
+
headers: {
|
|
1054
|
+
Authorization: bearerToken,
|
|
1055
|
+
'Content-Type': 'application/json',
|
|
1056
|
+
},
|
|
1057
|
+
data: { filter: {}, page: { limit: 10 } },
|
|
1058
|
+
});
|
|
1059
|
+
(0, test_1.expect)([200, 404, 405]).toContain(response.status());
|
|
1060
|
+
if (response.status() === 200) {
|
|
1061
|
+
const body = await response.json();
|
|
1062
|
+
(0, test_1.expect)(body).toHaveProperty('items');
|
|
1063
|
+
(0, test_1.expect)(Array.isArray(body.items)).toBeTruthy();
|
|
1064
|
+
}
|
|
1065
|
+
});
|
|
1066
|
+
(0, _8_9_1.test)('POST /v2/flownode-instances/search without token returns 401', async ({ request, }) => {
|
|
1067
|
+
const response = await request.post(`${apiUrl()}/v2/flownode-instances/search`, {
|
|
1068
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1069
|
+
data: { filter: {}, size: 10 },
|
|
1070
|
+
});
|
|
1071
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
1072
|
+
});
|
|
1073
|
+
(0, _8_9_1.test)('POST /v2/flownode-instances/search with invalid token returns 401', async ({ request, }) => {
|
|
1074
|
+
const response = await request.post(`${apiUrl()}/v2/flownode-instances/search`, {
|
|
1075
|
+
headers: {
|
|
1076
|
+
Authorization: 'Bearer invalid_token',
|
|
1077
|
+
'Content-Type': 'application/json',
|
|
1078
|
+
},
|
|
1079
|
+
data: { filter: {}, size: 10 },
|
|
1080
|
+
});
|
|
1081
|
+
(0, test_1.expect)(response.status()).toBe(401);
|
|
1082
|
+
});
|
|
1083
|
+
});
|
package/dist/utils/apiHelpers.js
CHANGED
|
@@ -410,14 +410,48 @@ async function createStringClusterVariable(authToken, environment = 'saas', cust
|
|
|
410
410
|
}
|
|
411
411
|
exports.createStringClusterVariable = createStringClusterVariable;
|
|
412
412
|
async function getOptimizeCoockie(page) {
|
|
413
|
-
|
|
413
|
+
const optimizeUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
414
|
+
const maxLoginAttempts = 3;
|
|
415
|
+
// Auth0 can fail or rate-limit concurrent logins. Retry the whole flow if
|
|
416
|
+
// loginToApp throws (e.g. waitForURL times out after a bad Auth0 redirect).
|
|
417
|
+
for (let loginAttempt = 0; loginAttempt < maxLoginAttempts; loginAttempt++) {
|
|
418
|
+
try {
|
|
419
|
+
await page.goto('about:blank');
|
|
420
|
+
await page.context().clearCookies();
|
|
421
|
+
await (0, utils_1.loginToApp)(optimizeUrl, page);
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
catch (error) {
|
|
425
|
+
if (loginAttempt < maxLoginAttempts - 1) {
|
|
426
|
+
console.warn(`getOptimizeCoockie: login attempt ${loginAttempt + 1} failed, retrying after backoff...`, error);
|
|
427
|
+
await page.goto('about:blank');
|
|
428
|
+
await page.waitForTimeout(5000 * (loginAttempt + 1));
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
throw error;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
414
435
|
const context = page.context();
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
436
|
+
// Optimize sets its session cookies asynchronously after the Auth0 redirect.
|
|
437
|
+
// Poll storage state until both cookies are present (up to ~30 s).
|
|
438
|
+
let serviceTokenCookie;
|
|
439
|
+
let authTokenCookie;
|
|
440
|
+
for (let i = 0; i < 10; i++) {
|
|
441
|
+
const tempFile = path_1.default.join(os_1.default.tmpdir(), `.auth_optimize_${Date.now()}_${Math.random().toString(36).slice(2)}`);
|
|
442
|
+
await context.storageState({ path: tempFile });
|
|
443
|
+
const authData = JSON.parse(fs_1.default.readFileSync(tempFile, 'utf8'));
|
|
444
|
+
fs_1.default.unlinkSync(tempFile);
|
|
445
|
+
serviceTokenCookie = authData.cookies.find((cookie) => cookie.name === 'X-Optimize-Service-Token_0');
|
|
446
|
+
authTokenCookie = authData.cookies.find((cookie) => cookie.name === 'X-Optimize-Authorization_0');
|
|
447
|
+
if (serviceTokenCookie?.value && authTokenCookie?.value) {
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
if (i < 9) {
|
|
451
|
+
console.warn(`getOptimizeCoockie: cookies not ready yet (attempt ${i + 1}/10), retrying in 3 s...`);
|
|
452
|
+
await page.waitForTimeout(3000);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
421
455
|
const optimizeServiceToken = serviceTokenCookie?.value || '';
|
|
422
456
|
const optimizeAuthToken = authTokenCookie?.value || '';
|
|
423
457
|
const optimizeCookie = `X-Optimize-Service-Token_0=${optimizeServiceToken}; X-Optimize-Authorization_0=${optimizeAuthToken}`;
|
package/dist/utils/utils.js
CHANGED
|
@@ -12,9 +12,9 @@ async function loginToApp(appName, page) {
|
|
|
12
12
|
await (0, test_1.expect)(loginPage.usernameInput).toHaveValue(process.env.C8_USERNAME);
|
|
13
13
|
await (0, test_1.expect)(loginPage.loginMessage).toBeVisible();
|
|
14
14
|
await loginPage.clickContinueButton();
|
|
15
|
-
await (0, test_1.expect)(loginPage.passwordInput).toBeVisible({ timeout:
|
|
15
|
+
await (0, test_1.expect)(loginPage.passwordInput).toBeVisible({ timeout: 90000 });
|
|
16
16
|
await loginPage.fillPassword(process.env.C8_PASSWORD);
|
|
17
|
-
await (0, test_1.expect)(loginPage.passwordHeading).toBeVisible();
|
|
17
|
+
await (0, test_1.expect)(loginPage.passwordHeading).toBeVisible({ timeout: 90000 });
|
|
18
18
|
await loginPage.clickLoginButton();
|
|
19
19
|
await page.waitForURL((url) => url.toString().startsWith(appName), {
|
|
20
20
|
timeout: 60000,
|