@camunda/e2e-test-suite 0.0.26 → 0.0.28
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.7/ClusterPage.js +1 -1
- package/dist/pages/8.7/ClusterSecretsPage.d.ts +9 -2
- package/dist/pages/8.7/ClusterSecretsPage.js +56 -28
- package/dist/pages/8.8/ClusterSecretsPage.d.ts +13 -0
- package/dist/pages/8.8/ClusterSecretsPage.js +47 -3
- package/dist/pages/8.9/ClusterPage.js +1 -0
- package/dist/pages/SM-8.6/LoginPage.d.ts +0 -7
- package/dist/pages/SM-8.6/LoginPage.js +8 -81
- package/dist/pages/SM-8.7/KeycloakAdminPage.js +1 -11
- package/dist/pages/SM-8.7/LoginPage.d.ts +0 -8
- package/dist/pages/SM-8.7/LoginPage.js +9 -78
- package/dist/pages/SM-8.7/NavigationPage.js +1 -4
- package/dist/pages/SM-8.9/LoginPage.d.ts +0 -2
- package/dist/pages/SM-8.9/LoginPage.js +16 -48
- package/dist/tests/8.7/connectors-user-flows.spec.js +79 -54
- package/dist/tests/8.7/idp-user-flows.spec.js +4 -4
- package/dist/tests/8.7/test-setup.spec.js +2 -2
- package/dist/tests/8.8/idp-user-flows.spec.js +54 -23
- package/dist/tests/8.8/test-setup.spec.js +6 -112
- package/dist/tests/8.9/test-setup.spec.js +1 -1
- package/dist/utils/connectorSecrets.d.ts +38 -0
- package/dist/utils/connectorSecrets.js +116 -0
- package/package.json +1 -1
|
@@ -48,7 +48,7 @@ class ClusterPage {
|
|
|
48
48
|
this.clusterGenerationCompleteMessage = page.getByText('Test Cluster is healthy and ready to use');
|
|
49
49
|
this.clustersBreadcrumb = page
|
|
50
50
|
.getByLabel('Breadcrumb')
|
|
51
|
-
.
|
|
51
|
+
.getByText('Clusters', { exact: true });
|
|
52
52
|
this.deleteClusterButton = page.getByRole('button', { name: 'Delete' });
|
|
53
53
|
this.confirmDeleteInput = page.getByRole('textbox', {
|
|
54
54
|
name: 'Type the word DELETE to confirm',
|
|
@@ -5,14 +5,21 @@ declare class ClusterSecretsPage {
|
|
|
5
5
|
readonly keyInput: Locator;
|
|
6
6
|
readonly valueInput: Locator;
|
|
7
7
|
readonly createButton: Locator;
|
|
8
|
-
readonly
|
|
8
|
+
readonly optionsButton: Locator;
|
|
9
9
|
readonly deleteConnectorSecretButton: Locator;
|
|
10
10
|
readonly deleteConnectorSecretSubButton: Locator;
|
|
11
11
|
readonly dialog: Locator;
|
|
12
12
|
readonly connectorSecretsTable: Locator;
|
|
13
|
+
readonly clusterBanner: Locator;
|
|
14
|
+
readonly clusterLink: (name: string) => Locator;
|
|
15
|
+
readonly clusterSecretTab: Locator;
|
|
16
|
+
readonly confirmDeleteInput: Locator;
|
|
13
17
|
constructor(page: Page);
|
|
14
18
|
deleteConnectorSecretsIfExist(): Promise<void>;
|
|
15
|
-
clickCreateNewSecretButton(): Promise<void>;
|
|
19
|
+
clickCreateNewSecretButton(clusterName: string): Promise<void>;
|
|
20
|
+
clickClusterBanner(): Promise<void>;
|
|
21
|
+
clickCluster(name: string): Promise<void>;
|
|
22
|
+
createNewSecret(cluster: string, key: string, value: string): Promise<void>;
|
|
16
23
|
clickKeyInput(): Promise<void>;
|
|
17
24
|
fillKeyInput(key: string): Promise<void>;
|
|
18
25
|
clickValueInput(): Promise<void>;
|
|
@@ -8,11 +8,15 @@ class ClusterSecretsPage {
|
|
|
8
8
|
keyInput;
|
|
9
9
|
valueInput;
|
|
10
10
|
createButton;
|
|
11
|
-
|
|
11
|
+
optionsButton;
|
|
12
12
|
deleteConnectorSecretButton;
|
|
13
13
|
deleteConnectorSecretSubButton;
|
|
14
14
|
dialog;
|
|
15
15
|
connectorSecretsTable;
|
|
16
|
+
clusterBanner;
|
|
17
|
+
clusterLink;
|
|
18
|
+
clusterSecretTab;
|
|
19
|
+
confirmDeleteInput;
|
|
16
20
|
constructor(page) {
|
|
17
21
|
this.page = page;
|
|
18
22
|
this.createNewSecretButton = page.getByRole('button', {
|
|
@@ -24,20 +28,31 @@ class ClusterSecretsPage {
|
|
|
24
28
|
this.connectorSecretsTable = page.getByRole('table', {
|
|
25
29
|
name: 'Connector secrets',
|
|
26
30
|
});
|
|
27
|
-
this.
|
|
28
|
-
name: '
|
|
29
|
-
|
|
31
|
+
this.optionsButton = page
|
|
32
|
+
.getByRole('cell', { name: 'Options' })
|
|
33
|
+
.getByRole('button');
|
|
30
34
|
this.deleteConnectorSecretButton = page.getByRole('menuitem', {
|
|
31
|
-
name: '
|
|
35
|
+
name: 'Delete',
|
|
36
|
+
exact: true,
|
|
32
37
|
});
|
|
33
38
|
this.deleteConnectorSecretSubButton = page.getByRole('button', {
|
|
34
39
|
name: 'danger Delete',
|
|
35
40
|
});
|
|
36
41
|
this.dialog = page.getByRole('dialog');
|
|
42
|
+
this.clusterBanner = this.page
|
|
43
|
+
.getByRole('banner')
|
|
44
|
+
.getByRole('link', { name: 'Clusters' });
|
|
45
|
+
this.clusterLink = (name) => page.getByRole('link', { name: name });
|
|
46
|
+
this.clusterSecretTab = this.page.getByRole('tab', {
|
|
47
|
+
name: 'Connector Secrets',
|
|
48
|
+
});
|
|
49
|
+
this.confirmDeleteInput = page.getByRole('textbox', {
|
|
50
|
+
name: 'Type the word DELETE to confirm',
|
|
51
|
+
});
|
|
37
52
|
}
|
|
38
53
|
async deleteConnectorSecretsIfExist() {
|
|
39
54
|
try {
|
|
40
|
-
await (0, test_1.expect)(this.
|
|
55
|
+
await (0, test_1.expect)(this.optionsButton.first()).toBeVisible({
|
|
41
56
|
timeout: 10000,
|
|
42
57
|
});
|
|
43
58
|
}
|
|
@@ -45,11 +60,11 @@ class ClusterSecretsPage {
|
|
|
45
60
|
return; //No Connector Secrets found in the list
|
|
46
61
|
}
|
|
47
62
|
try {
|
|
48
|
-
let
|
|
49
|
-
while (
|
|
50
|
-
const
|
|
51
|
-
if (await
|
|
52
|
-
await
|
|
63
|
+
let options = await this.optionsButton.all();
|
|
64
|
+
while (options.length > 0) {
|
|
65
|
+
const optionButton = options[0];
|
|
66
|
+
if (await optionButton.isVisible()) {
|
|
67
|
+
await optionButton.click({ timeout: 60000 });
|
|
53
68
|
await this.deleteConnectorSecretButton.click({ timeout: 60000 });
|
|
54
69
|
await (0, test_1.expect)(this.dialog).toBeVisible({ timeout: 40000 });
|
|
55
70
|
await this.deleteConnectorSecretSubButton.click();
|
|
@@ -59,9 +74,9 @@ class ClusterSecretsPage {
|
|
|
59
74
|
}
|
|
60
75
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
61
76
|
await sleep(3000);
|
|
62
|
-
|
|
77
|
+
options = await this.optionsButton.all();
|
|
63
78
|
}
|
|
64
|
-
await (0, test_1.expect)(this.
|
|
79
|
+
await (0, test_1.expect)(this.optionsButton).not.toBeVisible({
|
|
65
80
|
timeout: 30000,
|
|
66
81
|
});
|
|
67
82
|
}
|
|
@@ -69,26 +84,39 @@ class ClusterSecretsPage {
|
|
|
69
84
|
console.error('Error during Connector Secrets deletion: ', error);
|
|
70
85
|
}
|
|
71
86
|
}
|
|
72
|
-
async clickCreateNewSecretButton() {
|
|
87
|
+
async clickCreateNewSecretButton(clusterName) {
|
|
73
88
|
try {
|
|
74
|
-
await this.createNewSecretButton.
|
|
89
|
+
await (0, test_1.expect)(this.createNewSecretButton).toBeVisible({
|
|
90
|
+
timeout: 30000,
|
|
91
|
+
});
|
|
92
|
+
await this.createNewSecretButton.click({ timeout: 30000 });
|
|
75
93
|
}
|
|
76
94
|
catch (error) {
|
|
77
|
-
await this.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
await this.page
|
|
82
|
-
.getByRole('link', { name: 'Test Cluster' })
|
|
83
|
-
.click({ timeout: 60000 });
|
|
84
|
-
await this.page
|
|
85
|
-
.getByRole('tab', {
|
|
86
|
-
name: 'Connector Secrets',
|
|
87
|
-
})
|
|
88
|
-
.click({ timeout: 60000 });
|
|
89
|
-
await this.createNewSecretButton.click({ timeout: 60000 });
|
|
95
|
+
await this.clickClusterBanner();
|
|
96
|
+
await this.clickCluster(clusterName);
|
|
97
|
+
await this.clusterSecretTab.click({ timeout: 30000 });
|
|
98
|
+
await this.createNewSecretButton.click({ timeout: 30000 });
|
|
90
99
|
}
|
|
91
100
|
}
|
|
101
|
+
async clickClusterBanner() {
|
|
102
|
+
await (0, test_1.expect)(this.clusterBanner).toBeVisible({ timeout: 30000 });
|
|
103
|
+
await this.clusterBanner.click({ timeout: 60000 });
|
|
104
|
+
}
|
|
105
|
+
async clickCluster(name) {
|
|
106
|
+
await (0, test_1.expect)(this.clusterLink(name)).toBeVisible({ timeout: 30000 });
|
|
107
|
+
await this.clusterLink(name).click();
|
|
108
|
+
}
|
|
109
|
+
async createNewSecret(cluster, key, value) {
|
|
110
|
+
await this.clickCreateNewSecretButton(cluster);
|
|
111
|
+
await this.clickKeyInput();
|
|
112
|
+
await this.fillKeyInput(key);
|
|
113
|
+
await this.clickValueInput();
|
|
114
|
+
await this.fillValueInput(value);
|
|
115
|
+
await this.clickCreateButton();
|
|
116
|
+
await (0, test_1.expect)(this.page.getByText('Creating...')).not.toBeVisible({
|
|
117
|
+
timeout: 60000,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
92
120
|
async clickKeyInput() {
|
|
93
121
|
await this.keyInput.click();
|
|
94
122
|
}
|
|
@@ -9,6 +9,11 @@ declare class ClusterSecretsPage {
|
|
|
9
9
|
readonly deleteConnectorSecretButton: Locator;
|
|
10
10
|
readonly deleteConnectorSecretSubButton: Locator;
|
|
11
11
|
readonly dialog: Locator;
|
|
12
|
+
readonly importButton: Locator;
|
|
13
|
+
readonly fromFileButton: Locator;
|
|
14
|
+
readonly bulkImportTextArea: Locator;
|
|
15
|
+
readonly dialogImportButton: Locator;
|
|
16
|
+
readonly secretsSearchBox: Locator;
|
|
12
17
|
constructor(page: Page);
|
|
13
18
|
deleteConnectorSecretsIfExist(): Promise<void>;
|
|
14
19
|
clickCreateNewSecretButton(): Promise<void>;
|
|
@@ -22,5 +27,13 @@ declare class ClusterSecretsPage {
|
|
|
22
27
|
name: string;
|
|
23
28
|
value: string;
|
|
24
29
|
}[]): Promise<void>;
|
|
30
|
+
assertSecretsOrCreate(secrets: {
|
|
31
|
+
name: string;
|
|
32
|
+
value: string;
|
|
33
|
+
}[]): Promise<void>;
|
|
34
|
+
bulkImportSecrets(secrets: {
|
|
35
|
+
name: string;
|
|
36
|
+
value: string;
|
|
37
|
+
}[]): Promise<void>;
|
|
25
38
|
}
|
|
26
39
|
export { ClusterSecretsPage };
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ClusterSecretsPage = void 0;
|
|
4
4
|
const test_1 = require("@playwright/test");
|
|
5
5
|
const sleep_1 = require("../../utils/sleep");
|
|
6
|
+
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
6
7
|
class ClusterSecretsPage {
|
|
7
8
|
page;
|
|
8
9
|
createNewSecretButton;
|
|
@@ -13,6 +14,11 @@ class ClusterSecretsPage {
|
|
|
13
14
|
deleteConnectorSecretButton;
|
|
14
15
|
deleteConnectorSecretSubButton;
|
|
15
16
|
dialog;
|
|
17
|
+
importButton;
|
|
18
|
+
fromFileButton;
|
|
19
|
+
bulkImportTextArea;
|
|
20
|
+
dialogImportButton;
|
|
21
|
+
secretsSearchBox;
|
|
16
22
|
constructor(page) {
|
|
17
23
|
this.page = page;
|
|
18
24
|
this.createNewSecretButton = page.getByRole('button', {
|
|
@@ -32,6 +38,13 @@ class ClusterSecretsPage {
|
|
|
32
38
|
name: 'danger Delete',
|
|
33
39
|
});
|
|
34
40
|
this.dialog = page.getByRole('dialog');
|
|
41
|
+
this.importButton = page.getByRole('button', { name: 'Import', exact: true });
|
|
42
|
+
this.fromFileButton = page.getByText('from File', { exact: true });
|
|
43
|
+
this.bulkImportTextArea = page.locator('[id="env-content-input-secrets-bulk-import"]');
|
|
44
|
+
this.dialogImportButton = this.page
|
|
45
|
+
.getByRole('dialog')
|
|
46
|
+
.getByRole('button', { name: 'Import', exact: true });
|
|
47
|
+
this.secretsSearchBox = page.getByRole('searchbox', { name: 'Filter table' });
|
|
35
48
|
}
|
|
36
49
|
async deleteConnectorSecretsIfExist() {
|
|
37
50
|
try {
|
|
@@ -141,15 +154,46 @@ class ClusterSecretsPage {
|
|
|
141
154
|
});
|
|
142
155
|
}
|
|
143
156
|
async createSetOfSecrets(secrets) {
|
|
157
|
+
await this.bulkImportSecrets(secrets);
|
|
158
|
+
await this.assertSecretsOrCreate(secrets);
|
|
159
|
+
}
|
|
160
|
+
async assertSecretsOrCreate(secrets) {
|
|
144
161
|
for (const secret of secrets) {
|
|
145
162
|
try {
|
|
146
|
-
|
|
147
|
-
await this.
|
|
163
|
+
await (0, test_1.expect)(this.secretsSearchBox).toBeVisible();
|
|
164
|
+
await this.secretsSearchBox.click();
|
|
165
|
+
await this.secretsSearchBox.fill(secret.name);
|
|
166
|
+
const row = this.page.getByRole('row', {
|
|
167
|
+
name: new RegExp(`^${secret.name}\\b`, 'i'),
|
|
168
|
+
});
|
|
169
|
+
await (0, test_1.expect)(row).toBeVisible({ timeout: 5000 });
|
|
148
170
|
}
|
|
149
171
|
catch (error) {
|
|
150
|
-
|
|
172
|
+
console.error(`Creating secret for ${secret.name}`);
|
|
173
|
+
await this.createNewSecret(secret.name, secret.value);
|
|
151
174
|
}
|
|
152
175
|
}
|
|
153
176
|
}
|
|
177
|
+
async bulkImportSecrets(secrets) {
|
|
178
|
+
const mapped = secrets
|
|
179
|
+
.map((secret) => `${secret.name}=${secret.value}`)
|
|
180
|
+
.join('\n');
|
|
181
|
+
await this.importButton.click();
|
|
182
|
+
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(this.page, this.fromFileButton, {
|
|
183
|
+
postAction: async () => {
|
|
184
|
+
await this.importButton.click();
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
await this.fromFileButton.click();
|
|
188
|
+
await this.bulkImportTextArea.click();
|
|
189
|
+
await this.bulkImportTextArea.fill(mapped);
|
|
190
|
+
await this.dialogImportButton.click();
|
|
191
|
+
await (0, test_1.expect)(this.page.getByText('Importing secrets...')).not.toBeVisible({
|
|
192
|
+
timeout: 60000,
|
|
193
|
+
});
|
|
194
|
+
await (0, test_1.expect)(this.createNewSecretButton).toBeVisible({
|
|
195
|
+
timeout: 60000,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
154
198
|
}
|
|
155
199
|
exports.ClusterSecretsPage = ClusterSecretsPage;
|
|
@@ -96,6 +96,7 @@ class ClusterPage {
|
|
|
96
96
|
.click({ timeout: 60000 });
|
|
97
97
|
}
|
|
98
98
|
async deleteCluster(name) {
|
|
99
|
+
await this.page.waitForTimeout(1000);
|
|
99
100
|
const clusterInstance = this.cluster(name).first();
|
|
100
101
|
if ((await clusterInstance.count()) <= 0) {
|
|
101
102
|
console.log(`No clusters found with name ${name}, skipping deletion.`);
|
|
@@ -4,14 +4,7 @@ declare class LoginPage {
|
|
|
4
4
|
readonly usernameInput: Locator;
|
|
5
5
|
readonly passwordInput: Locator;
|
|
6
6
|
readonly loginButton: Locator;
|
|
7
|
-
readonly coreUsernameInput: Locator;
|
|
8
|
-
readonly corePasswordInput: Locator;
|
|
9
|
-
readonly coreLoginButton: Locator;
|
|
10
|
-
readonly keycloakBanner: Locator;
|
|
11
|
-
private useCore;
|
|
12
|
-
private useKeycloak;
|
|
13
7
|
constructor(page: Page);
|
|
14
|
-
detectLoginForm(): Promise<void>;
|
|
15
8
|
fillUsername(username: string): Promise<void>;
|
|
16
9
|
clickUsername(): Promise<void>;
|
|
17
10
|
fillPassword(password: string): Promise<void>;
|
|
@@ -7,109 +7,35 @@ class LoginPage {
|
|
|
7
7
|
usernameInput;
|
|
8
8
|
passwordInput;
|
|
9
9
|
loginButton;
|
|
10
|
-
coreUsernameInput;
|
|
11
|
-
corePasswordInput;
|
|
12
|
-
coreLoginButton;
|
|
13
|
-
keycloakBanner;
|
|
14
|
-
useCore = false;
|
|
15
|
-
useKeycloak = false;
|
|
16
10
|
constructor(page) {
|
|
17
11
|
this.page = page;
|
|
18
12
|
this.usernameInput = page.getByLabel('Username or email');
|
|
19
13
|
this.passwordInput = page.getByLabel('Password');
|
|
20
14
|
this.loginButton = page.getByRole('button', { name: 'Log in' });
|
|
21
|
-
this.coreUsernameInput = page.getByPlaceholder('Username');
|
|
22
|
-
this.corePasswordInput = page.getByPlaceholder('Password');
|
|
23
|
-
this.coreLoginButton = page.getByRole('button', { name: 'Login' });
|
|
24
|
-
this.keycloakBanner = page.locator('body#keycloak-bg[data-page-id="login-login"]');
|
|
25
|
-
}
|
|
26
|
-
// Race logic: call before interacting
|
|
27
|
-
async detectLoginForm() {
|
|
28
|
-
const winner = await Promise.race([
|
|
29
|
-
this.usernameInput.waitFor({ state: 'visible' }).then(() => 'default'),
|
|
30
|
-
this.coreUsernameInput.waitFor({ state: 'visible' }).then(() => 'core'),
|
|
31
|
-
this.keycloakBanner.waitFor({ state: 'visible' }).then(() => 'keycloak'),
|
|
32
|
-
]);
|
|
33
|
-
this.useCore = winner === 'core';
|
|
34
|
-
this.useKeycloak = winner === 'keycloak';
|
|
35
15
|
}
|
|
36
16
|
async fillUsername(username) {
|
|
37
|
-
|
|
38
|
-
await this.page.fill('#username', username);
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
await (this.useCore
|
|
42
|
-
? this.coreUsernameInput.fill(username)
|
|
43
|
-
: this.usernameInput.fill(username));
|
|
44
|
-
}
|
|
17
|
+
await this.usernameInput.fill(username);
|
|
45
18
|
}
|
|
46
19
|
async clickUsername() {
|
|
47
|
-
|
|
48
|
-
await this.page.click('#username');
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
await (this.useCore
|
|
52
|
-
? this.coreUsernameInput.click({ timeout: 60000 })
|
|
53
|
-
: this.usernameInput.click({ timeout: 60000 }));
|
|
54
|
-
}
|
|
20
|
+
await this.usernameInput.click({ timeout: 60000 });
|
|
55
21
|
}
|
|
56
22
|
async fillPassword(password) {
|
|
57
|
-
|
|
58
|
-
await this.page.fill('#password', password);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
await (this.useCore
|
|
62
|
-
? this.corePasswordInput.fill(password)
|
|
63
|
-
: this.passwordInput.fill(password));
|
|
64
|
-
}
|
|
23
|
+
await this.passwordInput.fill(password);
|
|
65
24
|
}
|
|
66
25
|
async clickLoginButton() {
|
|
67
|
-
|
|
68
|
-
await this.page.click('button[type="submit"]');
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
await (this.useCore
|
|
72
|
-
? this.coreLoginButton.click({ timeout: 60000 })
|
|
73
|
-
: this.loginButton.click({ timeout: 60000 }));
|
|
74
|
-
}
|
|
26
|
+
await this.loginButton.click({ timeout: 60000 });
|
|
75
27
|
}
|
|
76
28
|
async login(username, password) {
|
|
77
|
-
|
|
78
|
-
await this.detectLoginForm();
|
|
79
|
-
if (await this.page
|
|
80
|
-
.locator('body#keycloak-bg[data-page-id="login-login"]')
|
|
81
|
-
.isVisible()) {
|
|
82
|
-
await (0, test_1.expect)(this.keycloakBanner).toBeVisible({ timeout: 15000 });
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
const activeLoginButton = this.useCore
|
|
86
|
-
? this.coreLoginButton
|
|
87
|
-
: this.loginButton;
|
|
88
|
-
await (0, test_1.expect)(activeLoginButton).toBeVisible({ timeout: 15000 });
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
29
|
+
await (0, test_1.expect)(this.usernameInput).toBeVisible({ timeout: 180000 });
|
|
94
30
|
await this.clickUsername();
|
|
95
31
|
await this.fillUsername(username);
|
|
96
32
|
await this.fillPassword(password);
|
|
33
|
+
await (0, test_1.expect)(this.loginButton).toBeVisible({ timeout: 120000 });
|
|
97
34
|
await this.clickLoginButton();
|
|
98
35
|
}
|
|
99
36
|
async loginAfterPermissionsReadded(username, password) {
|
|
100
37
|
try {
|
|
101
|
-
await this.
|
|
102
|
-
if (await this.page
|
|
103
|
-
.locator('body#keycloak-bg[data-page-id="login-login"]')
|
|
104
|
-
.isVisible()) {
|
|
105
|
-
await (0, test_1.expect)(this.keycloakBanner).toBeVisible({ timeout: 15000 });
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
const activeLoginButton = this.useCore
|
|
109
|
-
? this.coreLoginButton
|
|
110
|
-
: this.loginButton;
|
|
111
|
-
await (0, test_1.expect)(activeLoginButton).toBeVisible({ timeout: 15000 });
|
|
112
|
-
}
|
|
38
|
+
await (0, test_1.expect)(this.usernameInput).toBeVisible({ timeout: 15000 });
|
|
113
39
|
}
|
|
114
40
|
catch (error) {
|
|
115
41
|
return;
|
|
@@ -117,6 +43,7 @@ class LoginPage {
|
|
|
117
43
|
await this.clickUsername();
|
|
118
44
|
await this.fillUsername(username);
|
|
119
45
|
await this.fillPassword(password);
|
|
46
|
+
await (0, test_1.expect)(this.loginButton).toBeVisible({ timeout: 10000 });
|
|
120
47
|
await this.clickLoginButton();
|
|
121
48
|
}
|
|
122
49
|
}
|
|
@@ -16,17 +16,7 @@ class KeycloakAdminPage {
|
|
|
16
16
|
async switchToCamundaPlatform() {
|
|
17
17
|
const realmSelector = this.page.getByTestId('nav-item-realms');
|
|
18
18
|
await realmSelector.click();
|
|
19
|
-
|
|
20
|
-
await searchField.click();
|
|
21
|
-
await this.page
|
|
22
|
-
.getByPlaceholder('Search')
|
|
23
|
-
.fill(process.env.KEYCLOAK_REALM || 'camunda-platform');
|
|
24
|
-
await this.page
|
|
25
|
-
.locator('[data-ouia-component-id="OUIA-Generated-Button-control-1"]')
|
|
26
|
-
.click();
|
|
27
|
-
await this.page
|
|
28
|
-
.getByText(process.env.KEYCLOAK_REALM || 'camunda-platform')
|
|
29
|
-
.click();
|
|
19
|
+
await this.page.getByRole('link', { name: 'camunda-platform' }).click();
|
|
30
20
|
const mainLocator = this.page.locator('#kc-main-content-page-container');
|
|
31
21
|
await (0, test_1.expect)(mainLocator).toBeVisible();
|
|
32
22
|
}
|
|
@@ -1,17 +1,9 @@
|
|
|
1
1
|
import { Page, Locator } from '@playwright/test';
|
|
2
2
|
declare class LoginPage {
|
|
3
|
-
private page;
|
|
4
3
|
readonly usernameInput: Locator;
|
|
5
4
|
readonly passwordInput: Locator;
|
|
6
5
|
readonly loginButton: Locator;
|
|
7
|
-
readonly coreUsernameInput: Locator;
|
|
8
|
-
readonly corePasswordInput: Locator;
|
|
9
|
-
readonly coreLoginButton: Locator;
|
|
10
|
-
readonly keycloakBanner: Locator;
|
|
11
|
-
private useCore;
|
|
12
|
-
private useKeycloak;
|
|
13
6
|
constructor(page: Page);
|
|
14
|
-
detectLoginForm(): Promise<void>;
|
|
15
7
|
fillUsername(username: string): Promise<void>;
|
|
16
8
|
clickUsername(): Promise<void>;
|
|
17
9
|
fillPassword(password: string): Promise<void>;
|
|
@@ -1,100 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.LoginPage = void 0;
|
|
4
|
-
const test_1 = require("@playwright/test");
|
|
5
4
|
class LoginPage {
|
|
6
|
-
page;
|
|
7
5
|
usernameInput;
|
|
8
6
|
passwordInput;
|
|
9
7
|
loginButton;
|
|
10
|
-
coreUsernameInput;
|
|
11
|
-
corePasswordInput;
|
|
12
|
-
coreLoginButton;
|
|
13
|
-
keycloakBanner;
|
|
14
|
-
useCore = false;
|
|
15
|
-
useKeycloak = false;
|
|
16
8
|
constructor(page) {
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.passwordInput = page.getByLabel('Password');
|
|
9
|
+
this.usernameInput = page.locator('input[name="username"]');
|
|
10
|
+
this.passwordInput = page.locator('input[name="password"]');
|
|
20
11
|
this.loginButton = page.getByRole('button', { name: 'Log in' });
|
|
21
|
-
this.coreUsernameInput = page.getByPlaceholder('Username');
|
|
22
|
-
this.corePasswordInput = page.getByPlaceholder('Password');
|
|
23
|
-
this.coreLoginButton = page.getByRole('button', { name: 'Login' });
|
|
24
|
-
this.keycloakBanner = page.locator('body#keycloak-bg[data-page-id="login-login"]');
|
|
25
|
-
}
|
|
26
|
-
// Race logic: call before interacting
|
|
27
|
-
async detectLoginForm() {
|
|
28
|
-
const winner = await Promise.race([
|
|
29
|
-
this.usernameInput.waitFor({ state: 'visible' }).then(() => 'default'),
|
|
30
|
-
this.coreUsernameInput.waitFor({ state: 'visible' }).then(() => 'core'),
|
|
31
|
-
this.keycloakBanner.waitFor({ state: 'visible' }).then(() => 'keycloak'),
|
|
32
|
-
]);
|
|
33
|
-
this.useCore = winner === 'core';
|
|
34
|
-
this.useKeycloak = winner === 'keycloak';
|
|
35
12
|
}
|
|
36
13
|
async fillUsername(username) {
|
|
37
|
-
|
|
38
|
-
await this.page.fill('#username', username);
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
await (this.useCore
|
|
42
|
-
? this.coreUsernameInput.fill(username)
|
|
43
|
-
: this.usernameInput.fill(username));
|
|
44
|
-
}
|
|
14
|
+
await this.usernameInput.fill(username);
|
|
45
15
|
}
|
|
46
16
|
async clickUsername() {
|
|
47
|
-
|
|
48
|
-
await this.page.click('#username');
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
await (this.useCore
|
|
52
|
-
? this.coreUsernameInput.click({ timeout: 60000 })
|
|
53
|
-
: this.usernameInput.click({ timeout: 60000 }));
|
|
54
|
-
}
|
|
17
|
+
await this.usernameInput.click({ timeout: 60000 });
|
|
55
18
|
}
|
|
56
19
|
async fillPassword(password) {
|
|
57
|
-
|
|
58
|
-
await this.page.fill('#password', password);
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
await (this.useCore
|
|
62
|
-
? this.corePasswordInput.fill(password)
|
|
63
|
-
: this.passwordInput.fill(password));
|
|
64
|
-
}
|
|
20
|
+
await this.passwordInput.fill(password);
|
|
65
21
|
}
|
|
66
22
|
async clickLoginButton() {
|
|
67
|
-
|
|
68
|
-
await this.page.click('button[type="submit"]');
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
await (this.useCore
|
|
72
|
-
? this.coreLoginButton.click({ timeout: 60000 })
|
|
73
|
-
: this.loginButton.click({ timeout: 60000 }));
|
|
74
|
-
}
|
|
23
|
+
await this.loginButton.click({ timeout: 60000 });
|
|
75
24
|
}
|
|
76
25
|
async login(username, password) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
.locator('body#keycloak-bg[data-page-id="login-login"]')
|
|
81
|
-
.isVisible()) {
|
|
82
|
-
await (0, test_1.expect)(this.keycloakBanner).toBeVisible({ timeout: 15000 });
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
const activeLoginButton = this.useCore
|
|
86
|
-
? this.coreLoginButton
|
|
87
|
-
: this.loginButton;
|
|
88
|
-
await (0, test_1.expect)(activeLoginButton).toBeVisible({ timeout: 15000 });
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
catch (error) {
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
await this.clickUsername();
|
|
95
|
-
await this.fillUsername(username);
|
|
96
|
-
await this.fillPassword(password);
|
|
97
|
-
await this.clickLoginButton();
|
|
26
|
+
await this.usernameInput.fill(username);
|
|
27
|
+
await this.passwordInput.fill(password);
|
|
28
|
+
await this.loginButton.click();
|
|
98
29
|
}
|
|
99
30
|
async isLoginPage() {
|
|
100
31
|
try {
|
|
@@ -124,10 +124,7 @@ class NavigationPage {
|
|
|
124
124
|
await this.goTo('/optimize', this.optimizePageBanner, sleepTimeout);
|
|
125
125
|
}
|
|
126
126
|
async goToKeycloak() {
|
|
127
|
-
|
|
128
|
-
? `${process.env.KEYCLOAK_URL}/auth`
|
|
129
|
-
: '/auth';
|
|
130
|
-
await this.page.goto(keycloakUrl);
|
|
127
|
+
await this.page.goto('/auth');
|
|
131
128
|
await (0, test_1.expect)(this.keyboardPageBanner).toBeVisible();
|
|
132
129
|
}
|
|
133
130
|
async goToIdentity(sleepTimeout) {
|
|
@@ -7,9 +7,7 @@ declare class LoginPage {
|
|
|
7
7
|
readonly coreUsernameInput: Locator;
|
|
8
8
|
readonly corePasswordInput: Locator;
|
|
9
9
|
readonly coreLoginButton: Locator;
|
|
10
|
-
readonly keycloakBanner: Locator;
|
|
11
10
|
private useCore;
|
|
12
|
-
private useKeycloak;
|
|
13
11
|
constructor(page: Page);
|
|
14
12
|
detectLoginForm(): Promise<void>;
|
|
15
13
|
fillUsername(username: string): Promise<void>;
|