@camunda/e2e-test-suite 0.0.1468 → 0.0.1470

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.
@@ -66,8 +66,14 @@ export declare function isAtModelerLoginRoute(page: Page): boolean;
66
66
  * the moment the session is accepted, and otherwise spends the wait backing
67
67
  * off.
68
68
  *
69
+ * Every healthy reload also passes through `/login?returnUrl=...` while the
70
+ * session call is in flight, and callers often check right after a
71
+ * `domcontentloaded` reload. So the page only counts as stuck once it has stayed
72
+ * on `/login` for `graceTimeout`; reloading earlier interrupts a working
73
+ * hand-off and sends a second session call for the same user.
74
+ *
69
75
  * Cheap to call speculatively -- a page that is not on `/login` costs one URL
70
76
  * comparison and no DOM access, which is what lets the Modeler page objects
71
77
  * guard their navigations with it.
72
78
  */
73
- export declare function recoverStuckModelerLogin(page: Page, attempts?: number, settleTimeout?: number): Promise<boolean>;
79
+ export declare function recoverStuckModelerLogin(page: Page, attempts?: number, settleTimeout?: number, graceTimeout?: number): Promise<boolean>;
@@ -15,8 +15,48 @@ const signedInUser = new WeakMap();
15
15
  */
16
16
  function trackSignedInUser(page, username) {
17
17
  signedInUser.set(page, username);
18
+ watchModelerSessionCalls(page);
18
19
  }
19
20
  exports.trackSignedInUser = trackSignedInUser;
21
+ const SESSION_CALL_PATH = /\/api\/internal\/login\/?$/;
22
+ // The status of the last `POST /api/internal/login` this page received, so a
23
+ // "stuck on /login" verdict can say what the backend actually answered rather
24
+ // than assume a 5xx from the URL alone.
25
+ const lastSessionCallStatus = new WeakMap();
26
+ const watchedPages = new WeakSet();
27
+ function watchModelerSessionCalls(page) {
28
+ if (watchedPages.has(page)) {
29
+ return;
30
+ }
31
+ watchedPages.add(page);
32
+ page.on('response', (response) => {
33
+ if (response.request().method() !== 'POST') {
34
+ return;
35
+ }
36
+ let pathname;
37
+ try {
38
+ pathname = new URL(response.url()).pathname;
39
+ }
40
+ catch {
41
+ return;
42
+ }
43
+ if (!SESSION_CALL_PATH.test(pathname)) {
44
+ return;
45
+ }
46
+ const status = response.status();
47
+ lastSessionCallStatus.set(page, status);
48
+ if (status >= 500) {
49
+ console.warn(`Modeler session call failed: POST ${response.url()} answered ` +
50
+ `${status} at ${new Date().toISOString()}`);
51
+ }
52
+ });
53
+ }
54
+ function describeLastSessionCall(page) {
55
+ const status = lastSessionCallStatus.get(page);
56
+ return status === undefined
57
+ ? 'no response to POST /api/internal/login was seen'
58
+ : `the last POST /api/internal/login answered ${status}`;
59
+ }
20
60
  // Read back out of the environment at the moment it is needed, from the
21
61
  // `C8_USERNAME*` / `C8_PASSWORD*` pair that defines this user -- the same
22
62
  // source LoginPage reads its own defaults from. Nothing secret is carried
@@ -189,17 +229,35 @@ exports.isAtModelerLoginRoute = isAtModelerLoginRoute;
189
229
  * the moment the session is accepted, and otherwise spends the wait backing
190
230
  * off.
191
231
  *
232
+ * Every healthy reload also passes through `/login?returnUrl=...` while the
233
+ * session call is in flight, and callers often check right after a
234
+ * `domcontentloaded` reload. So the page only counts as stuck once it has stayed
235
+ * on `/login` for `graceTimeout`; reloading earlier interrupts a working
236
+ * hand-off and sends a second session call for the same user.
237
+ *
192
238
  * Cheap to call speculatively -- a page that is not on `/login` costs one URL
193
239
  * comparison and no DOM access, which is what lets the Modeler page objects
194
240
  * guard their navigations with it.
195
241
  */
196
- async function recoverStuckModelerLogin(page, attempts = 4, settleTimeout = 25000) {
242
+ async function recoverStuckModelerLogin(page, attempts = 4, settleTimeout = 25000, graceTimeout = 20000) {
197
243
  if (!isAtModelerLoginRoute(page)) {
198
244
  return false;
199
245
  }
246
+ watchModelerSessionCalls(page);
247
+ const leftOnItsOwn = await page
248
+ .waitForURL((url) => !LOGIN_ROUTE.test(url.pathname), {
249
+ timeout: graceTimeout,
250
+ waitUntil: 'commit',
251
+ })
252
+ .then(() => true)
253
+ .catch(() => false);
254
+ if (leftOnItsOwn) {
255
+ return false;
256
+ }
200
257
  for (let attempt = 1; attempt <= attempts; attempt++) {
201
- console.warn(`recoverStuckModelerLogin: Modeler is stuck on ${page.url()} -- its ` +
202
- `POST /api/internal/login is failing. Reload ${attempt}/${attempts}.`);
258
+ console.warn(`recoverStuckModelerLogin: Modeler is still on ${page.url()} after ` +
259
+ `${graceTimeout / 1000}s; ${describeLastSessionCall(page)}. ` +
260
+ `Reload ${attempt}/${attempts}.`);
203
261
  await page
204
262
  .reload({ waitUntil: 'domcontentloaded', timeout: 60000 })
205
263
  .catch(() => undefined);
@@ -212,6 +270,7 @@ async function recoverStuckModelerLogin(page, attempts = 4, settleTimeout = 2500
212
270
  const recovered = await page
213
271
  .waitForURL((url) => !LOGIN_ROUTE.test(url.pathname), {
214
272
  timeout: settleTimeout,
273
+ waitUntil: 'commit',
215
274
  })
216
275
  .then(() => true)
217
276
  .catch(() => false);
@@ -219,8 +278,8 @@ async function recoverStuckModelerLogin(page, attempts = 4, settleTimeout = 2500
219
278
  return true;
220
279
  }
221
280
  }
222
- console.warn('recoverStuckModelerLogin: Modeler never left /login -- its backend is ' +
223
- 'still failing the session call.');
281
+ console.warn(`recoverStuckModelerLogin: Modeler never left /login; ` +
282
+ `${describeLastSessionCall(page)}.`);
224
283
  return true;
225
284
  }
226
285
  exports.recoverStuckModelerLogin = recoverStuckModelerLogin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/e2e-test-suite",
3
- "version": "0.0.1468",
3
+ "version": "0.0.1470",
4
4
  "description": "End-to-end test helpers for Camunda 8",
5
5
  "repository": {
6
6
  "type": "git",