@camunda/e2e-test-suite 0.0.1218 → 0.0.1220
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.
|
@@ -351,6 +351,13 @@ class ModelerHomePage {
|
|
|
351
351
|
if (await committedProjectName.first().isVisible()) {
|
|
352
352
|
return;
|
|
353
353
|
}
|
|
354
|
+
// A failed create-project POST logs the SPA out on its own -- the tab
|
|
355
|
+
// bounces to the Auth0 login form (or lands on "Project not found") -- so
|
|
356
|
+
// the inline editor never mounts and every probe below waits out its
|
|
357
|
+
// budget on a page Modeler does not own. Recover the session first, the
|
|
358
|
+
// same primitive clickCreateNewProjectButton uses, so the re-creation
|
|
359
|
+
// branch below runs against Modeler rather than the login form.
|
|
360
|
+
await this.recoverModelerSession();
|
|
354
361
|
// The rename runs on a freshly created project, which is exactly when an
|
|
355
362
|
// announcement dialog mounts on top of it: it takes focus, the inline
|
|
356
363
|
// editor unmounts, and the click below then waits out its whole timeout
|
|
@@ -12,6 +12,7 @@ const apiHelpers_1 = require("../../utils/apiHelpers");
|
|
|
12
12
|
const expectLocatorWithRetry_1 = require("../../utils/assertionHelpers/expectLocatorWithRetry");
|
|
13
13
|
const users_1 = require("../../utils/users");
|
|
14
14
|
const connectorSecrets_1 = require("../../utils/connectorSecrets");
|
|
15
|
+
const constants_1 = require("../../utils/constants");
|
|
15
16
|
const testUser = (0, users_1.getTestUser)('seventeenthUser');
|
|
16
17
|
_8_10_1.test.describe.configure({ mode: 'parallel' });
|
|
17
18
|
_8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
@@ -271,19 +272,21 @@ _8_10_1.test.describe('Connectors User Flow Tests @tasklistV2', () => {
|
|
|
271
272
|
await operateHomePage.clickProcessesTab();
|
|
272
273
|
await operateProcessesPage.clickProcessCompletedCheckbox();
|
|
273
274
|
await operateProcessesPage.clickProcessInstanceLink(processName);
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
275
|
+
// Poll the instance deep link rather than reloading whatever page the
|
|
276
|
+
// tab is left on, the same way the identical processes-list flow in
|
|
277
|
+
// smoke-tests.spec.ts does. The completed filter also lists still-ACTIVE
|
|
278
|
+
// instances, so the link is regularly opened before this flow's REST
|
|
279
|
+
// connector has finished round-tripping to a real AWS endpoint, and
|
|
280
|
+
// expectLocatorWithRetry is blind to both that and to Operate's 404
|
|
281
|
+
// bounce: it reported only "Failed to assert visibility locator ...
|
|
282
|
+
// after 4 attempts" (run 35595548687) without saying which state the
|
|
283
|
+
// header had reached. waitForInstanceLocator re-asks Operate every few
|
|
284
|
+
// seconds within the same budget the other import gates use, names the
|
|
285
|
+
// rendered state on timeout, and fails immediately with the incident
|
|
286
|
+
// text when the connector job raised one -- COMPLETED is unreachable
|
|
287
|
+
// then, so waiting out the budget only hides the cause.
|
|
288
|
+
await operateProcessInstancePage.rememberInstanceUrl(constants_1.TIMEOUT.navigation);
|
|
289
|
+
await operateProcessInstancePage.waitForInstanceLocator(operateProcessInstancePage.completedIcon, 'Completed icon', constants_1.TIMEOUT.processImport);
|
|
287
290
|
await (0, expectLocatorWithRetry_1.expectLocatorWithRetry)(page, operateProcessInstancePage.variablesList, {
|
|
288
291
|
postAction: async () => {
|
|
289
292
|
await page.reload();
|
|
@@ -177,11 +177,12 @@ _8_10_1.test.describe('Optimize Sharing & Export UI Tests @optimize-sharing-aler
|
|
|
177
177
|
});
|
|
178
178
|
(0, _8_10_1.test)('Enable dashboard sharing and expose a public share link', async ({ appsPage, optimizeHomePage, optimizeSharePage, }) => {
|
|
179
179
|
await _8_10_1.test.step('Open Optimize from the Camunda apps launcher', async () => {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
180
|
+
// Same retrying opener as the two tests above, for the same reason: a
|
|
181
|
+
// /sso-callback that answers 401 leaves the tab on a blank page that
|
|
182
|
+
// never renders the banner, and polling it can only watch that dead
|
|
183
|
+
// page time out (`expect(received).toBe(expected)` after 120s). Only
|
|
184
|
+
// re-entering through the apps menu starts a fresh hand-off.
|
|
185
|
+
await appsPage.openOptimizeWithRetry(optimizeHomePage.optimizeBanner, clusterName);
|
|
185
186
|
});
|
|
186
187
|
await _8_10_1.test.step('Navigate to the seeded dashboard', async () => {
|
|
187
188
|
await optimizeSharePage.openEntityById(baseUrl, 'dashboard', dashboardId);
|
package/dist/utils/apiHelpers.js
CHANGED
|
@@ -740,6 +740,28 @@ async function probeOptimizeSession(page) {
|
|
|
740
740
|
}
|
|
741
741
|
return token;
|
|
742
742
|
}
|
|
743
|
+
// Starts a fresh OIDC code exchange with Optimize without touching the
|
|
744
|
+
// identity provider session. The 401 that probeOptimizeSession catches is the
|
|
745
|
+
// cluster rejecting one exchange, not the IdP rejecting the user: the Auth0
|
|
746
|
+
// session minted moments earlier is still valid, so navigating to Optimize
|
|
747
|
+
// again sends the browser back through the IdP, which answers from that
|
|
748
|
+
// session and returns a brand new code. That costs seconds and no Auth0
|
|
749
|
+
// credential round trip, where a full re-login costs another interactive
|
|
750
|
+
// sign-in plus the minutes of backoff that precede it -- and there are only
|
|
751
|
+
// four of those before the caller's beforeAll fails outright with
|
|
752
|
+
// OPTIMIZE_SESSION_UNAUTHENTICATED.
|
|
753
|
+
async function redoOptimizeSsoHandshake(page) {
|
|
754
|
+
const optimizeUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
755
|
+
await page.goto(optimizeUrl, { waitUntil: 'domcontentloaded', timeout: 60000 });
|
|
756
|
+
// The redirect chain has to land back on Optimize for the exchange to have
|
|
757
|
+
// completed. A chain that stops anywhere else (the IdP asking for
|
|
758
|
+
// credentials again, another rejected callback) throws a waitForURL
|
|
759
|
+
// timeout, which the caller's catch already classifies and backs off for.
|
|
760
|
+
await page.waitForURL((url) => url.toString().startsWith(optimizeUrl), {
|
|
761
|
+
timeout: 60000,
|
|
762
|
+
waitUntil: 'commit',
|
|
763
|
+
});
|
|
764
|
+
}
|
|
743
765
|
async function performOptimizeInteractiveLogin(page, callerLabel, verifySession) {
|
|
744
766
|
const optimizeUrl = process.env.CAMUNDA_OPTIMIZE_BASE_URL;
|
|
745
767
|
const maxLoginAttempts = 4;
|
|
@@ -764,7 +786,15 @@ async function performOptimizeInteractiveLogin(page, callerLabel, verifySession)
|
|
|
764
786
|
await page.context().clearCookies();
|
|
765
787
|
await (0, utils_1.loginToApp)(optimizeUrl, page);
|
|
766
788
|
if (verifySession && !(await verifySession(page))) {
|
|
767
|
-
|
|
789
|
+
// Redo the hand-off once before writing the attempt off: the rejected
|
|
790
|
+
// exchange is what has to be replaced, and re-navigating replaces it
|
|
791
|
+
// for seconds (see redoOptimizeSsoHandshake). Only when a second,
|
|
792
|
+
// freshly minted exchange is also unauthenticated is the login itself
|
|
793
|
+
// worth repeating.
|
|
794
|
+
await redoOptimizeSsoHandshake(page);
|
|
795
|
+
if (!(await verifySession(page))) {
|
|
796
|
+
throw new Error(OPTIMIZE_SESSION_UNAUTHENTICATED);
|
|
797
|
+
}
|
|
768
798
|
}
|
|
769
799
|
return;
|
|
770
800
|
}
|