@camunda/e2e-test-suite 0.0.800 → 0.0.802
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.
|
@@ -185,9 +185,12 @@ class ModelerCreatePage {
|
|
|
185
185
|
this.secondPlacedElement = page.locator('g:nth-child(2) > .djs-element > .djs-hit');
|
|
186
186
|
this.payloadInput = page.locator('[class="fjs-input"]');
|
|
187
187
|
this.marketPlaceButton = page.getByTitle('Browse Marketplace for more Connectors');
|
|
188
|
+
// Match either marketplace display name — the connector was renamed from
|
|
189
|
+
// "Public Holiday Outbound" to "Worldwide Public Holiday"; accepting both
|
|
190
|
+
// keeps the flow green whichever the marketplace currently serves.
|
|
188
191
|
this.publicHolidayConnectorOption = page
|
|
189
192
|
.locator('[data-test="modeler"]')
|
|
190
|
-
.getByText(
|
|
193
|
+
.getByText(/Worldwide Public Holiday|Public Holiday Outbound/)
|
|
191
194
|
.first();
|
|
192
195
|
this.publicHolidayYearOption = page.getByLabel('Year');
|
|
193
196
|
this.publicHolidayCountryCodeOption = page.getByLabel('Countrycode');
|
|
@@ -457,8 +460,13 @@ class ModelerCreatePage {
|
|
|
457
460
|
await this.userTaskOption.click();
|
|
458
461
|
}
|
|
459
462
|
async clickForm(name) {
|
|
463
|
+
// Baseline upgrade runs use fixed form names, so a Playwright retry re-creates
|
|
464
|
+
// a form with the same name and the picker then lists two identical entries.
|
|
465
|
+
// Scope to the first matching item so the link step stays deterministic on retry
|
|
466
|
+
// instead of failing with a strict-mode violation.
|
|
460
467
|
await this.page
|
|
461
468
|
.locator(`[data-test="item-${name}"]`)
|
|
469
|
+
.first()
|
|
462
470
|
.getByText(name)
|
|
463
471
|
.click({ timeout: 90000 });
|
|
464
472
|
}
|
|
@@ -788,12 +796,35 @@ class ModelerCreatePage {
|
|
|
788
796
|
await this.secondElement.click({ timeout: 60000 });
|
|
789
797
|
await this.clickChangeTypeButton();
|
|
790
798
|
await (0, test_1.expect)(this.marketPlaceButton).toBeVisible({ timeout: 60000 });
|
|
791
|
-
// Filter the virtualized change-element popup so the option scrolls
|
|
799
|
+
// Filter the virtualized change-element popup so the option scrolls
|
|
800
|
+
// into view. Search by each full connector name (the marketplace
|
|
801
|
+
// renamed it "Public Holiday Outbound" -> "Worldwide Public Holiday"),
|
|
802
|
+
// not the shared "Public Holiday" substring — a generic term could
|
|
803
|
+
// surface a different Public Holiday connector we must not select.
|
|
804
|
+
const connectorNames = [
|
|
805
|
+
'Worldwide Public Holiday',
|
|
806
|
+
'Public Holiday Outbound',
|
|
807
|
+
];
|
|
792
808
|
const changeElementSearch = this.page.locator('.djs-popup-search input');
|
|
793
|
-
|
|
794
|
-
.
|
|
795
|
-
.
|
|
796
|
-
|
|
809
|
+
const searchVisible = await changeElementSearch
|
|
810
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
811
|
+
.then(() => true)
|
|
812
|
+
.catch(() => false);
|
|
813
|
+
if (searchVisible) {
|
|
814
|
+
for (const name of connectorNames) {
|
|
815
|
+
await changeElementSearch.fill('');
|
|
816
|
+
await changeElementSearch.pressSequentially(name, { delay: 50 });
|
|
817
|
+
// waitFor actually blocks up to the timeout; isVisible() would
|
|
818
|
+
// return immediately and miss the option still rendering after
|
|
819
|
+
// the search filter applies.
|
|
820
|
+
const optionVisible = await this.publicHolidayConnectorOption
|
|
821
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
822
|
+
.then(() => true)
|
|
823
|
+
.catch(() => false);
|
|
824
|
+
if (optionVisible) {
|
|
825
|
+
break;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
797
828
|
}
|
|
798
829
|
await this.publicHolidayConnectorOption.waitFor({
|
|
799
830
|
state: 'visible',
|
|
@@ -187,9 +187,12 @@ class ModelerCreatePage {
|
|
|
187
187
|
this.secondPlacedElement = page.locator('g:nth-child(2) > .djs-element > .djs-hit');
|
|
188
188
|
this.payloadInput = page.locator('[class="fjs-input"]');
|
|
189
189
|
this.marketPlaceButton = page.getByTitle('Browse Marketplace for more Connectors');
|
|
190
|
+
// Match either marketplace display name — the connector was renamed from
|
|
191
|
+
// "Public Holiday Outbound" to "Worldwide Public Holiday"; accepting both
|
|
192
|
+
// keeps the flow green whichever the marketplace currently serves.
|
|
190
193
|
this.publicHolidayConnectorOption = page
|
|
191
194
|
.locator('[data-test="modeler"]')
|
|
192
|
-
.getByText(
|
|
195
|
+
.getByText(/Worldwide Public Holiday|Public Holiday Outbound/);
|
|
193
196
|
this.publicHolidayYearOption = page.getByLabel('Year');
|
|
194
197
|
this.publicHolidayCountryCodeOption = page.getByLabel('Countrycode');
|
|
195
198
|
this.implementationSection = page.locator('[data-group-id="group-userTaskImplementation"]');
|
|
@@ -456,8 +459,13 @@ class ModelerCreatePage {
|
|
|
456
459
|
await this.userTaskOption.click();
|
|
457
460
|
}
|
|
458
461
|
async clickForm(name) {
|
|
462
|
+
// Baseline upgrade runs use fixed form names, so a Playwright retry re-creates
|
|
463
|
+
// a form with the same name and the picker then lists two identical entries.
|
|
464
|
+
// Scope to the first matching item so the link step stays deterministic on retry
|
|
465
|
+
// instead of failing with a strict-mode violation.
|
|
459
466
|
await this.page
|
|
460
467
|
.locator(`[data-test="item-${name}"]`)
|
|
468
|
+
.first()
|
|
461
469
|
.getByText(name)
|
|
462
470
|
.click({ timeout: 90000 });
|
|
463
471
|
}
|
|
@@ -809,12 +817,36 @@ class ModelerCreatePage {
|
|
|
809
817
|
await this.secondElement.click({ timeout: 60000 });
|
|
810
818
|
await this.clickChangeTypeButton();
|
|
811
819
|
await (0, test_1.expect)(this.marketPlaceButton).toBeVisible({ timeout: 60000 });
|
|
812
|
-
// Filter the virtualized change-element popup so the option scrolls
|
|
820
|
+
// Filter the virtualized change-element popup so the option scrolls
|
|
821
|
+
// into view. Search by each full connector name (the marketplace
|
|
822
|
+
// renamed it "Public Holiday Outbound" -> "Worldwide Public Holiday"),
|
|
823
|
+
// not the shared "Public Holiday" substring — a generic term could
|
|
824
|
+
// surface a different Public Holiday connector we must not select.
|
|
825
|
+
const connectorNames = [
|
|
826
|
+
'Worldwide Public Holiday',
|
|
827
|
+
'Public Holiday Outbound',
|
|
828
|
+
];
|
|
813
829
|
const changeElementSearch = this.page.locator('.djs-popup-search input');
|
|
814
|
-
|
|
815
|
-
.
|
|
816
|
-
.
|
|
817
|
-
|
|
830
|
+
const searchVisible = await changeElementSearch
|
|
831
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
832
|
+
.then(() => true)
|
|
833
|
+
.catch(() => false);
|
|
834
|
+
if (searchVisible) {
|
|
835
|
+
for (const name of connectorNames) {
|
|
836
|
+
await changeElementSearch.fill('');
|
|
837
|
+
await changeElementSearch.pressSequentially(name, { delay: 50 });
|
|
838
|
+
// waitFor actually blocks up to the timeout; isVisible() would
|
|
839
|
+
// return immediately and miss the option still rendering after
|
|
840
|
+
// the search filter applies.
|
|
841
|
+
const optionVisible = await this.publicHolidayConnectorOption
|
|
842
|
+
.first()
|
|
843
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
844
|
+
.then(() => true)
|
|
845
|
+
.catch(() => false);
|
|
846
|
+
if (optionVisible) {
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
818
850
|
}
|
|
819
851
|
// Importing via "Save as copy" can leave both the pre-existing and the
|
|
820
852
|
// newly imported template in the change-element list, so target the
|
|
@@ -183,9 +183,13 @@ class ModelerCreatePage {
|
|
|
183
183
|
this.secondPlacedElement = page.locator('g:nth-child(2) > .djs-element > .djs-hit');
|
|
184
184
|
this.payloadInput = page.locator('[class="fjs-input"]');
|
|
185
185
|
this.marketPlaceButton = page.getByTitle('Browse Marketplace for more Connectors');
|
|
186
|
+
// Match either marketplace display name — the connector was renamed from
|
|
187
|
+
// "Public Holiday Outbound" to "Worldwide Public Holiday"; accepting both
|
|
188
|
+
// keeps the flow green whichever the marketplace currently serves.
|
|
186
189
|
this.publicHolidayConnectorOption = page
|
|
187
190
|
.locator('[data-test="modeler"]')
|
|
188
|
-
.getByText(
|
|
191
|
+
.getByText(/Worldwide Public Holiday|Public Holiday Outbound/)
|
|
192
|
+
.first();
|
|
189
193
|
this.publicHolidayYearOption = page.getByLabel('Year');
|
|
190
194
|
this.publicHolidayCountryCodeOption = page.getByLabel('Countrycode');
|
|
191
195
|
this.implementationSection = page.locator('[data-group-id="group-userTaskImplementation"]');
|
|
@@ -454,8 +458,13 @@ class ModelerCreatePage {
|
|
|
454
458
|
await this.userTaskOption.click();
|
|
455
459
|
}
|
|
456
460
|
async clickForm(name) {
|
|
461
|
+
// Baseline upgrade runs use fixed form names, so a Playwright retry re-creates
|
|
462
|
+
// a form with the same name and the picker then lists two identical entries.
|
|
463
|
+
// Scope to the first matching item so the link step stays deterministic on retry
|
|
464
|
+
// instead of failing with a strict-mode violation.
|
|
457
465
|
await this.page
|
|
458
466
|
.locator(`[data-test="item-${name}"]`)
|
|
467
|
+
.first()
|
|
459
468
|
.getByText(name)
|
|
460
469
|
.click({ timeout: 90000 });
|
|
461
470
|
}
|
|
@@ -781,12 +790,35 @@ class ModelerCreatePage {
|
|
|
781
790
|
await this.secondElement.click({ timeout: 60000 });
|
|
782
791
|
await this.clickChangeTypeButton();
|
|
783
792
|
await (0, test_1.expect)(this.marketPlaceButton).toBeVisible({ timeout: 60000 });
|
|
784
|
-
// Filter the virtualized change-element popup so the option scrolls
|
|
793
|
+
// Filter the virtualized change-element popup so the option scrolls
|
|
794
|
+
// into view. Search by each full connector name (the marketplace
|
|
795
|
+
// renamed it "Public Holiday Outbound" -> "Worldwide Public Holiday"),
|
|
796
|
+
// not the shared "Public Holiday" substring — a generic term could
|
|
797
|
+
// surface a different Public Holiday connector we must not select.
|
|
798
|
+
const connectorNames = [
|
|
799
|
+
'Worldwide Public Holiday',
|
|
800
|
+
'Public Holiday Outbound',
|
|
801
|
+
];
|
|
785
802
|
const changeElementSearch = this.page.locator('.djs-popup-search input');
|
|
786
|
-
|
|
787
|
-
.
|
|
788
|
-
.
|
|
789
|
-
|
|
803
|
+
const searchVisible = await changeElementSearch
|
|
804
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
805
|
+
.then(() => true)
|
|
806
|
+
.catch(() => false);
|
|
807
|
+
if (searchVisible) {
|
|
808
|
+
for (const name of connectorNames) {
|
|
809
|
+
await changeElementSearch.fill('');
|
|
810
|
+
await changeElementSearch.pressSequentially(name, { delay: 50 });
|
|
811
|
+
// waitFor actually blocks up to the timeout; isVisible() would
|
|
812
|
+
// return immediately and miss the option still rendering after
|
|
813
|
+
// the search filter applies.
|
|
814
|
+
const optionVisible = await this.publicHolidayConnectorOption
|
|
815
|
+
.waitFor({ state: 'visible', timeout: 5000 })
|
|
816
|
+
.then(() => true)
|
|
817
|
+
.catch(() => false);
|
|
818
|
+
if (optionVisible) {
|
|
819
|
+
break;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
790
822
|
}
|
|
791
823
|
await this.publicHolidayConnectorOption.waitFor({
|
|
792
824
|
state: 'visible',
|
|
@@ -50,15 +50,15 @@ class OCIdentityClusterVariablesPage {
|
|
|
50
50
|
await this.editMenuItem.click();
|
|
51
51
|
await (0, test_1.expect)(this.variableValueField).toBeVisible();
|
|
52
52
|
await (0, test_1.expect)(this.monacoEditor).toBeVisible();
|
|
53
|
+
// Monaco's hidden <textarea> only forwards keyboard events to the
|
|
54
|
+
// editor model — `fill()` writes the value but doesn't trigger
|
|
55
|
+
// Monaco's onDidChangeContent, so the modal's JSON validator never
|
|
56
|
+
// re-runs and Save stays disabled. Use real keyboard input instead.
|
|
53
57
|
await this.monacoEditor.click();
|
|
54
|
-
await this.
|
|
55
|
-
await this.
|
|
56
|
-
await this.
|
|
57
|
-
await test_1.expect
|
|
58
|
-
.poll(async () => await this.saveVariableButton.isEnabled(), {
|
|
59
|
-
timeout: 30000,
|
|
60
|
-
})
|
|
61
|
-
.toBe(true);
|
|
58
|
+
await this.page.keyboard.press('ControlOrMeta+A');
|
|
59
|
+
await this.page.keyboard.press('Delete');
|
|
60
|
+
await this.page.keyboard.type(newValue);
|
|
61
|
+
await (0, test_1.expect)(this.saveVariableButton).toBeEnabled();
|
|
62
62
|
await this.saveVariableButton.click();
|
|
63
63
|
await (0, test_1.expect)(this.successMessage).toBeVisible();
|
|
64
64
|
await (0, test_1.expect)(this.editVariableModal).toBeHidden();
|
package/dist/utils/apiHelpers.js
CHANGED
|
@@ -209,24 +209,38 @@ async function authSaasAPI(audience, clusterType) {
|
|
|
209
209
|
const creds = getClusterCredentials(clusterType);
|
|
210
210
|
const tokenAudience = audience ?? creds.tokenAudience;
|
|
211
211
|
apiRequestContext = await getApiRequestContext();
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
212
|
+
// The SaaS token endpoint sits behind Cloudflare, which returns a 1015
|
|
213
|
+
// "You are being rate limited" page when many specs fetch a token at once
|
|
214
|
+
// (each MCP spec authenticates in beforeAll). Retry with exponential
|
|
215
|
+
// backoff so the rate-limit window clears instead of failing the suite.
|
|
216
|
+
const maxAttempts = 5;
|
|
217
|
+
const baseDelayMs = 3000;
|
|
218
|
+
let lastErrorMessage = '';
|
|
219
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
220
|
+
const tokenResponse = await apiRequestContext.post(creds.authUrl, {
|
|
221
|
+
headers: {
|
|
222
|
+
'Content-Type': 'application/json',
|
|
223
|
+
},
|
|
224
|
+
data: {
|
|
225
|
+
audience: tokenAudience,
|
|
226
|
+
client_id: creds.clientId,
|
|
227
|
+
client_secret: creds.clientSecret,
|
|
228
|
+
grant_type: 'client_credentials',
|
|
229
|
+
},
|
|
230
|
+
});
|
|
231
|
+
if (tokenResponse.status() === 200) {
|
|
232
|
+
const tokenJson = await tokenResponse.json();
|
|
233
|
+
return `Bearer ${tokenJson.access_token}`;
|
|
234
|
+
}
|
|
224
235
|
const errorBody = await tokenResponse.text();
|
|
225
|
-
|
|
236
|
+
lastErrorMessage = `HTTP ${tokenResponse.status()} - ${errorBody.slice(0, 200)}`;
|
|
237
|
+
if (attempt < maxAttempts) {
|
|
238
|
+
console.warn(`authSaasAPI attempt ${attempt}/${maxAttempts} failed to fetch access token (${lastErrorMessage}); retrying after backoff...`);
|
|
239
|
+
await new Promise((r) => setTimeout(r, baseDelayMs * 2 ** (attempt - 1)));
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
226
242
|
}
|
|
227
|
-
|
|
228
|
-
const bearerToken = `Bearer ${tokenJson.access_token}`;
|
|
229
|
-
return bearerToken;
|
|
243
|
+
throw new Error(`Failed to fetch access token. Response: ${lastErrorMessage}`);
|
|
230
244
|
}
|
|
231
245
|
exports.authSaasAPI = authSaasAPI;
|
|
232
246
|
async function authSmAPI() {
|