@opensteer/engine-playwright 0.8.2 → 0.8.3
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/index.cjs +509 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -15
- package/dist/index.d.ts +52 -15
- package/dist/index.js +509 -81
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1279,19 +1279,24 @@ function normalizePostLoadTrackerState(value) {
|
|
|
1279
1279
|
const installedAt = readFiniteNumber(value.installedAt);
|
|
1280
1280
|
const lastMutationAt = readFiniteNumber(value.lastMutationAt);
|
|
1281
1281
|
const lastNetworkActivityAt = readFiniteNumber(value.lastNetworkActivityAt);
|
|
1282
|
+
const lastTrackedNetworkActivityAt = readFiniteNumber(value.lastTrackedNetworkActivityAt);
|
|
1282
1283
|
const now = readFiniteNumber(value.now);
|
|
1283
1284
|
const readyState = typeof value.readyState === "string" ? value.readyState : void 0;
|
|
1284
|
-
if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
|
|
1285
|
+
if (installedAt === void 0 || lastMutationAt === void 0 || lastNetworkActivityAt === void 0 || lastTrackedNetworkActivityAt === void 0 || now === void 0 || readyState === void 0) {
|
|
1285
1286
|
return void 0;
|
|
1286
1287
|
}
|
|
1287
1288
|
return {
|
|
1288
1289
|
installedAt,
|
|
1289
1290
|
lastMutationAt,
|
|
1290
1291
|
lastNetworkActivityAt,
|
|
1292
|
+
lastTrackedNetworkActivityAt,
|
|
1291
1293
|
now,
|
|
1292
1294
|
pendingFetches: readNonNegativeNumber(value.pendingFetches),
|
|
1293
1295
|
pendingTimeouts: readNonNegativeNumber(value.pendingTimeouts),
|
|
1294
1296
|
pendingXhrs: readNonNegativeNumber(value.pendingXhrs),
|
|
1297
|
+
trackedPendingFetches: readNonNegativeNumber(value.trackedPendingFetches),
|
|
1298
|
+
trackedPendingXhrs: readNonNegativeNumber(value.trackedPendingXhrs),
|
|
1299
|
+
collecting: value.collecting === true,
|
|
1295
1300
|
readyState
|
|
1296
1301
|
};
|
|
1297
1302
|
}
|
|
@@ -1306,11 +1311,14 @@ function buildPostLoadTrackerInstallScript() {
|
|
|
1306
1311
|
installedAt: performance.now(),
|
|
1307
1312
|
lastMutationAt: performance.now(),
|
|
1308
1313
|
lastNetworkActivityAt: performance.now(),
|
|
1314
|
+
lastTrackedNetworkActivityAt: performance.now(),
|
|
1309
1315
|
pendingFetches: 0,
|
|
1310
1316
|
pendingTimeouts: 0,
|
|
1311
1317
|
pendingXhrs: 0,
|
|
1318
|
+
trackedPendingFetches: 0,
|
|
1319
|
+
trackedPendingXhrs: 0,
|
|
1320
|
+
collecting: true,
|
|
1312
1321
|
readyState: document.readyState,
|
|
1313
|
-
timeoutIds: new Set(),
|
|
1314
1322
|
};
|
|
1315
1323
|
globalObject.__opensteerActionBoundaryTrackerInstalled = true;
|
|
1316
1324
|
globalObject.__opensteerActionBoundaryTracker = tracker;
|
|
@@ -1323,6 +1331,18 @@ function buildPostLoadTrackerInstallScript() {
|
|
|
1323
1331
|
tracker.lastNetworkActivityAt = performance.now();
|
|
1324
1332
|
tracker.readyState = document.readyState;
|
|
1325
1333
|
};
|
|
1334
|
+
const markTrackedNetwork = () => {
|
|
1335
|
+
tracker.lastTrackedNetworkActivityAt = performance.now();
|
|
1336
|
+
markNetwork();
|
|
1337
|
+
};
|
|
1338
|
+
const resetTracking = () => {
|
|
1339
|
+
const now = performance.now();
|
|
1340
|
+
tracker.lastTrackedNetworkActivityAt = now;
|
|
1341
|
+
tracker.trackedPendingFetches = 0;
|
|
1342
|
+
tracker.trackedPendingXhrs = 0;
|
|
1343
|
+
tracker.collecting = true;
|
|
1344
|
+
tracker.readyState = document.readyState;
|
|
1345
|
+
};
|
|
1326
1346
|
|
|
1327
1347
|
const startObserver = () => {
|
|
1328
1348
|
const target = document.documentElement ?? document;
|
|
@@ -1348,45 +1368,26 @@ function buildPostLoadTrackerInstallScript() {
|
|
|
1348
1368
|
document.addEventListener("readystatechange", markMutation);
|
|
1349
1369
|
addEventListener("load", markMutation, { once: true });
|
|
1350
1370
|
|
|
1351
|
-
const nativeSetTimeout = globalObject.setTimeout.bind(globalObject);
|
|
1352
|
-
const nativeClearTimeout = globalObject.clearTimeout.bind(globalObject);
|
|
1353
|
-
globalObject.setTimeout = function(callback, delay, ...args) {
|
|
1354
|
-
tracker.pendingTimeouts += 1;
|
|
1355
|
-
markNetwork();
|
|
1356
|
-
let handle;
|
|
1357
|
-
const wrapped =
|
|
1358
|
-
typeof callback === "function"
|
|
1359
|
-
? (...callbackArgs) => {
|
|
1360
|
-
if (tracker.timeoutIds.delete(handle)) {
|
|
1361
|
-
tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
|
|
1362
|
-
}
|
|
1363
|
-
try {
|
|
1364
|
-
return callback(...callbackArgs);
|
|
1365
|
-
} finally {
|
|
1366
|
-
markMutation();
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
: callback;
|
|
1370
|
-
handle = nativeSetTimeout(wrapped, delay, ...args);
|
|
1371
|
-
tracker.timeoutIds.add(handle);
|
|
1372
|
-
return handle;
|
|
1373
|
-
};
|
|
1374
|
-
globalObject.clearTimeout = function(handle) {
|
|
1375
|
-
if (tracker.timeoutIds.delete(handle)) {
|
|
1376
|
-
tracker.pendingTimeouts = Math.max(0, tracker.pendingTimeouts - 1);
|
|
1377
|
-
}
|
|
1378
|
-
return nativeClearTimeout(handle);
|
|
1379
|
-
};
|
|
1380
|
-
|
|
1381
1371
|
if (typeof globalObject.fetch === "function") {
|
|
1382
1372
|
const nativeFetch = globalObject.fetch.bind(globalObject);
|
|
1383
1373
|
globalObject.fetch = (...args) => {
|
|
1374
|
+
const tracked = tracker.collecting === true;
|
|
1384
1375
|
tracker.pendingFetches += 1;
|
|
1385
|
-
|
|
1376
|
+
if (tracked) {
|
|
1377
|
+
tracker.trackedPendingFetches += 1;
|
|
1378
|
+
markTrackedNetwork();
|
|
1379
|
+
} else {
|
|
1380
|
+
markNetwork();
|
|
1381
|
+
}
|
|
1386
1382
|
return nativeFetch(...args)
|
|
1387
1383
|
.finally(() => {
|
|
1388
1384
|
tracker.pendingFetches = Math.max(0, tracker.pendingFetches - 1);
|
|
1389
|
-
|
|
1385
|
+
if (tracked) {
|
|
1386
|
+
tracker.trackedPendingFetches = Math.max(0, tracker.trackedPendingFetches - 1);
|
|
1387
|
+
markTrackedNetwork();
|
|
1388
|
+
} else {
|
|
1389
|
+
markNetwork();
|
|
1390
|
+
}
|
|
1390
1391
|
});
|
|
1391
1392
|
};
|
|
1392
1393
|
}
|
|
@@ -1395,21 +1396,60 @@ function buildPostLoadTrackerInstallScript() {
|
|
|
1395
1396
|
const NativeXMLHttpRequest = globalObject.XMLHttpRequest;
|
|
1396
1397
|
const nativeSend = NativeXMLHttpRequest.prototype.send;
|
|
1397
1398
|
NativeXMLHttpRequest.prototype.send = function(...args) {
|
|
1399
|
+
const tracked = tracker.collecting === true;
|
|
1398
1400
|
tracker.pendingXhrs += 1;
|
|
1399
|
-
|
|
1401
|
+
if (tracked) {
|
|
1402
|
+
tracker.trackedPendingXhrs += 1;
|
|
1403
|
+
markTrackedNetwork();
|
|
1404
|
+
} else {
|
|
1405
|
+
markNetwork();
|
|
1406
|
+
}
|
|
1400
1407
|
const finalize = () => {
|
|
1401
1408
|
this.removeEventListener("loadend", finalize);
|
|
1402
1409
|
tracker.pendingXhrs = Math.max(0, tracker.pendingXhrs - 1);
|
|
1403
|
-
|
|
1410
|
+
if (tracked) {
|
|
1411
|
+
tracker.trackedPendingXhrs = Math.max(0, tracker.trackedPendingXhrs - 1);
|
|
1412
|
+
markTrackedNetwork();
|
|
1413
|
+
} else {
|
|
1414
|
+
markNetwork();
|
|
1415
|
+
}
|
|
1404
1416
|
};
|
|
1405
1417
|
this.addEventListener("loadend", finalize, { once: true });
|
|
1406
1418
|
return nativeSend.apply(this, args);
|
|
1407
1419
|
};
|
|
1408
1420
|
}
|
|
1409
1421
|
|
|
1422
|
+
tracker.beginObservation = () => {
|
|
1423
|
+
resetTracking();
|
|
1424
|
+
return true;
|
|
1425
|
+
};
|
|
1426
|
+
tracker.freezeObservation = () => {
|
|
1427
|
+
tracker.collecting = false;
|
|
1428
|
+
tracker.readyState = document.readyState;
|
|
1429
|
+
return true;
|
|
1430
|
+
};
|
|
1431
|
+
|
|
1410
1432
|
return true;
|
|
1411
1433
|
})()`;
|
|
1412
1434
|
}
|
|
1435
|
+
function buildPostLoadTrackerBeginExpression() {
|
|
1436
|
+
return `(() => {
|
|
1437
|
+
const tracker = globalThis.__opensteerActionBoundaryTracker;
|
|
1438
|
+
if (!tracker || typeof tracker.beginObservation !== "function") {
|
|
1439
|
+
return false;
|
|
1440
|
+
}
|
|
1441
|
+
return tracker.beginObservation();
|
|
1442
|
+
})()`;
|
|
1443
|
+
}
|
|
1444
|
+
function buildPostLoadTrackerFreezeExpression() {
|
|
1445
|
+
return `(() => {
|
|
1446
|
+
const tracker = globalThis.__opensteerActionBoundaryTracker;
|
|
1447
|
+
if (!tracker || typeof tracker.freezeObservation !== "function") {
|
|
1448
|
+
return false;
|
|
1449
|
+
}
|
|
1450
|
+
return tracker.freezeObservation();
|
|
1451
|
+
})()`;
|
|
1452
|
+
}
|
|
1413
1453
|
function buildPostLoadTrackerReadExpression() {
|
|
1414
1454
|
return `(() => {
|
|
1415
1455
|
const tracker = globalThis.__opensteerActionBoundaryTracker;
|
|
@@ -1421,14 +1461,31 @@ function buildPostLoadTrackerReadExpression() {
|
|
|
1421
1461
|
installedAt: Number(tracker.installedAt ?? 0),
|
|
1422
1462
|
lastMutationAt: Number(tracker.lastMutationAt ?? 0),
|
|
1423
1463
|
lastNetworkActivityAt: Number(tracker.lastNetworkActivityAt ?? 0),
|
|
1464
|
+
lastTrackedNetworkActivityAt: Number(tracker.lastTrackedNetworkActivityAt ?? 0),
|
|
1424
1465
|
now: Number(performance.now()),
|
|
1425
1466
|
pendingFetches: Number(tracker.pendingFetches ?? 0),
|
|
1426
1467
|
pendingTimeouts: Number(tracker.pendingTimeouts ?? 0),
|
|
1427
1468
|
pendingXhrs: Number(tracker.pendingXhrs ?? 0),
|
|
1469
|
+
trackedPendingFetches: Number(tracker.trackedPendingFetches ?? 0),
|
|
1470
|
+
trackedPendingXhrs: Number(tracker.trackedPendingXhrs ?? 0),
|
|
1471
|
+
collecting: tracker.collecting === true,
|
|
1428
1472
|
readyState: String(document.readyState),
|
|
1429
1473
|
};
|
|
1430
1474
|
})()`;
|
|
1431
1475
|
}
|
|
1476
|
+
function capturePostLoadTrackerSnapshot(tracker) {
|
|
1477
|
+
return {
|
|
1478
|
+
lastTrackedNetworkActivityAt: tracker.lastTrackedNetworkActivityAt,
|
|
1479
|
+
trackedPendingFetches: tracker.trackedPendingFetches,
|
|
1480
|
+
trackedPendingXhrs: tracker.trackedPendingXhrs
|
|
1481
|
+
};
|
|
1482
|
+
}
|
|
1483
|
+
function postLoadTrackerHasTrackedNetworkActivitySince(snapshot, tracker) {
|
|
1484
|
+
if (!tracker) {
|
|
1485
|
+
return false;
|
|
1486
|
+
}
|
|
1487
|
+
return tracker.trackedPendingFetches > snapshot.trackedPendingFetches || tracker.trackedPendingXhrs > snapshot.trackedPendingXhrs || tracker.lastTrackedNetworkActivityAt > snapshot.lastTrackedNetworkActivityAt;
|
|
1488
|
+
}
|
|
1432
1489
|
function postLoadTrackerIsSettled(tracker, quietWindowMs = DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS) {
|
|
1433
1490
|
if (!tracker) {
|
|
1434
1491
|
return false;
|
|
@@ -1436,13 +1493,13 @@ function postLoadTrackerIsSettled(tracker, quietWindowMs = DEFAULT_POST_LOAD_TRA
|
|
|
1436
1493
|
if (tracker.readyState !== "complete") {
|
|
1437
1494
|
return false;
|
|
1438
1495
|
}
|
|
1439
|
-
if (tracker.
|
|
1496
|
+
if (tracker.trackedPendingFetches > 0 || tracker.trackedPendingXhrs > 0) {
|
|
1440
1497
|
return false;
|
|
1441
1498
|
}
|
|
1442
1499
|
const lastActivityAt = Math.max(
|
|
1443
1500
|
tracker.installedAt,
|
|
1444
1501
|
tracker.lastMutationAt,
|
|
1445
|
-
tracker.
|
|
1502
|
+
tracker.lastTrackedNetworkActivityAt
|
|
1446
1503
|
);
|
|
1447
1504
|
return tracker.now - lastActivityAt >= quietWindowMs;
|
|
1448
1505
|
}
|
|
@@ -1464,7 +1521,7 @@ async function waitForActionBoundary(input) {
|
|
|
1464
1521
|
const pollIntervalMs = input.pollIntervalMs ?? DEFAULT_ACTION_BOUNDARY_POLL_INTERVAL_MS;
|
|
1465
1522
|
let trigger = "dom-action";
|
|
1466
1523
|
let crossDocument = false;
|
|
1467
|
-
let
|
|
1524
|
+
let sameDocumentAsyncActivity = false;
|
|
1468
1525
|
while (Date.now() < deadline) {
|
|
1469
1526
|
input.throwBackgroundError();
|
|
1470
1527
|
if (input.isPageClosed()) {
|
|
@@ -1486,16 +1543,21 @@ async function waitForActionBoundary(input) {
|
|
|
1486
1543
|
throw abortError(input.signal);
|
|
1487
1544
|
}
|
|
1488
1545
|
const currentDocumentRef = input.getCurrentMainFrameDocumentRef();
|
|
1546
|
+
const currentPageUrl = input.getCurrentPageUrl?.();
|
|
1489
1547
|
if (input.snapshot !== void 0 && currentDocumentRef !== void 0 && currentDocumentRef !== input.snapshot.documentRef) {
|
|
1490
1548
|
trigger = "navigation";
|
|
1491
1549
|
crossDocument = true;
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1550
|
+
}
|
|
1551
|
+
if (!crossDocument && !sameDocumentAsyncActivity && input.snapshot?.tracker !== void 0 && postLoadTrackerHasTrackedNetworkActivitySince(
|
|
1552
|
+
input.snapshot.tracker,
|
|
1553
|
+
await input.readTrackerState()
|
|
1554
|
+
)) {
|
|
1555
|
+
trigger = "navigation";
|
|
1556
|
+
sameDocumentAsyncActivity = true;
|
|
1557
|
+
}
|
|
1558
|
+
if (!crossDocument && input.snapshot?.url !== void 0 && currentPageUrl !== void 0 && currentPageUrl !== input.snapshot.url && input.isCurrentMainFrameBootstrapSettled !== void 0 && !input.isCurrentMainFrameBootstrapSettled()) {
|
|
1559
|
+
trigger = "navigation";
|
|
1560
|
+
crossDocument = true;
|
|
1499
1561
|
}
|
|
1500
1562
|
if (!crossDocument && crossDocumentDetectionDeadline !== void 0 && Date.now() >= crossDocumentDetectionDeadline) {
|
|
1501
1563
|
return {
|
|
@@ -1504,7 +1566,18 @@ async function waitForActionBoundary(input) {
|
|
|
1504
1566
|
bootstrapSettled: true
|
|
1505
1567
|
};
|
|
1506
1568
|
}
|
|
1507
|
-
if (
|
|
1569
|
+
if (sameDocumentAsyncActivity) {
|
|
1570
|
+
return {
|
|
1571
|
+
trigger,
|
|
1572
|
+
crossDocument,
|
|
1573
|
+
bootstrapSettled: true
|
|
1574
|
+
};
|
|
1575
|
+
}
|
|
1576
|
+
if (crossDocument && input.isCurrentMainFrameBootstrapSettled !== void 0 && !input.isCurrentMainFrameBootstrapSettled()) {
|
|
1577
|
+
await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
|
|
1578
|
+
continue;
|
|
1579
|
+
}
|
|
1580
|
+
if (crossDocument) {
|
|
1508
1581
|
return {
|
|
1509
1582
|
trigger,
|
|
1510
1583
|
crossDocument,
|
|
@@ -3439,6 +3512,7 @@ async function releaseObject(controller, objectId) {
|
|
|
3439
3512
|
|
|
3440
3513
|
// src/action-settle.ts
|
|
3441
3514
|
var DEFAULT_PLAYWRIGHT_ACTION_SETTLE_TIMEOUT_MS = CROSS_DOCUMENT_INTERACTION_TIMEOUT_MS;
|
|
3515
|
+
var DEFAULT_PLAYWRIGHT_POST_LOAD_CAPTURE_WINDOW_MS = 1e3;
|
|
3442
3516
|
function clampPlaywrightActionSettleTimeout(timeoutMs) {
|
|
3443
3517
|
if (timeoutMs === void 0) {
|
|
3444
3518
|
return DEFAULT_PLAYWRIGHT_ACTION_SETTLE_TIMEOUT_MS;
|
|
@@ -3447,6 +3521,8 @@ function clampPlaywrightActionSettleTimeout(timeoutMs) {
|
|
|
3447
3521
|
}
|
|
3448
3522
|
function createPlaywrightActionSettler(context) {
|
|
3449
3523
|
const installScript = buildPostLoadTrackerInstallScript();
|
|
3524
|
+
const beginExpression = buildPostLoadTrackerBeginExpression();
|
|
3525
|
+
const freezeExpression = buildPostLoadTrackerFreezeExpression();
|
|
3450
3526
|
const readExpression = buildPostLoadTrackerReadExpression();
|
|
3451
3527
|
async function installTracker(controller) {
|
|
3452
3528
|
if (!controller.settleTrackerRegistered) {
|
|
@@ -3481,6 +3557,79 @@ function createPlaywrightActionSettler(context) {
|
|
|
3481
3557
|
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3482
3558
|
}
|
|
3483
3559
|
}
|
|
3560
|
+
async function beginTrackerObservation(controller) {
|
|
3561
|
+
await installTracker(controller);
|
|
3562
|
+
try {
|
|
3563
|
+
await controller.cdp.send("Runtime.evaluate", {
|
|
3564
|
+
expression: beginExpression,
|
|
3565
|
+
returnByValue: true,
|
|
3566
|
+
awaitPromise: true
|
|
3567
|
+
});
|
|
3568
|
+
} catch (error) {
|
|
3569
|
+
if (isIgnorableTrackerReadError(error)) {
|
|
3570
|
+
return;
|
|
3571
|
+
}
|
|
3572
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
async function freezeTrackerObservation(controller) {
|
|
3576
|
+
try {
|
|
3577
|
+
await controller.cdp.send("Runtime.evaluate", {
|
|
3578
|
+
expression: freezeExpression,
|
|
3579
|
+
returnByValue: true,
|
|
3580
|
+
awaitPromise: true
|
|
3581
|
+
});
|
|
3582
|
+
} catch (error) {
|
|
3583
|
+
if (isIgnorableTrackerReadError(error)) {
|
|
3584
|
+
return;
|
|
3585
|
+
}
|
|
3586
|
+
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3587
|
+
}
|
|
3588
|
+
}
|
|
3589
|
+
async function captureSnapshot(controller) {
|
|
3590
|
+
const documentRef = context.getMainFrameDocumentRef(controller);
|
|
3591
|
+
if (documentRef === void 0) {
|
|
3592
|
+
throw new Error(`page ${controller.pageRef} does not expose a main frame`);
|
|
3593
|
+
}
|
|
3594
|
+
await beginTrackerObservation(controller);
|
|
3595
|
+
const tracker = await readTrackerState(controller);
|
|
3596
|
+
return {
|
|
3597
|
+
pageRef: controller.pageRef,
|
|
3598
|
+
documentRef,
|
|
3599
|
+
url: controller.page.url(),
|
|
3600
|
+
...tracker === void 0 ? {} : { tracker: capturePostLoadTrackerSnapshot(tracker) }
|
|
3601
|
+
};
|
|
3602
|
+
}
|
|
3603
|
+
async function waitForPostLoadQuiet(input) {
|
|
3604
|
+
const { controller, timeoutMs, signal } = input;
|
|
3605
|
+
if (timeoutMs <= 0) {
|
|
3606
|
+
return;
|
|
3607
|
+
}
|
|
3608
|
+
const quietMs = input.quietMs ?? DEFAULT_POST_LOAD_TRACKER_QUIET_WINDOW_MS;
|
|
3609
|
+
const captureWindowMs = Math.max(
|
|
3610
|
+
0,
|
|
3611
|
+
Math.min(input.captureWindowMs ?? DEFAULT_PLAYWRIGHT_POST_LOAD_CAPTURE_WINDOW_MS, timeoutMs)
|
|
3612
|
+
);
|
|
3613
|
+
const deadline = Date.now() + timeoutMs;
|
|
3614
|
+
await installTracker(controller);
|
|
3615
|
+
if (captureWindowMs > 0) {
|
|
3616
|
+
await delayWithSignal2(captureWindowMs, signal, deadline);
|
|
3617
|
+
}
|
|
3618
|
+
await freezeTrackerObservation(controller);
|
|
3619
|
+
while (Date.now() < deadline) {
|
|
3620
|
+
if (signal?.aborted) {
|
|
3621
|
+
throw signal.reason ?? abortError2();
|
|
3622
|
+
}
|
|
3623
|
+
context.throwBackgroundError(controller);
|
|
3624
|
+
if (controller.lifecycleState === "closed") {
|
|
3625
|
+
return;
|
|
3626
|
+
}
|
|
3627
|
+
if (postLoadTrackerIsSettled(await readTrackerState(controller), quietMs)) {
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3630
|
+
await delayWithSignal2(100, signal, deadline);
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3484
3633
|
async function settle(options) {
|
|
3485
3634
|
const { controller, timeoutMs, signal, snapshot, policySettle } = options;
|
|
3486
3635
|
if (timeoutMs <= 0) {
|
|
@@ -3512,18 +3661,8 @@ function createPlaywrightActionSettler(context) {
|
|
|
3512
3661
|
...signal === void 0 ? {} : { signal },
|
|
3513
3662
|
snapshot,
|
|
3514
3663
|
getCurrentMainFrameDocumentRef: () => context.getMainFrameDocumentRef(controller),
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
await controller.page.waitForLoadState("domcontentloaded", {
|
|
3518
|
-
timeout: remainingMs
|
|
3519
|
-
});
|
|
3520
|
-
} catch (error) {
|
|
3521
|
-
if (controller.lifecycleState === "closed" || isContextClosedError(error)) {
|
|
3522
|
-
return;
|
|
3523
|
-
}
|
|
3524
|
-
throw normalizePlaywrightError(error, controller.pageRef);
|
|
3525
|
-
}
|
|
3526
|
-
},
|
|
3664
|
+
getCurrentPageUrl: () => controller.page.url(),
|
|
3665
|
+
isCurrentMainFrameBootstrapSettled: () => context.isCurrentMainFrameBootstrapSettled(controller),
|
|
3527
3666
|
readTrackerState: () => readTrackerState(controller),
|
|
3528
3667
|
throwBackgroundError: () => context.throwBackgroundError(controller),
|
|
3529
3668
|
isPageClosed: () => controller.lifecycleState === "closed"
|
|
@@ -3539,13 +3678,36 @@ function createPlaywrightActionSettler(context) {
|
|
|
3539
3678
|
return boundary;
|
|
3540
3679
|
}
|
|
3541
3680
|
return {
|
|
3681
|
+
captureSnapshot,
|
|
3542
3682
|
installTracker,
|
|
3683
|
+
waitForPostLoadQuiet,
|
|
3543
3684
|
settle
|
|
3544
3685
|
};
|
|
3545
3686
|
}
|
|
3546
3687
|
function abortError2() {
|
|
3547
3688
|
return new DOMException("The operation was aborted", "AbortError");
|
|
3548
3689
|
}
|
|
3690
|
+
async function delayWithSignal2(delayMs, signal, deadline) {
|
|
3691
|
+
const effectiveDelay = Math.max(0, Math.min(delayMs, Math.max(0, deadline - Date.now())));
|
|
3692
|
+
if (effectiveDelay <= 0) {
|
|
3693
|
+
return;
|
|
3694
|
+
}
|
|
3695
|
+
if (signal?.aborted) {
|
|
3696
|
+
throw signal.reason ?? abortError2();
|
|
3697
|
+
}
|
|
3698
|
+
await new Promise((resolve, reject) => {
|
|
3699
|
+
const timer = setTimeout(() => {
|
|
3700
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3701
|
+
resolve();
|
|
3702
|
+
}, effectiveDelay);
|
|
3703
|
+
const onAbort = () => {
|
|
3704
|
+
clearTimeout(timer);
|
|
3705
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3706
|
+
reject(signal?.reason ?? abortError2());
|
|
3707
|
+
};
|
|
3708
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
3709
|
+
});
|
|
3710
|
+
}
|
|
3549
3711
|
function isIgnorableTrackerReadError(error) {
|
|
3550
3712
|
return isContextClosedError(error) || error instanceof Error && /Execution context was destroyed|Cannot find context|Inspected target navigated or closed/i.test(
|
|
3551
3713
|
error.message
|
|
@@ -3743,6 +3905,71 @@ function cloneKeyPath(keyPath) {
|
|
|
3743
3905
|
}
|
|
3744
3906
|
|
|
3745
3907
|
// src/engine.ts
|
|
3908
|
+
var PLAYWRIGHT_RUNTIME_EVENT_RECORDER_SOURCE = String.raw`(() => {
|
|
3909
|
+
const key = "__opensteerRuntimeEventRecorder";
|
|
3910
|
+
const globalScope = globalThis;
|
|
3911
|
+
if (globalScope[key]?.installed === true) {
|
|
3912
|
+
return;
|
|
3913
|
+
}
|
|
3914
|
+
|
|
3915
|
+
const queue = [];
|
|
3916
|
+
const limit = 500;
|
|
3917
|
+
const asString = (value) => {
|
|
3918
|
+
if (typeof value === "string") {
|
|
3919
|
+
return value;
|
|
3920
|
+
}
|
|
3921
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null) {
|
|
3922
|
+
return String(value);
|
|
3923
|
+
}
|
|
3924
|
+
if (value === undefined) {
|
|
3925
|
+
return "undefined";
|
|
3926
|
+
}
|
|
3927
|
+
try {
|
|
3928
|
+
return JSON.stringify(value);
|
|
3929
|
+
} catch {
|
|
3930
|
+
return String(value);
|
|
3931
|
+
}
|
|
3932
|
+
};
|
|
3933
|
+
const enqueue = (entry) => {
|
|
3934
|
+
queue.push({
|
|
3935
|
+
...entry,
|
|
3936
|
+
timestamp: Date.now(),
|
|
3937
|
+
});
|
|
3938
|
+
if (queue.length > limit) {
|
|
3939
|
+
queue.splice(0, queue.length - limit);
|
|
3940
|
+
}
|
|
3941
|
+
};
|
|
3942
|
+
|
|
3943
|
+
globalScope.addEventListener("error", (event) => {
|
|
3944
|
+
enqueue({
|
|
3945
|
+
kind: "page-error",
|
|
3946
|
+
message:
|
|
3947
|
+
typeof event.message === "string" && event.message.length > 0
|
|
3948
|
+
? event.message
|
|
3949
|
+
: event.error?.message || "Uncaught exception",
|
|
3950
|
+
stack: typeof event.error?.stack === "string" ? event.error.stack : undefined,
|
|
3951
|
+
});
|
|
3952
|
+
});
|
|
3953
|
+
|
|
3954
|
+
globalScope.addEventListener("unhandledrejection", (event) => {
|
|
3955
|
+
const reason = event.reason;
|
|
3956
|
+
enqueue({
|
|
3957
|
+
kind: "page-error",
|
|
3958
|
+
message:
|
|
3959
|
+
typeof reason?.message === "string" && reason.message.length > 0
|
|
3960
|
+
? reason.message
|
|
3961
|
+
: asString(reason),
|
|
3962
|
+
stack: typeof reason?.stack === "string" ? reason.stack : undefined,
|
|
3963
|
+
});
|
|
3964
|
+
});
|
|
3965
|
+
|
|
3966
|
+
globalScope[key] = {
|
|
3967
|
+
installed: true,
|
|
3968
|
+
drain() {
|
|
3969
|
+
return queue.splice(0, queue.length);
|
|
3970
|
+
},
|
|
3971
|
+
};
|
|
3972
|
+
})();`;
|
|
3746
3973
|
var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
3747
3974
|
capabilities = PLAYWRIGHT_BROWSER_CORE_CAPABILITIES;
|
|
3748
3975
|
browser;
|
|
@@ -3762,6 +3989,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
3762
3989
|
flushPendingPageTasks: (sessionRef) => this.flushPendingPageTasks(sessionRef),
|
|
3763
3990
|
flushDomUpdateTask: (controller) => this.flushDomUpdateTask(controller),
|
|
3764
3991
|
getMainFrameDocumentRef: (controller) => controller.mainFrameRef === void 0 ? void 0 : this.frames.get(controller.mainFrameRef)?.currentDocument.documentRef,
|
|
3992
|
+
isCurrentMainFrameBootstrapSettled: (controller) => controller.mainFrameRef !== void 0 && this.frames.get(controller.mainFrameRef)?.currentDocument.domContentLoadedAt !== void 0,
|
|
3765
3993
|
throwBackgroundError: (controller) => this.throwBackgroundError(controller)
|
|
3766
3994
|
});
|
|
3767
3995
|
pageCounter = 0;
|
|
@@ -4174,11 +4402,15 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4174
4402
|
});
|
|
4175
4403
|
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4176
4404
|
const mainFrame = this.requireMainFrame(controller);
|
|
4405
|
+
const events = mergeDistinctStepEvents([
|
|
4406
|
+
...this.drainQueuedEvents(controller.pageRef),
|
|
4407
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4408
|
+
]);
|
|
4177
4409
|
return this.createStepResult(controller.sessionRef, controller.pageRef, startedAt, {
|
|
4178
4410
|
frameRef: mainFrame.frameRef,
|
|
4179
4411
|
documentRef: mainFrame.currentDocument.documentRef,
|
|
4180
4412
|
documentEpoch: mainFrame.currentDocument.documentEpoch,
|
|
4181
|
-
events
|
|
4413
|
+
events,
|
|
4182
4414
|
data: hit
|
|
4183
4415
|
});
|
|
4184
4416
|
}
|
|
@@ -4198,11 +4430,15 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4198
4430
|
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4199
4431
|
await this.flushDomUpdateTask(controller);
|
|
4200
4432
|
const mainFrame = this.requireMainFrame(controller);
|
|
4433
|
+
const events = mergeDistinctStepEvents([
|
|
4434
|
+
...this.drainQueuedEvents(controller.pageRef),
|
|
4435
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4436
|
+
]);
|
|
4201
4437
|
return this.createStepResult(controller.sessionRef, controller.pageRef, startedAt, {
|
|
4202
4438
|
frameRef: mainFrame.frameRef,
|
|
4203
4439
|
documentRef: mainFrame.currentDocument.documentRef,
|
|
4204
4440
|
documentEpoch: mainFrame.currentDocument.documentEpoch,
|
|
4205
|
-
events
|
|
4441
|
+
events,
|
|
4206
4442
|
data: void 0
|
|
4207
4443
|
});
|
|
4208
4444
|
}
|
|
@@ -4214,11 +4450,15 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4214
4450
|
});
|
|
4215
4451
|
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4216
4452
|
const mainFrame = this.requireMainFrame(controller);
|
|
4453
|
+
const events = mergeDistinctStepEvents([
|
|
4454
|
+
...this.drainQueuedEvents(controller.pageRef),
|
|
4455
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4456
|
+
]);
|
|
4217
4457
|
return this.createStepResult(controller.sessionRef, controller.pageRef, startedAt, {
|
|
4218
4458
|
frameRef: mainFrame.frameRef,
|
|
4219
4459
|
documentRef: mainFrame.currentDocument.documentRef,
|
|
4220
4460
|
documentEpoch: mainFrame.currentDocument.documentEpoch,
|
|
4221
|
-
events
|
|
4461
|
+
events,
|
|
4222
4462
|
data: void 0
|
|
4223
4463
|
});
|
|
4224
4464
|
}
|
|
@@ -4228,11 +4468,15 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4228
4468
|
await controller.page.keyboard.type(input.text);
|
|
4229
4469
|
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4230
4470
|
const mainFrame = this.requireMainFrame(controller);
|
|
4471
|
+
const events = mergeDistinctStepEvents([
|
|
4472
|
+
...this.drainQueuedEvents(controller.pageRef),
|
|
4473
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4474
|
+
]);
|
|
4231
4475
|
return this.createStepResult(controller.sessionRef, controller.pageRef, startedAt, {
|
|
4232
4476
|
frameRef: mainFrame.frameRef,
|
|
4233
4477
|
documentRef: mainFrame.currentDocument.documentRef,
|
|
4234
4478
|
documentEpoch: mainFrame.currentDocument.documentEpoch,
|
|
4235
|
-
events
|
|
4479
|
+
events,
|
|
4236
4480
|
data: void 0
|
|
4237
4481
|
});
|
|
4238
4482
|
}
|
|
@@ -4370,6 +4614,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4370
4614
|
}
|
|
4371
4615
|
return infos;
|
|
4372
4616
|
}
|
|
4617
|
+
async drainEvents(input) {
|
|
4618
|
+
const controller = this.requirePage(input.pageRef);
|
|
4619
|
+
return mergeDistinctStepEvents([
|
|
4620
|
+
...this.drainQueuedEvents(input.pageRef),
|
|
4621
|
+
...await this.drainInstrumentedRuntimeEvents(controller)
|
|
4622
|
+
]);
|
|
4623
|
+
}
|
|
4373
4624
|
async listFrames(input) {
|
|
4374
4625
|
const controller = this.requirePage(input.pageRef);
|
|
4375
4626
|
await this.flushDomUpdateTask(controller);
|
|
@@ -4421,6 +4672,12 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4421
4672
|
(contentDocIndex) => resolveCapturedContentDocumentRef(controller.framesByCdpId, captured, contentDocIndex)
|
|
4422
4673
|
);
|
|
4423
4674
|
}
|
|
4675
|
+
async getActionBoundarySnapshot(input) {
|
|
4676
|
+
const controller = this.requirePage(input.pageRef);
|
|
4677
|
+
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4678
|
+
await this.flushDomUpdateTask(controller);
|
|
4679
|
+
return this.actionSettler.captureSnapshot(controller);
|
|
4680
|
+
}
|
|
4424
4681
|
async waitForVisualStability(input) {
|
|
4425
4682
|
const controller = this.requirePage(input.pageRef);
|
|
4426
4683
|
await this.flushDomUpdateTask(controller);
|
|
@@ -4431,6 +4688,21 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4431
4688
|
});
|
|
4432
4689
|
await this.flushDomUpdateTask(controller);
|
|
4433
4690
|
}
|
|
4691
|
+
async waitForPostLoadQuiet(input) {
|
|
4692
|
+
const controller = this.requirePage(input.pageRef);
|
|
4693
|
+
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4694
|
+
await this.actionSettler.waitForPostLoadQuiet({
|
|
4695
|
+
controller,
|
|
4696
|
+
timeoutMs: clampPlaywrightActionSettleTimeout(input.timeoutMs),
|
|
4697
|
+
...input.quietMs === void 0 ? {} : { quietMs: input.quietMs },
|
|
4698
|
+
...input.captureWindowMs === void 0 ? {} : { captureWindowMs: input.captureWindowMs },
|
|
4699
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
4700
|
+
});
|
|
4701
|
+
await this.flushPendingPageTasks(controller.sessionRef);
|
|
4702
|
+
if (controller.lifecycleState !== "closed") {
|
|
4703
|
+
await this.flushDomUpdateTask(controller);
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4434
4706
|
async readText(input) {
|
|
4435
4707
|
const document = this.requireDocument(input.documentRef);
|
|
4436
4708
|
const controller = this.requirePage(document.pageRef);
|
|
@@ -4952,9 +5224,11 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
4952
5224
|
session.activePageRef = pageRef;
|
|
4953
5225
|
await cdp.send("Page.enable", { enableFileChooserOpenedEvent: true });
|
|
4954
5226
|
await cdp.send("Network.enable");
|
|
5227
|
+
await cdp.send("Runtime.enable");
|
|
4955
5228
|
await cdp.send("DOM.enable", { includeWhitespace: "none" });
|
|
4956
5229
|
await cdp.send("DOMStorage.enable");
|
|
4957
5230
|
await cdp.send("DOM.getDocument", { depth: 0 });
|
|
5231
|
+
await this.installRuntimeEventRecorder(page);
|
|
4958
5232
|
await this.actionSettler.installTracker(controller);
|
|
4959
5233
|
cdp.on(
|
|
4960
5234
|
"Page.frameAttached",
|
|
@@ -5030,9 +5304,19 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5030
5304
|
"DOM.documentUpdated",
|
|
5031
5305
|
() => this.runControllerEvent(controller, () => this.handleDocumentUpdated(controller))
|
|
5032
5306
|
);
|
|
5033
|
-
|
|
5034
|
-
"
|
|
5035
|
-
(
|
|
5307
|
+
cdp.on(
|
|
5308
|
+
"Runtime.consoleAPICalled",
|
|
5309
|
+
(payload) => this.runControllerEvent(
|
|
5310
|
+
controller,
|
|
5311
|
+
() => this.handleRuntimeConsole(controller, payload)
|
|
5312
|
+
)
|
|
5313
|
+
);
|
|
5314
|
+
cdp.on(
|
|
5315
|
+
"Runtime.exceptionThrown",
|
|
5316
|
+
(payload) => this.runControllerEvent(
|
|
5317
|
+
controller,
|
|
5318
|
+
() => this.handleRuntimeException(controller, payload)
|
|
5319
|
+
)
|
|
5036
5320
|
);
|
|
5037
5321
|
page.on(
|
|
5038
5322
|
"popup",
|
|
@@ -5059,10 +5343,6 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5059
5343
|
"download",
|
|
5060
5344
|
(download) => this.runControllerEvent(controller, () => this.handleDownload(controller, download))
|
|
5061
5345
|
);
|
|
5062
|
-
page.on(
|
|
5063
|
-
"pageerror",
|
|
5064
|
-
(error) => this.runControllerEvent(controller, () => this.handlePageError(controller, error))
|
|
5065
|
-
);
|
|
5066
5346
|
page.on(
|
|
5067
5347
|
"request",
|
|
5068
5348
|
(request) => this.runControllerEvent(controller, () => this.handlePlaywrightRequest(controller, request))
|
|
@@ -5074,6 +5354,10 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5074
5354
|
() => this.handlePlaywrightResponse(controller, response)
|
|
5075
5355
|
)
|
|
5076
5356
|
);
|
|
5357
|
+
page.on(
|
|
5358
|
+
"domcontentloaded",
|
|
5359
|
+
() => this.runControllerEvent(controller, () => this.handlePageDomContentLoaded(controller))
|
|
5360
|
+
);
|
|
5077
5361
|
page.on("close", () => this.handleUnexpectedPageClose(controller));
|
|
5078
5362
|
const frameTree = await cdp.send("Page.getFrameTree");
|
|
5079
5363
|
this.syncFrameTree(controller, frameTree.frameTree);
|
|
@@ -5126,6 +5410,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5126
5410
|
documentRef,
|
|
5127
5411
|
documentEpoch: createDocumentEpoch(0),
|
|
5128
5412
|
url: "about:blank",
|
|
5413
|
+
domContentLoadedAt: void 0,
|
|
5129
5414
|
parentDocumentRef: parent?.currentDocument.documentRef,
|
|
5130
5415
|
nodeRefsByBackendNodeId: /* @__PURE__ */ new Map(),
|
|
5131
5416
|
backendNodeIdsByNodeRef: /* @__PURE__ */ new Map(),
|
|
@@ -5184,6 +5469,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5184
5469
|
documentRef: nextDocumentRef,
|
|
5185
5470
|
documentEpoch: createDocumentEpoch(0),
|
|
5186
5471
|
url: combineFrameUrl(frame.url, frame.urlFragment),
|
|
5472
|
+
domContentLoadedAt: void 0,
|
|
5187
5473
|
parentDocumentRef: parent?.currentDocument.documentRef,
|
|
5188
5474
|
nodeRefsByBackendNodeId: /* @__PURE__ */ new Map(),
|
|
5189
5475
|
backendNodeIdsByNodeRef: /* @__PURE__ */ new Map(),
|
|
@@ -5213,6 +5499,13 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5213
5499
|
handleDocumentUpdated(controller) {
|
|
5214
5500
|
this.queueDocumentReconciliation(controller);
|
|
5215
5501
|
}
|
|
5502
|
+
handlePageDomContentLoaded(controller) {
|
|
5503
|
+
const mainFrame = controller.mainFrameRef === void 0 ? void 0 : this.frames.get(controller.mainFrameRef);
|
|
5504
|
+
if (mainFrame === void 0) {
|
|
5505
|
+
return;
|
|
5506
|
+
}
|
|
5507
|
+
mainFrame.currentDocument.domContentLoadedAt = Date.now();
|
|
5508
|
+
}
|
|
5216
5509
|
syncFrameTree(controller, tree) {
|
|
5217
5510
|
const visit = (node, parentFrameRef) => {
|
|
5218
5511
|
const existing = controller.framesByCdpId.get(node.frame.id);
|
|
@@ -5226,6 +5519,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5226
5519
|
documentRef,
|
|
5227
5520
|
documentEpoch: createDocumentEpoch(0),
|
|
5228
5521
|
url: combineFrameUrl(node.frame.url, node.frame.urlFragment),
|
|
5522
|
+
domContentLoadedAt: void 0,
|
|
5229
5523
|
parentDocumentRef: parentFrameRef === void 0 ? void 0 : this.requireFrame(parentFrameRef).currentDocument.documentRef,
|
|
5230
5524
|
nodeRefsByBackendNodeId: /* @__PURE__ */ new Map(),
|
|
5231
5525
|
backendNodeIdsByNodeRef: /* @__PURE__ */ new Map(),
|
|
@@ -5284,19 +5578,20 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5284
5578
|
}
|
|
5285
5579
|
}
|
|
5286
5580
|
}
|
|
5287
|
-
|
|
5581
|
+
handleRuntimeConsole(controller, payload) {
|
|
5582
|
+
const callFrame = payload.stackTrace?.callFrames?.[0];
|
|
5288
5583
|
this.queueEvent(
|
|
5289
5584
|
controller.pageRef,
|
|
5290
5585
|
this.createEvent({
|
|
5291
5586
|
kind: "console",
|
|
5292
5587
|
sessionRef: controller.sessionRef,
|
|
5293
5588
|
pageRef: controller.pageRef,
|
|
5294
|
-
level:
|
|
5295
|
-
text:
|
|
5589
|
+
level: normalizeRuntimeConsoleLevel(payload.type),
|
|
5590
|
+
text: formatRuntimeConsoleText(payload),
|
|
5296
5591
|
location: {
|
|
5297
|
-
url:
|
|
5298
|
-
lineNumber:
|
|
5299
|
-
columnNumber:
|
|
5592
|
+
url: callFrame?.url ?? "",
|
|
5593
|
+
lineNumber: callFrame?.lineNumber ?? 0,
|
|
5594
|
+
columnNumber: callFrame?.columnNumber ?? 0
|
|
5300
5595
|
}
|
|
5301
5596
|
})
|
|
5302
5597
|
);
|
|
@@ -5377,15 +5672,18 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5377
5672
|
})
|
|
5378
5673
|
);
|
|
5379
5674
|
}
|
|
5380
|
-
|
|
5675
|
+
handleRuntimeException(controller, payload) {
|
|
5676
|
+
const details = payload.exceptionDetails;
|
|
5677
|
+
const message = formatRuntimeExceptionMessage(details);
|
|
5678
|
+
const stack = formatRuntimeExceptionStack(details);
|
|
5381
5679
|
this.queueEvent(
|
|
5382
5680
|
controller.pageRef,
|
|
5383
5681
|
this.createEvent({
|
|
5384
5682
|
kind: "page-error",
|
|
5385
5683
|
sessionRef: controller.sessionRef,
|
|
5386
5684
|
pageRef: controller.pageRef,
|
|
5387
|
-
message
|
|
5388
|
-
...
|
|
5685
|
+
message,
|
|
5686
|
+
...stack === void 0 ? {} : { stack }
|
|
5389
5687
|
})
|
|
5390
5688
|
);
|
|
5391
5689
|
}
|
|
@@ -6107,10 +6405,11 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
6107
6405
|
}
|
|
6108
6406
|
}
|
|
6109
6407
|
createEvent(value) {
|
|
6408
|
+
const { timestamp, ...event } = value;
|
|
6110
6409
|
return {
|
|
6111
|
-
...
|
|
6410
|
+
...event,
|
|
6112
6411
|
eventId: `event:${++this.eventCounter}`,
|
|
6113
|
-
timestamp: Date.now()
|
|
6412
|
+
timestamp: timestamp ?? Date.now()
|
|
6114
6413
|
};
|
|
6115
6414
|
}
|
|
6116
6415
|
queueEvent(pageRef, event) {
|
|
@@ -6120,6 +6419,37 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
6120
6419
|
}
|
|
6121
6420
|
controller.queuedEvents.push(event);
|
|
6122
6421
|
}
|
|
6422
|
+
async installRuntimeEventRecorder(page) {
|
|
6423
|
+
await page.addInitScript({
|
|
6424
|
+
content: PLAYWRIGHT_RUNTIME_EVENT_RECORDER_SOURCE
|
|
6425
|
+
});
|
|
6426
|
+
await page.evaluate(PLAYWRIGHT_RUNTIME_EVENT_RECORDER_SOURCE).catch(() => void 0);
|
|
6427
|
+
}
|
|
6428
|
+
async drainInstrumentedRuntimeEvents(controller) {
|
|
6429
|
+
const recorded = await Promise.all(
|
|
6430
|
+
controller.page.frames().map(async (frame) => {
|
|
6431
|
+
const events = await frame.evaluate(() => {
|
|
6432
|
+
const recorder = globalThis.__opensteerRuntimeEventRecorder;
|
|
6433
|
+
return recorder?.drain?.() ?? [];
|
|
6434
|
+
}).catch(() => []);
|
|
6435
|
+
return events;
|
|
6436
|
+
})
|
|
6437
|
+
);
|
|
6438
|
+
return mergeDistinctStepEvents(
|
|
6439
|
+
recorded.flatMap(
|
|
6440
|
+
(events) => events.map(
|
|
6441
|
+
(event) => this.createEvent({
|
|
6442
|
+
kind: "page-error",
|
|
6443
|
+
sessionRef: controller.sessionRef,
|
|
6444
|
+
pageRef: controller.pageRef,
|
|
6445
|
+
message: event.message ?? "Uncaught exception",
|
|
6446
|
+
...event.stack === void 0 ? {} : { stack: event.stack },
|
|
6447
|
+
timestamp: event.timestamp
|
|
6448
|
+
})
|
|
6449
|
+
)
|
|
6450
|
+
)
|
|
6451
|
+
);
|
|
6452
|
+
}
|
|
6123
6453
|
drainQueuedEvents(pageRef) {
|
|
6124
6454
|
const controller = this.requirePage(pageRef);
|
|
6125
6455
|
const events = controller.queuedEvents.splice(0, controller.queuedEvents.length);
|
|
@@ -6366,6 +6696,104 @@ function withTimeout(promise, timeoutMs) {
|
|
|
6366
6696
|
})
|
|
6367
6697
|
]);
|
|
6368
6698
|
}
|
|
6699
|
+
function formatRuntimeConsoleText(payload) {
|
|
6700
|
+
const parts = (payload.args ?? []).map((arg) => formatRuntimeRemoteObject(arg)).filter((value) => value.length > 0);
|
|
6701
|
+
if (parts.length > 0) {
|
|
6702
|
+
return parts.join(" ");
|
|
6703
|
+
}
|
|
6704
|
+
return payload.type?.trim() || "console";
|
|
6705
|
+
}
|
|
6706
|
+
function normalizeRuntimeConsoleLevel(value) {
|
|
6707
|
+
switch (value) {
|
|
6708
|
+
case "warning":
|
|
6709
|
+
case "debug":
|
|
6710
|
+
case "info":
|
|
6711
|
+
case "error":
|
|
6712
|
+
case "trace":
|
|
6713
|
+
return normalizeConsoleLevel(value);
|
|
6714
|
+
default:
|
|
6715
|
+
return "log";
|
|
6716
|
+
}
|
|
6717
|
+
}
|
|
6718
|
+
function formatRuntimeExceptionMessage(details) {
|
|
6719
|
+
const description = details?.exception?.description?.trim();
|
|
6720
|
+
if (description) {
|
|
6721
|
+
const firstLine = description.split("\n")[0]?.trim() ?? "";
|
|
6722
|
+
if (firstLine.startsWith("Error: ")) {
|
|
6723
|
+
return firstLine.slice("Error: ".length);
|
|
6724
|
+
}
|
|
6725
|
+
return firstLine || description;
|
|
6726
|
+
}
|
|
6727
|
+
const value = details?.exception?.value;
|
|
6728
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
6729
|
+
return value.trim();
|
|
6730
|
+
}
|
|
6731
|
+
return details?.text?.trim() || "Uncaught exception";
|
|
6732
|
+
}
|
|
6733
|
+
function formatRuntimeExceptionStack(details) {
|
|
6734
|
+
const description = details?.exception?.description?.trim();
|
|
6735
|
+
if (description && description.includes("\n")) {
|
|
6736
|
+
return description;
|
|
6737
|
+
}
|
|
6738
|
+
const frames = details?.stackTrace?.callFrames;
|
|
6739
|
+
if (!frames || frames.length === 0) {
|
|
6740
|
+
return void 0;
|
|
6741
|
+
}
|
|
6742
|
+
return frames.map((frame) => {
|
|
6743
|
+
const url = frame.url ?? "<anonymous>";
|
|
6744
|
+
const lineNumber = frame.lineNumber ?? 0;
|
|
6745
|
+
const columnNumber = frame.columnNumber ?? 0;
|
|
6746
|
+
return ` at ${url}:${lineNumber}:${columnNumber}`;
|
|
6747
|
+
}).join("\n");
|
|
6748
|
+
}
|
|
6749
|
+
function formatRuntimeRemoteObject(object) {
|
|
6750
|
+
if (object.unserializableValue !== void 0) {
|
|
6751
|
+
return object.unserializableValue;
|
|
6752
|
+
}
|
|
6753
|
+
if (object.value !== void 0) {
|
|
6754
|
+
return typeof object.value === "string" ? object.value : JSON.stringify(object.value);
|
|
6755
|
+
}
|
|
6756
|
+
if (object.description !== void 0 && object.description.length > 0) {
|
|
6757
|
+
return object.description;
|
|
6758
|
+
}
|
|
6759
|
+
const previewParts = object.preview?.properties?.map((property) => {
|
|
6760
|
+
if (!property.name) {
|
|
6761
|
+
return "";
|
|
6762
|
+
}
|
|
6763
|
+
return property.value === void 0 ? property.name : `${property.name}: ${property.value}`;
|
|
6764
|
+
}).filter((value) => value.length > 0) ?? [];
|
|
6765
|
+
return previewParts.join(", ");
|
|
6766
|
+
}
|
|
6767
|
+
function mergeDistinctStepEvents(events) {
|
|
6768
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6769
|
+
const merged = [];
|
|
6770
|
+
for (const event of events) {
|
|
6771
|
+
const fingerprint = stepEventFingerprint(event);
|
|
6772
|
+
if (seen.has(fingerprint)) {
|
|
6773
|
+
continue;
|
|
6774
|
+
}
|
|
6775
|
+
seen.add(fingerprint);
|
|
6776
|
+
merged.push(event);
|
|
6777
|
+
}
|
|
6778
|
+
return merged;
|
|
6779
|
+
}
|
|
6780
|
+
function stepEventFingerprint(event) {
|
|
6781
|
+
switch (event.kind) {
|
|
6782
|
+
case "console":
|
|
6783
|
+
return [
|
|
6784
|
+
event.kind,
|
|
6785
|
+
event.level,
|
|
6786
|
+
event.text,
|
|
6787
|
+
event.location?.url ?? "",
|
|
6788
|
+
event.location?.lineNumber ?? "",
|
|
6789
|
+
event.location?.columnNumber ?? ""
|
|
6790
|
+
].join("|");
|
|
6791
|
+
case "page-error":
|
|
6792
|
+
return [event.kind, event.message, event.stack ?? ""].join("|");
|
|
6793
|
+
default:
|
|
6794
|
+
return event.eventId;
|
|
6795
|
+
}
|
|
6796
|
+
}
|
|
6369
6797
|
|
|
6370
6798
|
exports.PlaywrightBrowserCoreEngine = PlaywrightBrowserCoreEngine;
|
|
6371
6799
|
exports.capturePlaywrightStorageOrigins = capturePlaywrightStorageOrigins;
|