@camunda/e2e-test-suite 0.0.1009 → 0.0.1011
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/pages/8.10/FormJsPage.d.ts +2 -0
- package/dist/pages/8.10/FormJsPage.js +59 -1
- package/dist/pages/8.10/ModelerCreatePage.d.ts +1 -0
- package/dist/pages/8.10/ModelerCreatePage.js +139 -20
- package/dist/pages/8.10/ModelerHomePage.d.ts +12 -0
- package/dist/pages/8.10/ModelerHomePage.js +153 -12
- package/dist/pages/8.10/ProcessApplicationPage.d.ts +29 -0
- package/dist/pages/8.10/ProcessApplicationPage.js +237 -0
- package/dist/pages/8.10/UtilitiesPage.js +8 -0
- package/dist/pages/SM-8.10/FormJsPage.d.ts +1 -0
- package/dist/pages/SM-8.10/FormJsPage.js +31 -0
- package/dist/pages/SM-8.10/ModelerCreatePage.js +54 -16
- package/dist/pages/SM-8.10/ModelerHomePage.d.ts +11 -0
- package/dist/pages/SM-8.10/ModelerHomePage.js +147 -9
- package/dist/pages/SM-8.10/NavigationPage.js +3 -1
- package/dist/pages/SM-8.10/OCIdentityHomePage.js +31 -8
- package/dist/pages/SM-8.10/OCIdentityRolesPage.js +4 -1
- package/dist/pages/SM-8.10/ProcessApplicationPage.d.ts +23 -0
- package/dist/pages/SM-8.10/ProcessApplicationPage.js +132 -0
- package/dist/pages/SM-8.10/SettingsPage.js +12 -3
- package/dist/pages/SM-8.10/UtilitiesPage.js +8 -0
- package/dist/tests/8.10/access-user-role-management.spec.js +3 -3
- package/dist/tests/8.10/idp-user-flows.spec.js +9 -3
- package/package.json +1 -1
|
@@ -56,8 +56,10 @@ class NavigationPage {
|
|
|
56
56
|
});
|
|
57
57
|
// TODO: Drop support for Identity once we fully rename it to Admin
|
|
58
58
|
this.identityPageBanner = page
|
|
59
|
+
.getByRole('link', { name: 'Camunda Admin', exact: true })
|
|
60
|
+
.or(page
|
|
59
61
|
.locator('a')
|
|
60
|
-
.filter({ hasText: /^Camunda logo\s*(Identity|Admin)$/ })
|
|
62
|
+
.filter({ hasText: /^Camunda logo\s*(Identity|Admin)$/ }))
|
|
61
63
|
.first();
|
|
62
64
|
this.managementIdentityPageBanner = page
|
|
63
65
|
.locator('a')
|
|
@@ -19,34 +19,57 @@ class OCIdentityHomePage {
|
|
|
19
19
|
constructor(page) {
|
|
20
20
|
this.page = page;
|
|
21
21
|
this.adminBanner = page
|
|
22
|
-
.
|
|
23
|
-
.filter({ hasText: /^Camunda logo\s*Admin$/ })
|
|
22
|
+
.getByRole('link', { name: 'Camunda Admin', exact: true })
|
|
23
|
+
.or(page.locator('a').filter({ hasText: /^Camunda logo\s*Admin$/ }))
|
|
24
24
|
.first();
|
|
25
25
|
this.groupsTab = page
|
|
26
|
+
.getByRole('navigation', { name: 'Main navigation' })
|
|
27
|
+
.getByRole('link', { name: 'Groups', exact: true })
|
|
28
|
+
.or(page
|
|
26
29
|
.getByRole('banner')
|
|
27
30
|
.locator('a')
|
|
28
|
-
.filter({ hasText: /^Groups$/ })
|
|
31
|
+
.filter({ hasText: /^Groups$/ }))
|
|
32
|
+
.first();
|
|
29
33
|
this.mappingRulesTab = page
|
|
34
|
+
.getByRole('navigation', { name: 'Main navigation' })
|
|
35
|
+
.getByRole('link', { name: 'Mapping rules', exact: true })
|
|
36
|
+
.or(page
|
|
30
37
|
.getByRole('banner')
|
|
31
38
|
.locator('a')
|
|
32
|
-
.filter({ hasText: /^Mapping rules$/ })
|
|
39
|
+
.filter({ hasText: /^Mapping rules$/ }))
|
|
33
40
|
.first();
|
|
34
41
|
this.tenantsTab = page
|
|
42
|
+
.getByRole('navigation', { name: 'Main navigation' })
|
|
43
|
+
.getByRole('link', { name: 'Tenants', exact: true })
|
|
44
|
+
.or(page
|
|
35
45
|
.getByRole('banner')
|
|
36
46
|
.locator('a')
|
|
37
|
-
.filter({ hasText: /^Tenants$/ })
|
|
47
|
+
.filter({ hasText: /^Tenants$/ }))
|
|
48
|
+
.first();
|
|
38
49
|
this.rolesTab = page
|
|
50
|
+
.getByRole('navigation', { name: 'Main navigation' })
|
|
51
|
+
.getByRole('link', { name: 'Roles', exact: true })
|
|
52
|
+
.or(page
|
|
39
53
|
.getByRole('banner')
|
|
40
54
|
.locator('a')
|
|
41
|
-
.filter({ hasText:
|
|
55
|
+
.filter({ hasText: /^Roles$/ }))
|
|
56
|
+
.first();
|
|
42
57
|
this.authorizationsTab = page
|
|
58
|
+
.getByRole('navigation', { name: 'Main navigation' })
|
|
59
|
+
.getByRole('link', { name: 'Authorizations', exact: true })
|
|
60
|
+
.or(page
|
|
43
61
|
.getByRole('banner')
|
|
44
62
|
.locator('a')
|
|
45
|
-
.filter({ hasText: /^Authorizations$/ })
|
|
63
|
+
.filter({ hasText: /^Authorizations$/ }))
|
|
64
|
+
.first();
|
|
46
65
|
this.clusterVariablesTab = page
|
|
66
|
+
.getByRole('navigation', { name: 'Main navigation' })
|
|
67
|
+
.getByRole('link', { name: 'Cluster variables', exact: true })
|
|
68
|
+
.or(page
|
|
47
69
|
.getByRole('banner')
|
|
48
70
|
.locator('a')
|
|
49
|
-
.filter({ hasText: /Cluster variables/i })
|
|
71
|
+
.filter({ hasText: /Cluster variables/i }))
|
|
72
|
+
.first();
|
|
50
73
|
this.licenseKeyTagNonProduction = page
|
|
51
74
|
.getByText('Non-production license')
|
|
52
75
|
.first();
|
|
@@ -87,9 +87,12 @@ class OCIdentityRolesPage {
|
|
|
87
87
|
});
|
|
88
88
|
this.adminRole = page.getByRole('cell', { name: 'admin', exact: true });
|
|
89
89
|
this.rolesNavTab = page
|
|
90
|
+
.getByRole('navigation', { name: 'Main navigation' })
|
|
91
|
+
.getByRole('link', { name: 'Roles', exact: true })
|
|
92
|
+
.or(page
|
|
90
93
|
.getByRole('banner')
|
|
91
94
|
.locator('a')
|
|
92
|
-
.filter({ hasText: /^Roles$/ })
|
|
95
|
+
.filter({ hasText: /^Roles$/ }))
|
|
93
96
|
.first();
|
|
94
97
|
this.assignUserButton = page.getByRole('button', { name: 'Assign user' });
|
|
95
98
|
this.usernameTextBox = page.getByRole('textbox', { name: 'Username' });
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Locator, Page } from '@playwright/test';
|
|
2
|
+
declare class ProcessApplicationPage {
|
|
3
|
+
private page;
|
|
4
|
+
readonly createProcessApplicationButton: Locator;
|
|
5
|
+
readonly createProcessApplicationOption: Locator;
|
|
6
|
+
readonly creationDialog: Locator;
|
|
7
|
+
readonly nameInput: Locator;
|
|
8
|
+
readonly submitButton: Locator;
|
|
9
|
+
readonly cancelButton: Locator;
|
|
10
|
+
readonly breadcrumb: Locator;
|
|
11
|
+
readonly folderExplorer: Locator;
|
|
12
|
+
readonly titleBar: Locator;
|
|
13
|
+
readonly createNewDropdown: Locator;
|
|
14
|
+
readonly inlineNameInput: Locator;
|
|
15
|
+
constructor(page: Page);
|
|
16
|
+
private pageReady;
|
|
17
|
+
waitForProcessApplication(timeout?: number): Promise<void>;
|
|
18
|
+
clickCreateProcessApplicationButton(): Promise<void>;
|
|
19
|
+
clickCreateProcessApplicationOption(): Promise<void>;
|
|
20
|
+
nameNewProcessApplication(name: string): Promise<void>;
|
|
21
|
+
openByName(name: string): Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
export { ProcessApplicationPage };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProcessApplicationPage = void 0;
|
|
4
|
+
const test_1 = require("@playwright/test");
|
|
5
|
+
const submitModalWithRetry_1 = require("../../utils/assertionHelpers/submitModalWithRetry");
|
|
6
|
+
// Since camunda/camunda-hub#25831 a process application is a first-class
|
|
7
|
+
// container rather than a folder, and a workspace root ("project" in today's
|
|
8
|
+
// UI) holds nothing but process applications and IDP applications. Every file
|
|
9
|
+
// and folder this suite creates therefore has to live inside a process
|
|
10
|
+
// application. This page object owns that container's surface only; entering
|
|
11
|
+
// and leaving it is driven from ModelerHomePage so the ~150 existing spec call
|
|
12
|
+
// sites keep working unchanged.
|
|
13
|
+
class ProcessApplicationPage {
|
|
14
|
+
page;
|
|
15
|
+
// Empty workspace root: a plain primary button rendered next to the "Create
|
|
16
|
+
// new" menu (hub's EmptyStateActionButtons).
|
|
17
|
+
createProcessApplicationButton;
|
|
18
|
+
// Non-empty root: the item inside the "Create new" menu. Hub passes
|
|
19
|
+
// hideProcessApplication at workspace level, so this is the fallback rather
|
|
20
|
+
// than the primary path -- its own unit test asserts the item is absent
|
|
21
|
+
// there. Kept because the Hub PR is still moving this surface.
|
|
22
|
+
createProcessApplicationOption;
|
|
23
|
+
creationDialog;
|
|
24
|
+
nameInput;
|
|
25
|
+
submitButton;
|
|
26
|
+
cancelButton;
|
|
27
|
+
breadcrumb;
|
|
28
|
+
folderExplorer;
|
|
29
|
+
titleBar;
|
|
30
|
+
createNewDropdown;
|
|
31
|
+
inlineNameInput;
|
|
32
|
+
constructor(page) {
|
|
33
|
+
this.page = page;
|
|
34
|
+
// .first() defensively only: hub renders exactly one of these today, in the
|
|
35
|
+
// workspace-root empty state. A future second placement should not turn
|
|
36
|
+
// every PA-creating test into a strict-mode violation.
|
|
37
|
+
this.createProcessApplicationButton = page
|
|
38
|
+
.getByRole('button', { name: 'Create process application' })
|
|
39
|
+
.first();
|
|
40
|
+
this.createProcessApplicationOption = page.locator('[data-test="create-process-application"]');
|
|
41
|
+
this.creationDialog = page.getByRole('dialog', {
|
|
42
|
+
name: 'Create a process application',
|
|
43
|
+
});
|
|
44
|
+
// Deliberately scoped to the dialog: ModelerCreatePage owns an unscoped
|
|
45
|
+
// getByLabel('Name', {exact: true}) for the properties panel, which would
|
|
46
|
+
// resolve to two elements while the creation modal is open.
|
|
47
|
+
this.nameInput = this.creationDialog.getByLabel('Name', { exact: true });
|
|
48
|
+
this.submitButton = this.creationDialog.getByRole('button', {
|
|
49
|
+
name: 'Create',
|
|
50
|
+
exact: true,
|
|
51
|
+
});
|
|
52
|
+
this.cancelButton = this.creationDialog.getByRole('button', {
|
|
53
|
+
name: 'Cancel',
|
|
54
|
+
exact: true,
|
|
55
|
+
});
|
|
56
|
+
this.breadcrumb = page.locator('[data-test="breadcrumb-process-application-menu"]');
|
|
57
|
+
// The Design System shell renames this region "Resources"; the Carbon shell
|
|
58
|
+
// calls it "Folder explorer". Both hold the resource table and its toolbar,
|
|
59
|
+
// so matching either keeps createNewDropdown below correctly scoped.
|
|
60
|
+
this.folderExplorer = page
|
|
61
|
+
.getByRole('region', { name: 'Folder explorer' })
|
|
62
|
+
.or(page.getByRole('region', { name: 'Resources' }))
|
|
63
|
+
.first();
|
|
64
|
+
// Design System proof that we are on a process application page: the
|
|
65
|
+
// Carbon-era breadcrumb hook is gone under that shell, the same way
|
|
66
|
+
// breadcrumb-project is.
|
|
67
|
+
this.titleBar = page.locator('[data-test="process-application-title-bar"]');
|
|
68
|
+
// The process application page renders more than one diagram-dropdown
|
|
69
|
+
// (hub's own unit tests reach for it with getAllByTestId), so the dropdown
|
|
70
|
+
// has to be resolved inside the folder explorer rather than page-wide.
|
|
71
|
+
this.createNewDropdown = this.folderExplorer
|
|
72
|
+
.locator('[data-test="diagram-dropdown"]')
|
|
73
|
+
.first();
|
|
74
|
+
this.inlineNameInput = page.locator('[data-test="editable-input"]');
|
|
75
|
+
}
|
|
76
|
+
// Any one of the title bar, the resource region or the breadcrumb proves we
|
|
77
|
+
// are on the process application page. Three branches because the Design
|
|
78
|
+
// System and Carbon shells expose different subsets: only the title bar is
|
|
79
|
+
// present under both. .first() because several match once it has rendered.
|
|
80
|
+
pageReady() {
|
|
81
|
+
return this.titleBar.or(this.folderExplorer).or(this.breadcrumb).first();
|
|
82
|
+
}
|
|
83
|
+
async waitForProcessApplication(timeout = 90000) {
|
|
84
|
+
await (0, test_1.expect)(this.pageReady()).toBeVisible({ timeout });
|
|
85
|
+
}
|
|
86
|
+
async clickCreateProcessApplicationButton() {
|
|
87
|
+
await (0, test_1.expect)(this.createProcessApplicationButton).toBeVisible({
|
|
88
|
+
timeout: 60000,
|
|
89
|
+
});
|
|
90
|
+
await this.createProcessApplicationButton.click({ timeout: 60000 });
|
|
91
|
+
}
|
|
92
|
+
async clickCreateProcessApplicationOption() {
|
|
93
|
+
await (0, test_1.expect)(this.createProcessApplicationOption).toBeVisible({
|
|
94
|
+
timeout: 60000,
|
|
95
|
+
});
|
|
96
|
+
await this.createProcessApplicationOption.click({ timeout: 60000 });
|
|
97
|
+
}
|
|
98
|
+
// Hub creates a process application through a modal today. It used an inline
|
|
99
|
+
// editable title before, and #27593 is still moving this surface, so the
|
|
100
|
+
// inline path is kept as a fallback — this is the one method that has to
|
|
101
|
+
// change if naming moves back inline.
|
|
102
|
+
async nameNewProcessApplication(name) {
|
|
103
|
+
const isModal = await this.creationDialog
|
|
104
|
+
.waitFor({ state: 'visible', timeout: 15000 })
|
|
105
|
+
.then(() => true)
|
|
106
|
+
.catch(() => false);
|
|
107
|
+
if (isModal) {
|
|
108
|
+
await this.nameInput.click({ timeout: 30000 });
|
|
109
|
+
await this.nameInput.fill(name);
|
|
110
|
+
await (0, test_1.expect)(this.nameInput).toHaveValue(name, { timeout: 10000 });
|
|
111
|
+
await (0, submitModalWithRetry_1.submitModalWithRetry)(this.submitButton, this.creationDialog);
|
|
112
|
+
await this.waitForProcessApplication();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
await (0, test_1.expect)(this.inlineNameInput).toBeVisible({ timeout: 30000 });
|
|
116
|
+
await this.inlineNameInput.click({ timeout: 60000 });
|
|
117
|
+
await this.inlineNameInput.fill(name);
|
|
118
|
+
await this.inlineNameInput.press('Enter');
|
|
119
|
+
await this.waitForProcessApplication();
|
|
120
|
+
}
|
|
121
|
+
async openByName(name) {
|
|
122
|
+
const processApplication = this.page
|
|
123
|
+
.getByRole('row')
|
|
124
|
+
.filter({ hasText: name })
|
|
125
|
+
.getByTitle(name)
|
|
126
|
+
.first();
|
|
127
|
+
await (0, test_1.expect)(processApplication).toBeVisible({ timeout: 90000 });
|
|
128
|
+
await processApplication.click({ timeout: 60000 });
|
|
129
|
+
await this.waitForProcessApplication();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.ProcessApplicationPage = ProcessApplicationPage;
|
|
@@ -8,9 +8,18 @@ class SettingsPage {
|
|
|
8
8
|
openUserSidebarButton;
|
|
9
9
|
constructor(page) {
|
|
10
10
|
this.page = page;
|
|
11
|
-
this.openSettingsButton = page
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
this.openSettingsButton = page
|
|
12
|
+
.getByRole('button', { name: /^User menu/ })
|
|
13
|
+
.or(page.getByLabel('Open Settings'))
|
|
14
|
+
.first();
|
|
15
|
+
this.openUserSidebarButton = page
|
|
16
|
+
.getByRole('button', { name: /^User menu/ })
|
|
17
|
+
.or(page.getByLabel('Open User Sidebar'))
|
|
18
|
+
.first();
|
|
19
|
+
this.logoutButton = page
|
|
20
|
+
.getByRole('menuitem', { name: /log out/i })
|
|
21
|
+
.or(page.getByRole('button', { name: 'Log out' }))
|
|
22
|
+
.first();
|
|
14
23
|
}
|
|
15
24
|
async clickOpenSettingsButton() {
|
|
16
25
|
await this.openSettingsButton.click({ timeout: 120000 });
|
|
@@ -416,6 +416,14 @@ async function modelAndRunConnectorsTimerEventDiagram(modelerCreatePage, modeler
|
|
|
416
416
|
timeout: 60000,
|
|
417
417
|
});
|
|
418
418
|
await connectorMarketplacePage.downloadConnectorToProject();
|
|
419
|
+
// Both lookups are container-relative: clickProjectBreadcrumb() returns to
|
|
420
|
+
// this test's process application, which is where the uploaded diagram
|
|
421
|
+
// lives. The downloaded element template is the open question -- hub
|
|
422
|
+
// publishes element templates to the workspace, but the marketplace
|
|
423
|
+
// download is initiated from inside the container, so it should land there.
|
|
424
|
+
// If a trace shows the template at workspace root instead, the first of
|
|
425
|
+
// these two calls becomes clickWorkspaceBreadcrumb() followed by
|
|
426
|
+
// returnToResourceContainer() before the diagram is reopened.
|
|
419
427
|
await modelerHomePage.clickProjectBreadcrumb();
|
|
420
428
|
await modelerHomePage.clickProcessDiagram('REST Outbound Connector');
|
|
421
429
|
await connectorTemplatePage.publishConnector();
|
|
@@ -125,7 +125,7 @@ _8_10_1.test.describe('User Roles User Flow', () => {
|
|
|
125
125
|
await modelerCreatePage.clickAppendEndEventButton();
|
|
126
126
|
await (0, sleep_1.sleep)(20000);
|
|
127
127
|
await modelerCreatePage.runProcessInstance(clusterName);
|
|
128
|
-
await (0, test_1.expect)(page.getByText(
|
|
128
|
+
await (0, test_1.expect)(page.getByText(/The (diagram|application) failed to deploy & run/)).toBeVisible({ timeout: 60000 });
|
|
129
129
|
await modelerCreatePage.clickCloseButton();
|
|
130
130
|
});
|
|
131
131
|
});
|
|
@@ -216,7 +216,7 @@ _8_10_1.test.describe('User Roles User Flow', () => {
|
|
|
216
216
|
await modelerCreatePage.clickAppendEndEventButton();
|
|
217
217
|
await (0, sleep_1.sleep)(20000);
|
|
218
218
|
await modelerCreatePage.runProcessInstance(clusterName, '', {}, '', false);
|
|
219
|
-
await (0, test_1.expect)(page.getByText(
|
|
219
|
+
await (0, test_1.expect)(page.getByText(/The (diagram|application) failed to deploy & run/)).toBeVisible({ timeout: 60000 });
|
|
220
220
|
await modelerCreatePage.clickCloseButton();
|
|
221
221
|
});
|
|
222
222
|
});
|
|
@@ -312,7 +312,7 @@ _8_10_1.test.describe('User Roles User Flow', () => {
|
|
|
312
312
|
await modelerCreatePage.clickAppendEndEventButton();
|
|
313
313
|
await (0, sleep_1.sleep)(20000);
|
|
314
314
|
await modelerCreatePage.runProcessInstance(clusterName);
|
|
315
|
-
await (0, test_1.expect)(page.getByText(
|
|
315
|
+
await (0, test_1.expect)(page.getByText(/The (diagram|application) failed to deploy & run/)).not.toBeVisible({ timeout: 60000 });
|
|
316
316
|
await (0, test_1.expect)(modelerCreatePage.viewProcessInstanceLink).toBeVisible({
|
|
317
317
|
timeout: 120000,
|
|
318
318
|
});
|
|
@@ -95,7 +95,9 @@ _8_10_1.test.describe('IDP User Flow Tests', () => {
|
|
|
95
95
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
96
96
|
});
|
|
97
97
|
await _8_10_1.test.step('Add an IDP application to the project', async () => {
|
|
98
|
-
|
|
98
|
+
// Workspace-level menu: an IDP application can only be created at
|
|
99
|
+
// workspace root, never inside a process application.
|
|
100
|
+
await modelerHomePage.clickWorkspaceDiagramTypeDropdown();
|
|
99
101
|
await modelerHomePage.clickIdpApplicationTemplateOption();
|
|
100
102
|
});
|
|
101
103
|
await _8_10_1.test.step('Creates a document extraction template', async () => {
|
|
@@ -168,7 +170,9 @@ _8_10_1.test.describe('IDP User Flow Tests', () => {
|
|
|
168
170
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
169
171
|
});
|
|
170
172
|
await _8_10_1.test.step('Add an IDP application to the project', async () => {
|
|
171
|
-
|
|
173
|
+
// Workspace-level menu: an IDP application can only be created at
|
|
174
|
+
// workspace root, never inside a process application.
|
|
175
|
+
await modelerHomePage.clickWorkspaceDiagramTypeDropdown();
|
|
172
176
|
await modelerHomePage.clickIdpApplicationTemplateOption();
|
|
173
177
|
});
|
|
174
178
|
await _8_10_1.test.step('Creates a document extraction template', async () => {
|
|
@@ -249,7 +253,9 @@ _8_10_1.test.describe('IDP User Flow Tests', () => {
|
|
|
249
253
|
await modelerHomePage.clickCrossComponentProjectFolder();
|
|
250
254
|
});
|
|
251
255
|
await _8_10_1.test.step('Add an IDP application to the project', async () => {
|
|
252
|
-
|
|
256
|
+
// Workspace-level menu: an IDP application can only be created at
|
|
257
|
+
// workspace root, never inside a process application.
|
|
258
|
+
await modelerHomePage.clickWorkspaceDiagramTypeDropdown();
|
|
253
259
|
await modelerHomePage.clickIdpApplicationTemplateOption();
|
|
254
260
|
});
|
|
255
261
|
await _8_10_1.test.step('Creates a classification template', async () => {
|