@camunda/e2e-test-suite 0.0.775 → 0.0.777
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/OperateProcessesPage.js +4 -1
- package/dist/pages/8.7/ModelerCreatePage.js +5 -0
- package/dist/pages/8.8/ClusterPage.js +6 -2
- package/dist/pages/8.8/FormJsPage.d.ts +1 -0
- package/dist/pages/8.8/FormJsPage.js +30 -7
- package/dist/pages/8.8/ModelerCreatePage.d.ts +1 -0
- package/dist/pages/8.8/ModelerCreatePage.js +18 -1
- package/dist/pages/8.8/OperateProcessesPage.js +4 -1
- package/dist/pages/8.9/OperateProcessesPage.js +4 -1
- package/dist/tests/8.7/smoke-tests.spec.js +12 -6
- package/package.json +1 -1
|
@@ -79,7 +79,10 @@ class OperateProcessesPage {
|
|
|
79
79
|
await this.processFinishedInstancesCheckbox.click();
|
|
80
80
|
}
|
|
81
81
|
async clickProcessInstanceLink(processName) {
|
|
82
|
-
|
|
82
|
+
// Increased from 3 to 5 retries: process-instance indexing in Operate can take
|
|
83
|
+
// longer than 3 × (60 s visible + 10 s reload) on busy SaaS environments,
|
|
84
|
+
// causing intermittent failures in the webhook connector nightly tests.
|
|
85
|
+
const maxRetries = 5;
|
|
83
86
|
for (let retries = 0; retries < maxRetries; retries++) {
|
|
84
87
|
try {
|
|
85
88
|
await (0, test_1.expect)(this.processInstanceLink(processName)).toBeVisible({
|
|
@@ -398,8 +398,13 @@ class ModelerCreatePage {
|
|
|
398
398
|
await this.userTaskOption.click();
|
|
399
399
|
}
|
|
400
400
|
async clickForm(name) {
|
|
401
|
+
// Baseline upgrade runs use fixed form names, so a Playwright retry re-creates
|
|
402
|
+
// a form with the same name and the picker then lists two identical entries.
|
|
403
|
+
// Scope to the first matching item so the link step stays deterministic on retry
|
|
404
|
+
// instead of failing with a strict-mode violation.
|
|
401
405
|
await this.page
|
|
402
406
|
.locator(`[data-test="item-${name}"]`)
|
|
407
|
+
.first()
|
|
403
408
|
.getByText(name)
|
|
404
409
|
.click({ timeout: 90000 });
|
|
405
410
|
}
|
|
@@ -364,8 +364,12 @@ class ClusterPage {
|
|
|
364
364
|
}
|
|
365
365
|
}
|
|
366
366
|
async assertClusterHealthyStatusWithRetry(name, visibilityTimeout = 100000, totalTimeout = 420000, isUpgradeScenario = false) {
|
|
367
|
-
// For upgrade scenarios, use much longer timeouts and more retries instead of fixed waits
|
|
368
|
-
|
|
367
|
+
// For upgrade scenarios, use much longer timeouts and more retries instead of fixed waits.
|
|
368
|
+
// After the 8.7->8.8 upgrade the cluster's components report healthy and the generation
|
|
369
|
+
// flips to 8.8 well before the cluster-list overall Status leaves "Updating"; that overall
|
|
370
|
+
// flip to "Healthy" can lag past 15 min, so allow 25 min here (job timeout is 60 min and the
|
|
371
|
+
// caller runs under test.slow()).
|
|
372
|
+
const actualTotalTimeout = isUpgradeScenario ? 1500000 : totalTimeout; // 25 minutes for upgrades
|
|
369
373
|
const actualVisibilityTimeout = isUpgradeScenario
|
|
370
374
|
? 15000
|
|
371
375
|
: visibilityTimeout; // Shorter individual checks
|
|
@@ -17,6 +17,7 @@ declare class FormJsPage {
|
|
|
17
17
|
readonly deploySubButton: Locator;
|
|
18
18
|
readonly dialog: Locator;
|
|
19
19
|
readonly deploySuccessNotification: Locator;
|
|
20
|
+
readonly deployErrorMessage: Locator;
|
|
20
21
|
constructor(page: Page);
|
|
21
22
|
generateAIForm(request?: string): Promise<void>;
|
|
22
23
|
clickAIFormGeneratorButton(): Promise<void>;
|
|
@@ -21,6 +21,7 @@ class FormJsPage {
|
|
|
21
21
|
deploySubButton;
|
|
22
22
|
dialog;
|
|
23
23
|
deploySuccessNotification;
|
|
24
|
+
deployErrorMessage;
|
|
24
25
|
constructor(page) {
|
|
25
26
|
this.page = page;
|
|
26
27
|
this.aiFormGeneratorButton = page.getByRole('button', {
|
|
@@ -54,6 +55,7 @@ class FormJsPage {
|
|
|
54
55
|
this.deploySuccessNotification = page
|
|
55
56
|
.locator('.cds--toast-notification--success')
|
|
56
57
|
.filter({ hasText: 'Form deployed!' });
|
|
58
|
+
this.deployErrorMessage = this.dialog.getByText('The form failed to deploy');
|
|
57
59
|
}
|
|
58
60
|
async generateAIForm(request = 'Create a form with the following fields: 1. A text field with the label "Full Name" 2. A number with the label "Count" 3. A date input with the label "Date of birth"4. A Checkbox with the label "Agree"') {
|
|
59
61
|
await (0, test_1.expect)(this.aiFormGeneratorButton).toBeVisible({
|
|
@@ -120,13 +122,34 @@ class FormJsPage {
|
|
|
120
122
|
await this.deploySubButton.click({ timeout: 60000 });
|
|
121
123
|
}
|
|
122
124
|
async deployForm(clusterName) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
125
|
+
// After a 8.7->8.8 upgrade, orchestration-cluster authorization commands
|
|
126
|
+
// propagate across partitions for several minutes; deploy is rejected with
|
|
127
|
+
// FORBIDDEN until the deployer's grant lands. In migration runs, reload and
|
|
128
|
+
// retry through that propagation window instead of failing on the transient
|
|
129
|
+
// rejection. Non-migration runs keep the original single-attempt behavior.
|
|
130
|
+
const maxAttempts = process.env.IS_MIGRATION === 'true' ? 15 : 1;
|
|
131
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
132
|
+
await this.clickDeployButton();
|
|
133
|
+
await (0, test_1.expect)(this.dialog).toBeVisible({
|
|
134
|
+
timeout: 30000,
|
|
135
|
+
});
|
|
136
|
+
await this.selectCluster(clusterName);
|
|
137
|
+
await this.clickDeploySubButton();
|
|
138
|
+
if (attempt === maxAttempts) {
|
|
139
|
+
await (0, test_1.expect)(this.deploySuccessNotification).toBeVisible({
|
|
140
|
+
timeout: 30000,
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const deployed = await this.deploySuccessNotification
|
|
145
|
+
.waitFor({ state: 'visible', timeout: 30000 })
|
|
146
|
+
.then(() => true)
|
|
147
|
+
.catch(() => false);
|
|
148
|
+
if (deployed) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
await this.page.reload();
|
|
152
|
+
}
|
|
130
153
|
}
|
|
131
154
|
}
|
|
132
155
|
exports.FormJsPage = FormJsPage;
|
|
@@ -12,6 +12,7 @@ declare class ModelerCreatePage {
|
|
|
12
12
|
readonly startInstanceMainButton: Locator;
|
|
13
13
|
readonly startInstanceSubButton: Locator;
|
|
14
14
|
readonly viewProcessInstanceLink: Locator;
|
|
15
|
+
readonly deployErrorMessage: Locator;
|
|
15
16
|
readonly nameInput: Locator;
|
|
16
17
|
readonly diagramBreadcrumb: Locator;
|
|
17
18
|
readonly renameDiagramNameButton: Locator;
|
|
@@ -18,6 +18,7 @@ class ModelerCreatePage {
|
|
|
18
18
|
startInstanceMainButton;
|
|
19
19
|
startInstanceSubButton;
|
|
20
20
|
viewProcessInstanceLink;
|
|
21
|
+
deployErrorMessage;
|
|
21
22
|
nameInput;
|
|
22
23
|
diagramBreadcrumb;
|
|
23
24
|
renameDiagramNameButton;
|
|
@@ -147,6 +148,7 @@ class ModelerCreatePage {
|
|
|
147
148
|
this.viewProcessLink = page.getByRole('button', {
|
|
148
149
|
name: 'View process in Operate',
|
|
149
150
|
});
|
|
151
|
+
this.deployErrorMessage = page.getByText('The diagram failed to deploy & run');
|
|
150
152
|
this.nameInput = page.getByLabel('Name', { exact: true });
|
|
151
153
|
this.diagramBreadcrumb = page.locator('[data-test="breadcrumb-diagram"]');
|
|
152
154
|
this.renameDiagramNameButton = page.getByText('Rename');
|
|
@@ -545,7 +547,13 @@ class ModelerCreatePage {
|
|
|
545
547
|
}
|
|
546
548
|
}
|
|
547
549
|
async runProcessInstance(clusterName, variables = '', formVariables = {}, textToVisible = '') {
|
|
548
|
-
|
|
550
|
+
// After a 8.7->8.8 upgrade, orchestration-cluster authorization commands
|
|
551
|
+
// propagate across partitions for several minutes; deploy & run is rejected
|
|
552
|
+
// with FORBIDDEN until the deployer's grant lands. In migration runs, detect
|
|
553
|
+
// that rejection and retry through the propagation window (more attempts),
|
|
554
|
+
// rather than returning a silently-failed run.
|
|
555
|
+
const isMigration = process.env.IS_MIGRATION === 'true';
|
|
556
|
+
const maxRetries = isMigration ? 20 : 10;
|
|
549
557
|
const retryDelayMs = 20000;
|
|
550
558
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
551
559
|
try {
|
|
@@ -576,6 +584,15 @@ class ModelerCreatePage {
|
|
|
576
584
|
});
|
|
577
585
|
}
|
|
578
586
|
await this.clickStartInstanceSubButton();
|
|
587
|
+
if (isMigration) {
|
|
588
|
+
const deployRejected = await this.deployErrorMessage
|
|
589
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
590
|
+
.then(() => true)
|
|
591
|
+
.catch(() => false);
|
|
592
|
+
if (deployRejected) {
|
|
593
|
+
throw new Error('Deploy & run rejected; authorization may still be propagating after upgrade');
|
|
594
|
+
}
|
|
595
|
+
}
|
|
579
596
|
return;
|
|
580
597
|
}
|
|
581
598
|
catch (error) {
|
|
@@ -79,7 +79,10 @@ class OperateProcessesPage {
|
|
|
79
79
|
await this.processFinishedInstancesCheckbox.click();
|
|
80
80
|
}
|
|
81
81
|
async clickProcessInstanceLink(processName) {
|
|
82
|
-
|
|
82
|
+
// Increased from 3 to 5 retries: process-instance indexing in Operate can take
|
|
83
|
+
// longer than 3 × (60 s visible + 10 s reload) on busy SaaS environments,
|
|
84
|
+
// causing intermittent failures in the webhook connector nightly tests.
|
|
85
|
+
const maxRetries = 5;
|
|
83
86
|
for (let retries = 0; retries < maxRetries; retries++) {
|
|
84
87
|
try {
|
|
85
88
|
await (0, test_1.expect)(this.processInstanceLink(processName)).toBeVisible({
|
|
@@ -79,7 +79,10 @@ class OperateProcessesPage {
|
|
|
79
79
|
await this.processFinishedInstancesCheckbox.click();
|
|
80
80
|
}
|
|
81
81
|
async clickProcessInstanceLink(processName) {
|
|
82
|
-
|
|
82
|
+
// Increased from 3 to 5 retries: process-instance indexing in Operate can take
|
|
83
|
+
// longer than 3 × (60 s visible + 10 s reload) on busy SaaS environments,
|
|
84
|
+
// causing intermittent failures in the webhook connector nightly tests.
|
|
85
|
+
const maxRetries = 5;
|
|
83
86
|
for (let retries = 0; retries < maxRetries; retries++) {
|
|
84
87
|
try {
|
|
85
88
|
await (0, test_1.expect)(this.processInstanceLink(processName)).toBeVisible({
|
|
@@ -100,8 +100,12 @@ _8_7_1.test.describe('Smoke Tests', () => {
|
|
|
100
100
|
});
|
|
101
101
|
});
|
|
102
102
|
await _8_7_1.test.step('Open process instance in Operate and verify it is active', async () => {
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
// Register the popup waiter before the click so the Operate tab is not missed
|
|
104
|
+
// if it opens in the gap between the click resolving and waitForEvent starting.
|
|
105
|
+
[appTab] = await Promise.all([
|
|
106
|
+
page.waitForEvent('popup', { timeout: TIMEOUT.navigation }),
|
|
107
|
+
modelerCreatePage.clickViewProcessInstanceLink(),
|
|
108
|
+
]);
|
|
105
109
|
const appTabProcessInstancePage = new OperateProcessInstancePage_1.OperateProcessInstancePage(appTab);
|
|
106
110
|
await (0, test_1.expect)(appTabProcessInstancePage.activeIcon).toBeVisible({
|
|
107
111
|
timeout: TIMEOUT.processActive,
|
|
@@ -209,10 +213,12 @@ _8_7_1.test.describe('Smoke Tests', () => {
|
|
|
209
213
|
});
|
|
210
214
|
});
|
|
211
215
|
await _8_7_1.test.step('Assert process completes in Operate and verify connector result', async () => {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
+
// Register the popup waiter before the click so the Operate tab is not missed
|
|
217
|
+
// if it opens in the gap between the click resolving and waitForEvent starting.
|
|
218
|
+
const [operateTab] = await Promise.all([
|
|
219
|
+
page.waitForEvent('popup', { timeout: TIMEOUT.navigation }),
|
|
220
|
+
modelerCreatePage.clickViewProcessInstanceLink(),
|
|
221
|
+
]);
|
|
216
222
|
const operateHomePage = new OperateHomePage_1.OperateHomePage(operateTab);
|
|
217
223
|
const operateProcessesPage = new OperateProcessesPage_1.OperateProcessesPage(operateTab);
|
|
218
224
|
const operateProcessInstancePage = new OperateProcessInstancePage_1.OperateProcessInstancePage(operateTab);
|