@camunda/e2e-test-suite 0.0.1240 → 0.0.1242
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.
|
@@ -8,18 +8,19 @@ declare class NavigationPage {
|
|
|
8
8
|
readonly identityPageBanner: Locator;
|
|
9
9
|
readonly keyboardPageBanner: Locator;
|
|
10
10
|
readonly managementIdentityPageBanner: Locator;
|
|
11
|
+
private onboardingTourSuppressed;
|
|
11
12
|
constructor(page: Page);
|
|
12
13
|
private isGatewayErrorPage;
|
|
13
14
|
private waitForBanner;
|
|
14
15
|
goTo(url: string, banner: Locator, sleepTimeout?: number, { username, password, }?: {
|
|
15
16
|
username?: string;
|
|
16
17
|
password?: string;
|
|
17
|
-
}, maxRetries?: number
|
|
18
|
+
}, maxRetries?: number): Promise<void>;
|
|
18
19
|
goToModeler(sleepTimeout?: number, credentials?: {
|
|
19
20
|
username: string;
|
|
20
21
|
password: string;
|
|
21
22
|
}): Promise<void>;
|
|
22
|
-
private
|
|
23
|
+
private suppressOnboardingTour;
|
|
23
24
|
goToTasklist(sleepTimeout?: number, credentials?: {
|
|
24
25
|
username: string;
|
|
25
26
|
password: string;
|
|
@@ -28,6 +28,7 @@ class NavigationPage {
|
|
|
28
28
|
identityPageBanner;
|
|
29
29
|
keyboardPageBanner;
|
|
30
30
|
managementIdentityPageBanner;
|
|
31
|
+
onboardingTourSuppressed = false;
|
|
31
32
|
constructor(page) {
|
|
32
33
|
this.page = page;
|
|
33
34
|
// Operate renders the Design System header (AppHeaderV2) whenever the
|
|
@@ -112,15 +113,12 @@ class NavigationPage {
|
|
|
112
113
|
// that is exactly the reported "Login (/modeler) failed after 8 attempts".
|
|
113
114
|
// The 60s budget is unchanged: a genuinely slow shell still gets all of it,
|
|
114
115
|
// and a sustained outage still fails.
|
|
115
|
-
async waitForBanner(url, banner, submitted
|
|
116
|
+
async waitForBanner(url, banner, submitted) {
|
|
116
117
|
const totalTimeout = constants_1._1_SECOND_IN_MS * 60;
|
|
117
118
|
const deadline = Date.now() + totalTimeout;
|
|
118
119
|
let lastState = 'no banner';
|
|
119
120
|
while (Date.now() < deadline) {
|
|
120
121
|
const round = Math.min(constants_1._1_SECOND_IN_MS * 20, deadline - Date.now());
|
|
121
|
-
if (beforeBannerCheck) {
|
|
122
|
-
await beforeBannerCheck();
|
|
123
|
-
}
|
|
124
122
|
try {
|
|
125
123
|
await (0, test_1.expect)(banner).toBeVisible({ timeout: round });
|
|
126
124
|
return;
|
|
@@ -148,7 +146,7 @@ class NavigationPage {
|
|
|
148
146
|
}
|
|
149
147
|
throw new Error(`${url} did not render its banner within ${totalTimeout}ms: ${lastState}`);
|
|
150
148
|
}
|
|
151
|
-
async goTo(url, banner, sleepTimeout, { username = IDENTITY_FIRSTUSER_USERNAME, password = IDENTITY_FIRSTUSER_PASSWORD, } = {}, maxRetries = 8
|
|
149
|
+
async goTo(url, banner, sleepTimeout, { username = IDENTITY_FIRSTUSER_USERNAME, password = IDENTITY_FIRSTUSER_PASSWORD, } = {}, maxRetries = 8) {
|
|
152
150
|
const startTime = Date.now();
|
|
153
151
|
let timeout = constants_1._1_SECOND_IN_MS * 10;
|
|
154
152
|
if (url === '/modeler') {
|
|
@@ -217,7 +215,7 @@ class NavigationPage {
|
|
|
217
215
|
else {
|
|
218
216
|
submitted = await loginPage.login(username, password);
|
|
219
217
|
}
|
|
220
|
-
await this.waitForBanner(url, banner, submitted
|
|
218
|
+
await this.waitForBanner(url, banner, submitted);
|
|
221
219
|
return;
|
|
222
220
|
}
|
|
223
221
|
catch (error) {
|
|
@@ -264,25 +262,27 @@ class NavigationPage {
|
|
|
264
262
|
}
|
|
265
263
|
}
|
|
266
264
|
async goToModeler(sleepTimeout, credentials) {
|
|
267
|
-
await this.
|
|
265
|
+
await this.suppressOnboardingTour();
|
|
266
|
+
await this.goTo(MODELER_CONTEXT_PATH, this.modelerPageBanner, sleepTimeout, credentials, 8);
|
|
268
267
|
}
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
272
|
-
//
|
|
273
|
-
//
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
.
|
|
284
|
-
|
|
285
|
-
|
|
268
|
+
// Mirrors camunda-hub@452978f: pre-seed the onboarding tour's "seen" localStorage flag
|
|
269
|
+
// (SEEN_KEY_PREFIX in .../tour-dialog/use-onboarding-seen.ts) so it never auto-opens, rather
|
|
270
|
+
// than dismissing it reactively (the two prior fixes here -- both raced the dialog's mount
|
|
271
|
+
// and lost, since the user id needed for the real key isn't known until after that same
|
|
272
|
+
// race). addInitScript avoids the race by running before any page script, matching the
|
|
273
|
+
// flag by prefix since the user id isn't known up front.
|
|
274
|
+
async suppressOnboardingTour() {
|
|
275
|
+
if (this.onboardingTourSuppressed) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
this.onboardingTourSuppressed = true;
|
|
279
|
+
await this.page.addInitScript((prefixPattern) => {
|
|
280
|
+
const pattern = new RegExp(prefixPattern);
|
|
281
|
+
const originalGetItem = Storage.prototype.getItem;
|
|
282
|
+
Storage.prototype.getItem = function (key) {
|
|
283
|
+
return pattern.test(key) ? 'true' : originalGetItem.call(this, key);
|
|
284
|
+
};
|
|
285
|
+
}, '^hub\\.onboarding\\..*\\.seen\\.');
|
|
286
286
|
}
|
|
287
287
|
async goToTasklist(sleepTimeout, credentials) {
|
|
288
288
|
await this.goTo(`${NORMALIZED_ORCHESTRATION_CONTEXT_PATH}/tasklist`, this.tasklistPageBanner, sleepTimeout, credentials);
|
|
@@ -156,6 +156,12 @@ class ProcessApplicationPage {
|
|
|
156
156
|
await (0, test_1.expect)(this.defineStagesDialog).toBeVisible({ timeout: 60000 });
|
|
157
157
|
await this.developmentClusterSelect.click({ timeout: 30000 });
|
|
158
158
|
const escapedClusterName = clusterName?.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
159
|
+
// The listbox leads with a "No cluster" entry that unassigns the stage; the
|
|
160
|
+
// placeholder "Select a development cluster" is only the trigger's text, not an
|
|
161
|
+
// option. Excluding just the placeholder leaves "No cluster" first, so an
|
|
162
|
+
// unnamed pick binds no cluster and saves defaultDevClusterId=null -- which
|
|
163
|
+
// makes the later Deploy dialog report "Clusters not configured for stages".
|
|
164
|
+
// Exclude "No cluster" too so the fallback lands on a real cluster.
|
|
159
165
|
const option = clusterName
|
|
160
166
|
? this.page
|
|
161
167
|
.getByRole('option', { name: new RegExp(`^${escapedClusterName}`) })
|
|
@@ -163,6 +169,7 @@ class ProcessApplicationPage {
|
|
|
163
169
|
: this.page
|
|
164
170
|
.getByRole('option')
|
|
165
171
|
.filter({ hasNotText: 'Select a development cluster' })
|
|
172
|
+
.filter({ hasNotText: 'No cluster' })
|
|
166
173
|
.first();
|
|
167
174
|
await option.click({ timeout: 30000 });
|
|
168
175
|
await this.defineStagesSaveButton.click({ timeout: 30000 });
|