@camunda/e2e-test-suite 0.0.1598 → 0.0.1600
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.11/ConsoleOrganizationPage.d.ts +1 -0
- package/dist/pages/8.11/ConsoleOrganizationPage.js +83 -67
- package/dist/pages/8.11/ModelerCreatePage.js +11 -2
- package/dist/pages/8.8/ClusterPage.js +8 -0
- package/dist/pages/8.9/ClientCredentialsDetailsPage.js +17 -7
- package/dist/pages/8.9/ClusterDetailsPage.d.ts +1 -0
- package/dist/pages/8.9/ClusterDetailsPage.js +36 -11
- package/dist/tests/8.11/test-setup.spec.js +1 -2
- package/dist/tests/8.11/web-modeler-user-flows.spec.js +3 -5
- package/dist/tests/8.8/idp-user-flows.spec.js +15 -0
- package/dist/tests/8.9/operate-access-flow.spec.js +14 -3
- package/package.json +1 -1
|
@@ -58,6 +58,7 @@ declare class ConsoleOrganizationPage {
|
|
|
58
58
|
clickSettingsTab(): Promise<void>;
|
|
59
59
|
clickOptInButton(): Promise<void>;
|
|
60
60
|
enableAlphaFeature(name: string): Promise<void>;
|
|
61
|
+
closeTermsDialog(): Promise<void>;
|
|
61
62
|
scrollToOptInCheckbox(): Promise<void>;
|
|
62
63
|
checkOptInCheckbox(): Promise<void>;
|
|
63
64
|
clickMainUser(): Promise<void>;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ConsoleOrganizationPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
|
-
const sleep_1 = require("../../utils/sleep");
|
|
6
5
|
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
7
6
|
class ConsoleOrganizationPage {
|
|
8
7
|
page;
|
|
@@ -86,7 +85,7 @@ class ConsoleOrganizationPage {
|
|
|
86
85
|
this.startProcessIPermissionCheckbox = page.getByRole('checkbox', {
|
|
87
86
|
name: 'Start process instance',
|
|
88
87
|
});
|
|
89
|
-
this.optInAICheckbox =
|
|
88
|
+
this.optInAICheckbox = this.dialog.first().getByRole('checkbox');
|
|
90
89
|
this.rows = this.page.getByRole('row');
|
|
91
90
|
this.groupsTab = page.getByRole('tab', { name: 'Groups' });
|
|
92
91
|
this.createGroupButton = page.getByRole('button', {
|
|
@@ -283,70 +282,85 @@ class ConsoleOrganizationPage {
|
|
|
283
282
|
await this.optInButton.click({ timeout: 60000 });
|
|
284
283
|
}
|
|
285
284
|
async enableAlphaFeature(name) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
285
|
+
await this.clickSettingsTab();
|
|
286
|
+
await this.optInToAlphaFeatures();
|
|
287
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.rows.first(), {
|
|
288
|
+
visibilityTimeout: 60000,
|
|
289
|
+
totalTimeout: 300000,
|
|
290
|
+
maxRetries: 5,
|
|
291
|
+
postAction: async () => {
|
|
292
292
|
await this.page.reload();
|
|
293
293
|
await this.clickSettingsTab();
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
//Opt-in The Alpha Feature
|
|
311
|
-
const alphaFeatureOptInButton = alphaFeature.getByRole('button', {
|
|
312
|
-
name: 'Opt in to enable',
|
|
313
|
-
});
|
|
314
|
-
if (await alphaFeatureOptInButton.isVisible({ timeout: 10000 })) {
|
|
315
|
-
await alphaFeatureOptInButton.click({ timeout: 30000 });
|
|
316
|
-
await this.optInAICheckbox.scrollIntoViewIfNeeded();
|
|
317
|
-
await this.optInAICheckbox.check({ timeout: 30000 });
|
|
318
|
-
await (0, sleep_1.sleep)(3000);
|
|
319
|
-
}
|
|
320
|
-
//Enable Alpha Feature
|
|
321
|
-
const toggleText = await alphaFeature
|
|
322
|
-
.locator('[class= "cds--toggle__text"]')
|
|
323
|
-
.textContent();
|
|
324
|
-
console.info(`Previous feature(${name}) setting is ${toggleText}.`);
|
|
325
|
-
if (toggleText == 'Enabled') {
|
|
326
|
-
console.log(`Feature ${name} is already enabled.`);
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
if (toggleText == 'Disabled') {
|
|
330
|
-
await alphaFeature
|
|
331
|
-
.locator('[class= "cds--toggle__switch"]')
|
|
332
|
-
.first()
|
|
333
|
-
.click();
|
|
334
|
-
await (0, sleep_1.sleep)(10000);
|
|
335
|
-
}
|
|
336
|
-
await (0, test_1.expect)(alphaFeature.locator('[class= "cds--toggle__text"]')).toHaveText('Enabled');
|
|
337
|
-
return;
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
const alphaFeature = this.rows.filter({ hasText: name }).first();
|
|
297
|
+
if ((await alphaFeature.count()) < 1) {
|
|
298
|
+
throw new Error(`No alpha feature(${name}) is found.`);
|
|
299
|
+
}
|
|
300
|
+
const alphaFeatureOptInButton = alphaFeature.getByRole('button', {
|
|
301
|
+
name: 'Opt in to enable',
|
|
302
|
+
});
|
|
303
|
+
if (await alphaFeatureOptInButton.isVisible({ timeout: 10000 })) {
|
|
304
|
+
if (await alphaFeatureOptInButton.isEnabled()) {
|
|
305
|
+
await alphaFeatureOptInButton.click({ timeout: 90000 });
|
|
306
|
+
await (0, test_1.expect)(this.dialog.first()).toBeVisible({ timeout: 60000 });
|
|
307
|
+
await this.scrollToOptInCheckbox();
|
|
308
|
+
await this.optInAICheckbox.check({ timeout: 90000 });
|
|
309
|
+
await this.closeTermsDialog();
|
|
338
310
|
}
|
|
339
|
-
|
|
340
|
-
|
|
311
|
+
}
|
|
312
|
+
const toggle = alphaFeature.getByRole('switch').first();
|
|
313
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, toggle, {
|
|
314
|
+
visibilityTimeout: 30000,
|
|
315
|
+
totalTimeout: 180000,
|
|
316
|
+
maxRetries: 5,
|
|
317
|
+
postAction: async () => {
|
|
341
318
|
await this.page.reload();
|
|
342
|
-
await
|
|
343
|
-
}
|
|
319
|
+
await this.clickSettingsTab();
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
if (await toggle.isChecked()) {
|
|
323
|
+
console.log(`Feature ${name} is already enabled.`);
|
|
324
|
+
return;
|
|
344
325
|
}
|
|
345
|
-
|
|
326
|
+
await toggle.click();
|
|
327
|
+
await (0, test_1.expect)(toggle).toBeChecked({ timeout: 60000 });
|
|
328
|
+
}
|
|
329
|
+
async closeTermsDialog() {
|
|
330
|
+
const closeButton = this.dialog
|
|
331
|
+
.first()
|
|
332
|
+
.getByRole('button', { name: 'Close' });
|
|
333
|
+
if (await closeButton.isVisible({ timeout: 10000 }).catch(() => false)) {
|
|
334
|
+
await closeButton.click();
|
|
335
|
+
}
|
|
336
|
+
await (0, test_1.expect)(this.dialog.first()).toBeHidden({ timeout: 60000 });
|
|
346
337
|
}
|
|
347
338
|
async scrollToOptInCheckbox() {
|
|
348
|
-
|
|
349
|
-
|
|
339
|
+
const dialog = this.dialog.first();
|
|
340
|
+
await (0, test_1.expect)(dialog).toBeVisible({ timeout: 30000 });
|
|
341
|
+
const contractScroll = this.page.locator('.ps-contract-scroll').first();
|
|
342
|
+
if (await contractScroll.isVisible({ timeout: 5000 }).catch(() => false)) {
|
|
343
|
+
await contractScroll.evaluate((el) => {
|
|
344
|
+
el.scrollTop = el.scrollHeight;
|
|
345
|
+
el.dispatchEvent(new Event('scroll', { bubbles: true }));
|
|
346
|
+
});
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const box = await dialog.boundingBox();
|
|
350
|
+
if (box) {
|
|
351
|
+
await this.page.mouse.move(box.x + box.width / 2, box.y + box.height * 0.6);
|
|
352
|
+
for (let i = 0; i < 20; i++) {
|
|
353
|
+
await this.page.mouse.wheel(0, 300);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
await dialog.evaluate((dlg) => {
|
|
357
|
+
const all = [dlg, ...Array.from(dlg.querySelectorAll('*'))];
|
|
358
|
+
for (const node of all) {
|
|
359
|
+
if (!(node instanceof HTMLElement))
|
|
360
|
+
continue;
|
|
361
|
+
node.scrollTop = node.scrollHeight;
|
|
362
|
+
node.dispatchEvent(new Event('scroll', { bubbles: true }));
|
|
363
|
+
}
|
|
350
364
|
});
|
|
351
365
|
}
|
|
352
366
|
async checkOptInCheckbox() {
|
|
@@ -378,15 +392,17 @@ class ConsoleOrganizationPage {
|
|
|
378
392
|
await this.page.reload();
|
|
379
393
|
},
|
|
380
394
|
});
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
await this.clickOptInButton();
|
|
384
|
-
await this.scrollToOptInCheckbox();
|
|
385
|
-
await this.checkOptInCheckbox();
|
|
386
|
-
}
|
|
387
|
-
catch {
|
|
388
|
-
await (0, test_1.expect)(this.optInButton).not.toBeVisible();
|
|
395
|
+
if (!(await this.optInButton.isVisible({ timeout: 30000 }).catch(() => false))) {
|
|
396
|
+
return;
|
|
389
397
|
}
|
|
398
|
+
await this.clickOptInButton();
|
|
399
|
+
await (0, test_1.expect)(this.dialog.first()).toBeVisible({ timeout: 60000 });
|
|
400
|
+
await this.scrollToOptInCheckbox();
|
|
401
|
+
await this.optInCheckbox.check({ timeout: 90000 });
|
|
402
|
+
await this.closeTermsDialog();
|
|
403
|
+
await this.page.reload();
|
|
404
|
+
await this.clickSettingsTab();
|
|
405
|
+
await (0, test_1.expect)(this.optInButton).not.toBeVisible({ timeout: 60000 });
|
|
390
406
|
}
|
|
391
407
|
async clickGroupsTab() {
|
|
392
408
|
await this.groupsTab.click({ timeout: 60000 });
|
|
@@ -302,8 +302,17 @@ class ModelerCreatePage {
|
|
|
302
302
|
this.processIdInput = page.getByLabel('ID', { exact: true });
|
|
303
303
|
this.payloadNameInput = page.getByLabel('Full Name');
|
|
304
304
|
this.payloadDateInput = page.getByLabel('Date of Birth');
|
|
305
|
-
|
|
306
|
-
|
|
305
|
+
// Scoped to the deploy/run dialog and matched by role, not through the
|
|
306
|
+
// exact-class form container: the start form renders inside the dialog
|
|
307
|
+
// and `[class="fjs-container"]` only matches when that element carries
|
|
308
|
+
// no other class, so an extra class on the form root silently empties
|
|
309
|
+
// every locator built on it.
|
|
310
|
+
this.payloadCheckboxInput = this.dialog
|
|
311
|
+
.first()
|
|
312
|
+
.getByRole('checkbox', { name: 'Agree' });
|
|
313
|
+
this.payloadNumberInput = this.dialog
|
|
314
|
+
.first()
|
|
315
|
+
.getByRole('textbox', { name: 'Count' });
|
|
307
316
|
this.formPropertySection = page.locator('[data-group-id="group-form"]');
|
|
308
317
|
this.formLinkingTypeDropdown = page.getByLabel('Type');
|
|
309
318
|
this.formLinkTypeOptions = page.locator('#bio-properties-panel-formType');
|
|
@@ -296,6 +296,14 @@ class ClusterPage {
|
|
|
296
296
|
await this.selectSubRegion(region);
|
|
297
297
|
await this.clickClusterOption(process.env.CLUSTER_VERSION);
|
|
298
298
|
await this.determineTasklistAPI(tasklistV1Api);
|
|
299
|
+
// The form re-renders when its session/parameters refresh lands after the
|
|
300
|
+
// name was typed, which clears the name: Create then only shows "Please
|
|
301
|
+
// enter a name for the cluster" and no cluster is ever requested. Re-fill
|
|
302
|
+
// it right before submitting.
|
|
303
|
+
if ((await this.clusterNameInput.inputValue()) !== name) {
|
|
304
|
+
await this.fillClusterNameInput(name);
|
|
305
|
+
}
|
|
306
|
+
await (0, test_1.expect)(this.clusterNameInput).toHaveValue(name, { timeout: 10000 });
|
|
299
307
|
await this.clickCreateClusterButton();
|
|
300
308
|
await this.logClusterCreationInfo(name);
|
|
301
309
|
await this.clickClustersBreadcrumb(name);
|
|
@@ -17,15 +17,25 @@ class ClientCredentialsDetailsPage {
|
|
|
17
17
|
await (0, test_1.expect)(this.clientNameHeading(clientName).or(this.operateUrlRow).first()).toBeVisible({ timeout: 60000 });
|
|
18
18
|
}
|
|
19
19
|
async getOperateUrl() {
|
|
20
|
-
if (await this.operateUrlValue.isVisible(
|
|
20
|
+
if (await this.operateUrlValue.isVisible().catch(() => false)) {
|
|
21
21
|
return await this.operateUrlValue.inputValue();
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
// locator.isVisible() ignores its timeout, so the old probe read the body
|
|
24
|
+
// the instant the client view opened and failed whenever the credentials
|
|
25
|
+
// rendered a moment later. Poll the rendered text until the URL appears.
|
|
26
|
+
const pattern = /Operate URL\s*([\w:/.-]+\/?)/i;
|
|
27
|
+
let operateUrl = '';
|
|
28
|
+
await test_1.expect
|
|
29
|
+
.poll(async () => {
|
|
30
|
+
const text = await this.page.innerText('body').catch(() => '');
|
|
31
|
+
operateUrl = text.match(pattern)?.[1] ?? '';
|
|
32
|
+
return operateUrl;
|
|
33
|
+
}, {
|
|
34
|
+
timeout: 30000,
|
|
35
|
+
message: 'Operate URL not found in client credentials page',
|
|
36
|
+
})
|
|
37
|
+
.not.toBe('');
|
|
38
|
+
return operateUrl;
|
|
29
39
|
}
|
|
30
40
|
async goBack() {
|
|
31
41
|
await this.page.goBack();
|
|
@@ -39,6 +39,7 @@ declare class ClusterDetailsPage {
|
|
|
39
39
|
readonly createAlertButton: Locator;
|
|
40
40
|
readonly createNewClientButton: Locator;
|
|
41
41
|
readonly clientsList: Locator;
|
|
42
|
+
readonly clientsFilterInput: Locator;
|
|
42
43
|
readonly envVarsTab: Locator;
|
|
43
44
|
readonly zeebeCheckbox: Locator;
|
|
44
45
|
readonly apiClientNameTextbox: Locator;
|
|
@@ -51,6 +51,7 @@ class ClusterDetailsPage {
|
|
|
51
51
|
createAlertButton;
|
|
52
52
|
createNewClientButton;
|
|
53
53
|
clientsList;
|
|
54
|
+
clientsFilterInput;
|
|
54
55
|
envVarsTab;
|
|
55
56
|
zeebeCheckbox;
|
|
56
57
|
apiClientNameTextbox;
|
|
@@ -194,6 +195,13 @@ class ClusterDetailsPage {
|
|
|
194
195
|
name: 'Create new client',
|
|
195
196
|
});
|
|
196
197
|
this.clientsList = page.getByRole('row').filter({ hasNotText: 'Scopes' });
|
|
198
|
+
// The clients table paginates and isn't ordered by creation time, so a
|
|
199
|
+
// newly created client can sit on a page other than the one displayed.
|
|
200
|
+
// Filter it first (same locator as pages/8.10/ClusterDetailsPage.ts).
|
|
201
|
+
this.clientsFilterInput = page
|
|
202
|
+
.getByRole('searchbox', { name: 'Filter table' })
|
|
203
|
+
.or(page.getByRole('searchbox', { name: 'Search' }))
|
|
204
|
+
.or(page.getByPlaceholder('Search'));
|
|
197
205
|
this.envVarsTab = this.clientCredentialsDialog.getByRole('tab', {
|
|
198
206
|
name: 'Env Vars',
|
|
199
207
|
});
|
|
@@ -313,6 +321,8 @@ class ClusterDetailsPage {
|
|
|
313
321
|
const maxAttempts = 3;
|
|
314
322
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
315
323
|
try {
|
|
324
|
+
await (0, test_1.expect)(this.clientsFilterInput).toBeVisible({ timeout: 60000 });
|
|
325
|
+
await this.clientsFilterInput.fill(name);
|
|
316
326
|
await (0, test_1.expect)(row).toContainText(scopes, { timeout: 60000 });
|
|
317
327
|
return;
|
|
318
328
|
}
|
|
@@ -565,6 +575,8 @@ class ClusterDetailsPage {
|
|
|
565
575
|
}
|
|
566
576
|
async searchAndClickClientCredentialsLink(name) {
|
|
567
577
|
await (0, test_1.expect)(this.clientsList.first()).toBeVisible({ timeout: 60000 });
|
|
578
|
+
await (0, test_1.expect)(this.clientsFilterInput).toBeVisible({ timeout: 60000 });
|
|
579
|
+
await this.clientsFilterInput.fill(name);
|
|
568
580
|
const clientLink = this.clientCredentialsLink(name);
|
|
569
581
|
await (0, test_1.expect)(clientLink).toBeVisible({ timeout: 30000 });
|
|
570
582
|
await clientLink.click();
|
|
@@ -823,13 +835,24 @@ class ClusterDetailsPage {
|
|
|
823
835
|
return variables;
|
|
824
836
|
}
|
|
825
837
|
async createAPIClient(name) {
|
|
826
|
-
|
|
838
|
+
// Console API requests on SaaS INT fail in bursts (net::ERR_FAILED) that
|
|
839
|
+
// can last a few minutes: GETs recover via the app's own refetch, but
|
|
840
|
+
// the create POST is not retried and surfaces as "fetch error", and the
|
|
841
|
+
// reload between attempts lands the panel with "Create new client"
|
|
842
|
+
// disabled until the cluster queries succeed. Five attempts, each one
|
|
843
|
+
// waiting for the panel to recover first, ride out such a burst.
|
|
844
|
+
const maxRetries = 5;
|
|
827
845
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
828
846
|
// Use a suffixed name on retries so duplicate-name validation never
|
|
829
847
|
// leaves the Create button permanently disabled. A prior attempt may
|
|
830
848
|
// have created the client before we could detect the credentials dialog.
|
|
831
849
|
const attemptName = attempt === 0 ? name : `${name}-r${attempt}`;
|
|
832
850
|
try {
|
|
851
|
+
// Wait for the clients panel to be usable before clicking: after a
|
|
852
|
+
// failed burst the button renders disabled for tens of seconds, and
|
|
853
|
+
// clicking it only burns clickLocatorWithRetry's attempts.
|
|
854
|
+
await this.dismissOopsIfPresent();
|
|
855
|
+
await (0, test_1.expect)(this.createFirstClientButton.or(this.createNewClientButton)).toBeEnabled({ timeout: 60000 });
|
|
833
856
|
await this.clickCreateClientButton();
|
|
834
857
|
await (0, test_1.expect)(this.createClientCredentialsDialog).toBeVisible({
|
|
835
858
|
timeout: 30000,
|
|
@@ -845,20 +868,22 @@ class ClusterDetailsPage {
|
|
|
845
868
|
// Secret will not be shown again.") dialog never appears. Detect
|
|
846
869
|
// that state and retry instead of burning 60s on a visibility
|
|
847
870
|
// assertion that will never resolve.
|
|
871
|
+
// locator.isVisible() ignores its timeout and returns immediately,
|
|
872
|
+
// so wait for either outcome explicitly before branching on it.
|
|
873
|
+
const fetchErrorBanner = this.createClientCredentialsDialog.getByText(/fetch error/i);
|
|
874
|
+
await this.clientCredentialsDialog
|
|
875
|
+
.or(fetchErrorBanner)
|
|
876
|
+
.first()
|
|
877
|
+
.waitFor({ state: 'visible', timeout: 30000 })
|
|
878
|
+
.catch(() => false);
|
|
848
879
|
const credentialsShown = await this.clientCredentialsDialog
|
|
849
|
-
.isVisible(
|
|
880
|
+
.isVisible()
|
|
850
881
|
.catch(() => false);
|
|
851
882
|
if (!credentialsShown) {
|
|
852
|
-
const
|
|
853
|
-
.isVisible(
|
|
883
|
+
const fetchError = await fetchErrorBanner
|
|
884
|
+
.isVisible()
|
|
854
885
|
.catch(() => false);
|
|
855
|
-
|
|
856
|
-
? await this.createClientCredentialsDialog
|
|
857
|
-
.getByText(/fetch error/i)
|
|
858
|
-
.isVisible({ timeout: 500 })
|
|
859
|
-
.catch(() => false)
|
|
860
|
-
: false;
|
|
861
|
-
if (stuckCreateDialog && fetchError) {
|
|
886
|
+
if (fetchError) {
|
|
862
887
|
throw new Error('createAPIClient: create dialog stuck with "fetch error"');
|
|
863
888
|
}
|
|
864
889
|
// Not the fetch-error path — fall through to the original
|
|
@@ -18,8 +18,7 @@ _8_11_1.test.describe('Cluster Setup Tests', () => {
|
|
|
18
18
|
await (0, _setup_1.captureScreenshot)(page, testInfo);
|
|
19
19
|
await (0, _setup_1.captureFailureVideo)(page, testInfo);
|
|
20
20
|
});
|
|
21
|
-
|
|
22
|
-
_8_11_1.test.skip('Enable Alpha Features', async ({ page, loginPage, consoleOrganizationsPage, homePage, }, testInfo) => {
|
|
21
|
+
(0, _8_11_1.test)('Enable Alpha Features', async ({ page, loginPage, consoleOrganizationsPage, homePage, }, testInfo) => {
|
|
23
22
|
_8_11_1.test.skip(process.env.IS_PROD === 'true', 'Skipping test because not required on PROD test org');
|
|
24
23
|
_8_11_1.test.skip(process.env.IS_AG === 'true', 'Skipping test because not required when IS_AG is true');
|
|
25
24
|
await (0, UtilitiesPage_1.loginWithRetry)(page, loginPage, users_1.testUsers.mainUser, (testInfo.workerIndex + 1) * 1000);
|
|
@@ -35,8 +35,7 @@ _8_11_1.test.describe('Web Modeler User Flow Tests', () => {
|
|
|
35
35
|
await (0, mailSlurpClient_1.deleteInbox)(inboxes[testInfo.title]);
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
|
-
|
|
39
|
-
_8_11_1.test.skip('Form.js Integration with User Task and AI Generated Form @ai-external', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, consoleOrganizationsPage, loginPage, }, testInfo) => {
|
|
38
|
+
(0, _8_11_1.test)('Form.js Integration with User Task and AI Generated Form @ai-external', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, consoleOrganizationsPage, loginPage, }, testInfo) => {
|
|
40
39
|
_8_11_1.test.slow();
|
|
41
40
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
42
41
|
const processName = 'User_Task_Process_With_AI_Form' + randomString;
|
|
@@ -75,7 +74,7 @@ _8_11_1.test.describe('Web Modeler User Flow Tests', () => {
|
|
|
75
74
|
// identity-provider page, and if so signs back in before trying once
|
|
76
75
|
// more (run 35562939552, "Camunda Modeler" banner absent 90s after 3
|
|
77
76
|
// such retries).
|
|
78
|
-
await (0, UtilitiesPage_1.withSessionRecovery)(page, loginPage, appsPage, modelerHomePage.modelerPageBanner, testUser, (testInfo.workerIndex + 1) * 1000, () => appsPage.openModelerWithRetry(modelerHomePage.modelerPageBanner, 90000, 3, modelerHomePage.createNewProjectButton));
|
|
77
|
+
await (0, UtilitiesPage_1.withSessionRecovery)(page, loginPage, appsPage, modelerHomePage.modelerPageBanner, testUser, (testInfo.workerIndex + 1) * 1000, () => appsPage.openModelerWithRetry(modelerHomePage.modelerPageBanner, 90000, 3, modelerHomePage.createNewProjectButton.or(modelerHomePage.createWorkspaceButton)));
|
|
79
78
|
});
|
|
80
79
|
await _8_11_1.test.step('Open Cross Component Test Project', async () => {
|
|
81
80
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
@@ -141,8 +140,7 @@ _8_11_1.test.describe('Web Modeler User Flow Tests', () => {
|
|
|
141
140
|
await operateTabTaskDetailsPage.clickCompleteTaskButton();
|
|
142
141
|
});
|
|
143
142
|
});
|
|
144
|
-
|
|
145
|
-
_8_11_1.test.skip('Form.js Integration with AI generated Start form @ai-external', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, }) => {
|
|
143
|
+
(0, _8_11_1.test)('Form.js Integration with AI generated Start form @ai-external', async ({ page, homePage, modelerHomePage, appsPage, modelerCreatePage, formJsPage, }) => {
|
|
146
144
|
_8_11_1.test.slow();
|
|
147
145
|
const randomString = await (0, _setup_1.generateRandomStringAsync)(3);
|
|
148
146
|
const processName = 'AI-generated-Start-form' + randomString;
|
|
@@ -8,6 +8,7 @@ const randomName_1 = require("../../utils/randomName");
|
|
|
8
8
|
const fileUpload_1 = require("../../utils/fileUpload");
|
|
9
9
|
const connectorSecrets_1 = require("../../utils/connectorSecrets");
|
|
10
10
|
const users_1 = require("../../utils/users");
|
|
11
|
+
const consoleApiHelpers_1 = require("../../utils/consoleApiHelpers");
|
|
11
12
|
const testUser = (0, users_1.getTestUser)('twentiethUser');
|
|
12
13
|
let idpApplicationName;
|
|
13
14
|
let idpDocumentExtractionTemplateName;
|
|
@@ -88,6 +89,13 @@ _8_8_1.test.describe('IDP User Flow Tests', () => {
|
|
|
88
89
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
89
90
|
});
|
|
90
91
|
await _8_8_1.test.step('Add an IDP application to the project', async () => {
|
|
92
|
+
// The "Create IDP project" dialog only offers the Environments
|
|
93
|
+
// assigned to the workspace. test-setup's link of the cluster is a
|
|
94
|
+
// no-op when the workspace does not exist yet, so on a fresh org the
|
|
95
|
+
// dialog showed "No deployment environments available" (or only
|
|
96
|
+
// another spec's cluster) on the first attempt. Ensure the link here,
|
|
97
|
+
// as every deploy path in the page objects already does.
|
|
98
|
+
await (0, consoleApiHelpers_1.ensureClusterLinkedToSharedWorkspace)(page, clusterName);
|
|
91
99
|
// Workspace root only: an IDP application can never be created
|
|
92
100
|
// inside a process application. The entry point there is the create
|
|
93
101
|
// menu or the empty state, depending on whether the workspace
|
|
@@ -163,6 +171,13 @@ _8_8_1.test.describe('IDP User Flow Tests', () => {
|
|
|
163
171
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
164
172
|
});
|
|
165
173
|
await _8_8_1.test.step('Add an IDP application to the project', async () => {
|
|
174
|
+
// The "Create IDP project" dialog only offers the Environments
|
|
175
|
+
// assigned to the workspace. test-setup's link of the cluster is a
|
|
176
|
+
// no-op when the workspace does not exist yet, so on a fresh org the
|
|
177
|
+
// dialog showed "No deployment environments available" (or only
|
|
178
|
+
// another spec's cluster) on the first attempt. Ensure the link here,
|
|
179
|
+
// as every deploy path in the page objects already does.
|
|
180
|
+
await (0, consoleApiHelpers_1.ensureClusterLinkedToSharedWorkspace)(page, clusterName);
|
|
166
181
|
// Workspace root only: an IDP application can never be created
|
|
167
182
|
// inside a process application. The entry point there is the create
|
|
168
183
|
// menu or the empty state, depending on whether the workspace
|
|
@@ -57,7 +57,7 @@ _8_9_1.test.describe('Operate access requires authentication @tasklistV2', () =>
|
|
|
57
57
|
(0, test_1.expect)([200, 405]).toContain(response.status());
|
|
58
58
|
});
|
|
59
59
|
});
|
|
60
|
-
(0, _8_9_1.test)('check that POST /v2/user-tasks/search returns 401 without credentials', async ({ homePage, clusterPage, clusterDetailsPage, clientCredentialsDetailsPage, request, }) => {
|
|
60
|
+
(0, _8_9_1.test)('check that POST /v2/user-tasks/search returns 401 without credentials', async ({ page, homePage, clusterPage, clusterDetailsPage, clientCredentialsDetailsPage, request, }) => {
|
|
61
61
|
clientName = `tasklist-deny-${await (0, _setup_1.generateRandomStringAsync)(5)}`;
|
|
62
62
|
let operateUrl = '';
|
|
63
63
|
await _8_9_1.test.step('Add API Client to Cluster', async () => {
|
|
@@ -69,8 +69,19 @@ _8_9_1.test.describe('Operate access requires authentication @tasklistV2', () =>
|
|
|
69
69
|
await (0, test_1.expect)(clusterDetailsPage.clientsList.filter({ hasText: clientName })).toBeVisible({ timeout: 6000 });
|
|
70
70
|
});
|
|
71
71
|
await _8_9_1.test.step('Capture Operate URL (base URL shared with Tasklist v2 endpoint)', async () => {
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
// A failed Console API request can render the client view as "Oops ...
|
|
73
|
+
// something went wrong." instead of its credentials. The view is not a
|
|
74
|
+
// route, so recover by reloading the API tab and reopening the client.
|
|
75
|
+
let firstAttempt = true;
|
|
76
|
+
await (0, test_1.expect)(async () => {
|
|
77
|
+
if (!firstAttempt) {
|
|
78
|
+
await page.reload({ waitUntil: 'domcontentloaded' });
|
|
79
|
+
await clusterDetailsPage.clickAPITab();
|
|
80
|
+
}
|
|
81
|
+
firstAttempt = false;
|
|
82
|
+
await clusterDetailsPage.searchAndClickClientCredentialsLink(clientName);
|
|
83
|
+
operateUrl = await clientCredentialsDetailsPage.getOperateUrl();
|
|
84
|
+
}).toPass({ timeout: 240000, intervals: [5000] });
|
|
74
85
|
(0, test_1.expect)(operateUrl).toMatch(/^https?:\/\//);
|
|
75
86
|
await clientCredentialsDetailsPage.goBack();
|
|
76
87
|
await clusterDetailsPage.clickAPITab();
|