@opensteer/engine-playwright 0.7.0 → 0.8.0
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 +482 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +482 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2373,8 +2373,421 @@ var CLASSIFY_POINTER_HIT_DECLARATION = String.raw`function(hitNode, point) {
|
|
|
2373
2373
|
ambiguous,
|
|
2374
2374
|
};
|
|
2375
2375
|
}`;
|
|
2376
|
+
var LIVE_REPLAY_PATH_MATCH_ATTRIBUTE_PRIORITY = [
|
|
2377
|
+
"class",
|
|
2378
|
+
"data-testid",
|
|
2379
|
+
"data-test",
|
|
2380
|
+
"data-qa",
|
|
2381
|
+
"data-cy",
|
|
2382
|
+
"name",
|
|
2383
|
+
"role",
|
|
2384
|
+
"type",
|
|
2385
|
+
"aria-label",
|
|
2386
|
+
"title",
|
|
2387
|
+
"placeholder",
|
|
2388
|
+
"for",
|
|
2389
|
+
"aria-controls",
|
|
2390
|
+
"aria-labelledby",
|
|
2391
|
+
"aria-describedby",
|
|
2392
|
+
"id",
|
|
2393
|
+
"href",
|
|
2394
|
+
"value",
|
|
2395
|
+
"src",
|
|
2396
|
+
"srcset",
|
|
2397
|
+
"imagesrcset",
|
|
2398
|
+
"ping",
|
|
2399
|
+
"alt"
|
|
2400
|
+
];
|
|
2401
|
+
var LIVE_REPLAY_PATH_STABLE_PRIMARY_ATTR_KEYS = [
|
|
2402
|
+
"data-testid",
|
|
2403
|
+
"data-test",
|
|
2404
|
+
"data-qa",
|
|
2405
|
+
"data-cy",
|
|
2406
|
+
"name",
|
|
2407
|
+
"role",
|
|
2408
|
+
"type",
|
|
2409
|
+
"aria-label",
|
|
2410
|
+
"title",
|
|
2411
|
+
"placeholder"
|
|
2412
|
+
];
|
|
2413
|
+
var LIVE_REPLAY_PATH_DEFERRED_MATCH_ATTR_KEYS = [
|
|
2414
|
+
"href",
|
|
2415
|
+
"src",
|
|
2416
|
+
"srcset",
|
|
2417
|
+
"imagesrcset",
|
|
2418
|
+
"ping",
|
|
2419
|
+
"value",
|
|
2420
|
+
"for",
|
|
2421
|
+
"aria-controls",
|
|
2422
|
+
"aria-labelledby",
|
|
2423
|
+
"aria-describedby"
|
|
2424
|
+
];
|
|
2425
|
+
var LIVE_REPLAY_PATH_POLICY = {
|
|
2426
|
+
matchAttributePriority: LIVE_REPLAY_PATH_MATCH_ATTRIBUTE_PRIORITY,
|
|
2427
|
+
stablePrimaryAttrKeys: LIVE_REPLAY_PATH_STABLE_PRIMARY_ATTR_KEYS,
|
|
2428
|
+
deferredMatchAttrKeys: LIVE_REPLAY_PATH_DEFERRED_MATCH_ATTR_KEYS
|
|
2429
|
+
};
|
|
2430
|
+
var BUILD_LIVE_REPLAY_PATH_DECLARATION = String.raw`function(policy, source) {
|
|
2431
|
+
const buildReplayPath = (0, eval)(source);
|
|
2432
|
+
return buildReplayPath(this, policy);
|
|
2433
|
+
}`;
|
|
2434
|
+
var BUILD_LIVE_REPLAY_PATH_SOURCE = String.raw`(target, policy) => {
|
|
2435
|
+
const MAX_ATTRIBUTE_VALUE_LENGTH = 300;
|
|
2436
|
+
|
|
2437
|
+
function isValidAttrKey(key) {
|
|
2438
|
+
const trimmed = String(key || "").trim();
|
|
2439
|
+
if (!trimmed) return false;
|
|
2440
|
+
if (/[\s"'<>/]/.test(trimmed)) return false;
|
|
2441
|
+
return /^[A-Za-z_][A-Za-z0-9_:\-.]*$/.test(trimmed);
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2444
|
+
function isMediaTag(tag) {
|
|
2445
|
+
return new Set(["img", "video", "source", "iframe"]).has(String(tag || "").toLowerCase());
|
|
2446
|
+
}
|
|
2447
|
+
|
|
2448
|
+
function shouldKeepAttr(tag, key, value) {
|
|
2449
|
+
const normalized = String(key || "").trim().toLowerCase();
|
|
2450
|
+
if (!normalized || !String(value || "").trim()) return false;
|
|
2451
|
+
if (!isValidAttrKey(key)) return false;
|
|
2452
|
+
if (normalized === "c") return false;
|
|
2453
|
+
if (/^on[a-z]/i.test(normalized)) return false;
|
|
2454
|
+
if (new Set(["style", "nonce", "integrity", "crossorigin", "referrerpolicy", "autocomplete"]).has(normalized)) {
|
|
2455
|
+
return false;
|
|
2456
|
+
}
|
|
2457
|
+
if (normalized.startsWith("data-os-") || normalized.startsWith("data-opensteer-")) {
|
|
2458
|
+
return false;
|
|
2459
|
+
}
|
|
2460
|
+
if (
|
|
2461
|
+
isMediaTag(tag) &&
|
|
2462
|
+
new Set([
|
|
2463
|
+
"data-src",
|
|
2464
|
+
"data-lazy-src",
|
|
2465
|
+
"data-original",
|
|
2466
|
+
"data-lazy",
|
|
2467
|
+
"data-image",
|
|
2468
|
+
"data-url",
|
|
2469
|
+
"data-srcset",
|
|
2470
|
+
"data-lazy-srcset",
|
|
2471
|
+
"data-was-processed",
|
|
2472
|
+
]).has(normalized)
|
|
2473
|
+
) {
|
|
2474
|
+
return false;
|
|
2475
|
+
}
|
|
2476
|
+
return true;
|
|
2477
|
+
}
|
|
2478
|
+
|
|
2479
|
+
function collectAttrs(node) {
|
|
2480
|
+
const tag = node.tagName.toLowerCase();
|
|
2481
|
+
const attrs = {};
|
|
2482
|
+
for (const attr of Array.from(node.attributes)) {
|
|
2483
|
+
if (!shouldKeepAttr(tag, attr.name, attr.value)) {
|
|
2484
|
+
continue;
|
|
2485
|
+
}
|
|
2486
|
+
const value = String(attr.value || "");
|
|
2487
|
+
if (!value.trim()) continue;
|
|
2488
|
+
if (value.length > MAX_ATTRIBUTE_VALUE_LENGTH) continue;
|
|
2489
|
+
attrs[attr.name] = value;
|
|
2490
|
+
}
|
|
2491
|
+
return attrs;
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
function getSiblings(node, root) {
|
|
2495
|
+
if (node.parentElement) return Array.from(node.parentElement.children);
|
|
2496
|
+
return Array.from(root.children || []);
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
function toPosition(node, root) {
|
|
2500
|
+
const siblings = getSiblings(node, root);
|
|
2501
|
+
const tag = node.tagName.toLowerCase();
|
|
2502
|
+
const sameTag = siblings.filter((candidate) => candidate.tagName.toLowerCase() === tag);
|
|
2503
|
+
return {
|
|
2504
|
+
nthChild: siblings.indexOf(node) + 1,
|
|
2505
|
+
nthOfType: sameTag.indexOf(node) + 1,
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
function buildChain(node) {
|
|
2510
|
+
const chain = [];
|
|
2511
|
+
let current = node;
|
|
2512
|
+
while (current) {
|
|
2513
|
+
chain.push(current);
|
|
2514
|
+
if (current.parentElement) {
|
|
2515
|
+
current = current.parentElement;
|
|
2516
|
+
continue;
|
|
2517
|
+
}
|
|
2518
|
+
break;
|
|
2519
|
+
}
|
|
2520
|
+
chain.reverse();
|
|
2521
|
+
return chain;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
function sortAttributeKeys(keys) {
|
|
2525
|
+
const priority = Array.isArray(policy?.matchAttributePriority)
|
|
2526
|
+
? policy.matchAttributePriority.map((value) => String(value))
|
|
2527
|
+
: [];
|
|
2528
|
+
return [...keys].sort((left, right) => {
|
|
2529
|
+
const leftIndex = priority.indexOf(left);
|
|
2530
|
+
const rightIndex = priority.indexOf(right);
|
|
2531
|
+
const leftRank = leftIndex === -1 ? Number.MAX_SAFE_INTEGER : leftIndex;
|
|
2532
|
+
const rightRank = rightIndex === -1 ? Number.MAX_SAFE_INTEGER : rightIndex;
|
|
2533
|
+
if (leftRank !== rightRank) {
|
|
2534
|
+
return leftRank - rightRank;
|
|
2535
|
+
}
|
|
2536
|
+
return left.localeCompare(right);
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
function tokenizeClassValue(value) {
|
|
2541
|
+
const seen = new Set();
|
|
2542
|
+
const out = [];
|
|
2543
|
+
for (const token of String(value || "").split(/\s+/)) {
|
|
2544
|
+
const normalized = token.trim();
|
|
2545
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
2546
|
+
seen.add(normalized);
|
|
2547
|
+
out.push(normalized);
|
|
2548
|
+
}
|
|
2549
|
+
return out;
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
function clauseKey(clause) {
|
|
2553
|
+
return JSON.stringify(clause);
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
function shouldDeferMatchAttribute(rawKey) {
|
|
2557
|
+
const key = String(rawKey || "").trim().toLowerCase();
|
|
2558
|
+
if (!key || key === "class") return false;
|
|
2559
|
+
if (key === "id" || /(?:^|[-_:])id$/.test(key)) return true;
|
|
2560
|
+
const deferred = new Set(
|
|
2561
|
+
Array.isArray(policy?.deferredMatchAttrKeys)
|
|
2562
|
+
? policy.deferredMatchAttrKeys.map((value) => String(value))
|
|
2563
|
+
: [],
|
|
2564
|
+
);
|
|
2565
|
+
if (deferred.has(key)) return true;
|
|
2566
|
+
const stablePrimary = new Set(
|
|
2567
|
+
Array.isArray(policy?.stablePrimaryAttrKeys)
|
|
2568
|
+
? policy.stablePrimaryAttrKeys.map((value) => String(value))
|
|
2569
|
+
: [],
|
|
2570
|
+
);
|
|
2571
|
+
if (key.startsWith("data-") && !stablePrimary.has(key)) return true;
|
|
2572
|
+
return !stablePrimary.has(key);
|
|
2573
|
+
}
|
|
2574
|
+
|
|
2575
|
+
function buildSegmentSelector(data) {
|
|
2576
|
+
let selector = String(data.tag || "*").toLowerCase();
|
|
2577
|
+
for (const clause of data.match || []) {
|
|
2578
|
+
if (clause.kind === "position") {
|
|
2579
|
+
if (clause.axis === "nthOfType") {
|
|
2580
|
+
selector += ":nth-of-type(" + Math.max(1, Number(data.position?.nthOfType || 1)) + ")";
|
|
2581
|
+
} else {
|
|
2582
|
+
selector += ":nth-child(" + Math.max(1, Number(data.position?.nthChild || 1)) + ")";
|
|
2583
|
+
}
|
|
2584
|
+
continue;
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
const key = String(clause.key || "");
|
|
2588
|
+
const value = typeof clause.value === "string" ? clause.value : data.attrs?.[key];
|
|
2589
|
+
if (!key || !value) continue;
|
|
2590
|
+
if (key === "class" && (clause.op || "exact") === "exact") {
|
|
2591
|
+
for (const token of tokenizeClassValue(value)) {
|
|
2592
|
+
const escapedToken = String(token).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
2593
|
+
selector += '[class~="' + escapedToken + '"]';
|
|
2594
|
+
}
|
|
2595
|
+
continue;
|
|
2596
|
+
}
|
|
2597
|
+
const escaped = String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
2598
|
+
const op = clause.op || "exact";
|
|
2599
|
+
if (op === "startsWith") selector += "[" + key + '^="' + escaped + '"]';
|
|
2600
|
+
else if (op === "contains") selector += "[" + key + '*="' + escaped + '"]';
|
|
2601
|
+
else selector += "[" + key + '="' + escaped + '"]';
|
|
2602
|
+
}
|
|
2603
|
+
return selector;
|
|
2604
|
+
}
|
|
2605
|
+
|
|
2606
|
+
function buildCandidates(nodes) {
|
|
2607
|
+
const parts = nodes.map((node) => buildSegmentSelector(node));
|
|
2608
|
+
const out = [];
|
|
2609
|
+
const seen = new Set();
|
|
2610
|
+
for (let start = 0; start < parts.length; start += 1) {
|
|
2611
|
+
const selector = parts.slice(start).join(" ");
|
|
2612
|
+
if (!selector || seen.has(selector)) continue;
|
|
2613
|
+
seen.add(selector);
|
|
2614
|
+
out.push(selector);
|
|
2615
|
+
}
|
|
2616
|
+
return out;
|
|
2617
|
+
}
|
|
2618
|
+
|
|
2619
|
+
function selectReplayCandidate(nodes, root) {
|
|
2620
|
+
const selectors = buildCandidates(nodes);
|
|
2621
|
+
let fallback = null;
|
|
2622
|
+
let fallbackSelector = null;
|
|
2623
|
+
let fallbackCount = 0;
|
|
2624
|
+
for (const selector of selectors) {
|
|
2625
|
+
let matches = [];
|
|
2626
|
+
try {
|
|
2627
|
+
matches = Array.from(root.querySelectorAll(selector));
|
|
2628
|
+
} catch {
|
|
2629
|
+
matches = [];
|
|
2630
|
+
}
|
|
2631
|
+
if (!matches.length) continue;
|
|
2632
|
+
if (matches.length === 1) {
|
|
2633
|
+
return {
|
|
2634
|
+
element: matches[0],
|
|
2635
|
+
selector,
|
|
2636
|
+
count: 1,
|
|
2637
|
+
mode: "unique",
|
|
2638
|
+
};
|
|
2639
|
+
}
|
|
2640
|
+
if (!fallback) {
|
|
2641
|
+
fallback = matches[0];
|
|
2642
|
+
fallbackSelector = selector;
|
|
2643
|
+
fallbackCount = matches.length;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
if (fallback && fallbackSelector) {
|
|
2647
|
+
return {
|
|
2648
|
+
element: fallback,
|
|
2649
|
+
selector: fallbackSelector,
|
|
2650
|
+
count: fallbackCount,
|
|
2651
|
+
mode: "fallback",
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
return null;
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
function buildClausePool(data) {
|
|
2658
|
+
const attrs = data.attrs || {};
|
|
2659
|
+
const pool = [];
|
|
2660
|
+
const deferred = [];
|
|
2661
|
+
const used = new Set();
|
|
2662
|
+
|
|
2663
|
+
const classValue = String(attrs.class || "").trim();
|
|
2664
|
+
if (classValue) {
|
|
2665
|
+
const clause = { kind: "attr", key: "class", op: "exact", value: classValue };
|
|
2666
|
+
used.add(clauseKey(clause));
|
|
2667
|
+
pool.push(clause);
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2670
|
+
for (const key of sortAttributeKeys(Object.keys(attrs))) {
|
|
2671
|
+
if (key === "class") continue;
|
|
2672
|
+
const value = attrs[key];
|
|
2673
|
+
if (!value || !String(value).trim()) continue;
|
|
2674
|
+
const clause = { kind: "attr", key, op: "exact" };
|
|
2675
|
+
const keyId = clauseKey(clause);
|
|
2676
|
+
if (used.has(keyId)) continue;
|
|
2677
|
+
used.add(keyId);
|
|
2678
|
+
if (shouldDeferMatchAttribute(key)) deferred.push(clause);
|
|
2679
|
+
else pool.push(clause);
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
for (const clause of [
|
|
2683
|
+
{ kind: "position", axis: "nthOfType" },
|
|
2684
|
+
{ kind: "position", axis: "nthChild" },
|
|
2685
|
+
]) {
|
|
2686
|
+
const keyId = clauseKey(clause);
|
|
2687
|
+
if (used.has(keyId)) continue;
|
|
2688
|
+
used.add(keyId);
|
|
2689
|
+
pool.push(clause);
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
if (!pool.some((clause) => clause.kind === "attr")) {
|
|
2693
|
+
pool.push(...deferred);
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2696
|
+
return pool;
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
function finalizePath(elements, root) {
|
|
2700
|
+
if (!elements.length) return null;
|
|
2701
|
+
const nodes = elements.map((element) => ({
|
|
2702
|
+
tag: element.tagName.toLowerCase(),
|
|
2703
|
+
attrs: collectAttrs(element),
|
|
2704
|
+
position: toPosition(element, root),
|
|
2705
|
+
match: [],
|
|
2706
|
+
}));
|
|
2707
|
+
|
|
2708
|
+
const pools = nodes.map((node) => {
|
|
2709
|
+
node.match = [];
|
|
2710
|
+
return [...buildClausePool(node)];
|
|
2711
|
+
});
|
|
2712
|
+
|
|
2713
|
+
for (let index = 0; index < pools.length; index += 1) {
|
|
2714
|
+
const classIndex = pools[index].findIndex(
|
|
2715
|
+
(clause) => clause.kind === "attr" && clause.key === "class",
|
|
2716
|
+
);
|
|
2717
|
+
if (classIndex < 0) continue;
|
|
2718
|
+
const classClause = pools[index][classIndex];
|
|
2719
|
+
if (!classClause) continue;
|
|
2720
|
+
nodes[index].match.push(classClause);
|
|
2721
|
+
pools[index].splice(classIndex, 1);
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
const expected = elements[elements.length - 1];
|
|
2725
|
+
const totalRemaining = pools.reduce((count, pool) => count + pool.length, 0);
|
|
2726
|
+
for (let iteration = 0; iteration <= totalRemaining; iteration += 1) {
|
|
2727
|
+
const chosen = selectReplayCandidate(nodes, root);
|
|
2728
|
+
if (chosen && chosen.mode === "unique" && chosen.element === expected) {
|
|
2729
|
+
return {
|
|
2730
|
+
nodes,
|
|
2731
|
+
selector: chosen.selector,
|
|
2732
|
+
};
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
let added = false;
|
|
2736
|
+
for (let index = pools.length - 1; index >= 0; index -= 1) {
|
|
2737
|
+
const next = pools[index][0];
|
|
2738
|
+
if (!next) continue;
|
|
2739
|
+
nodes[index].match.push(next);
|
|
2740
|
+
pools[index].shift();
|
|
2741
|
+
added = true;
|
|
2742
|
+
break;
|
|
2743
|
+
}
|
|
2744
|
+
if (!added) break;
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
return null;
|
|
2748
|
+
}
|
|
2749
|
+
|
|
2750
|
+
if (!(target instanceof Element)) return null;
|
|
2751
|
+
|
|
2752
|
+
const context = [];
|
|
2753
|
+
let currentRoot = target.getRootNode() instanceof ShadowRoot ? target.getRootNode() : document;
|
|
2754
|
+
const targetChain = buildChain(target);
|
|
2755
|
+
const finalizedTarget = finalizePath(targetChain, currentRoot);
|
|
2756
|
+
if (!finalizedTarget) return null;
|
|
2757
|
+
|
|
2758
|
+
while (currentRoot instanceof ShadowRoot) {
|
|
2759
|
+
const host = currentRoot.host;
|
|
2760
|
+
const hostRoot =
|
|
2761
|
+
host.getRootNode() instanceof ShadowRoot ? host.getRootNode() : document;
|
|
2762
|
+
const hostChain = buildChain(host);
|
|
2763
|
+
const finalizedHost = finalizePath(hostChain, hostRoot);
|
|
2764
|
+
if (!finalizedHost) return null;
|
|
2765
|
+
context.unshift({
|
|
2766
|
+
kind: "shadow",
|
|
2767
|
+
host: finalizedHost.nodes,
|
|
2768
|
+
});
|
|
2769
|
+
currentRoot = hostRoot;
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2772
|
+
return {
|
|
2773
|
+
resolution: "deterministic",
|
|
2774
|
+
context,
|
|
2775
|
+
nodes: finalizedTarget.nodes,
|
|
2776
|
+
};
|
|
2777
|
+
}`;
|
|
2376
2778
|
function createPlaywrightDomActionBridge(context) {
|
|
2377
2779
|
return {
|
|
2780
|
+
buildReplayPath(locator) {
|
|
2781
|
+
return withLiveNode(context, locator, async ({ controller, document, backendNodeId }) => {
|
|
2782
|
+
const localPath = await buildLiveReplayPathForLocator(
|
|
2783
|
+
controller,
|
|
2784
|
+
document,
|
|
2785
|
+
locator,
|
|
2786
|
+
backendNodeId
|
|
2787
|
+
);
|
|
2788
|
+
return prefixIframeReplayPath(context, document.frameRef, localPath);
|
|
2789
|
+
});
|
|
2790
|
+
},
|
|
2378
2791
|
inspectActionTarget(locator) {
|
|
2379
2792
|
return withLiveNode(context, locator, async ({ controller, document, backendNodeId }) => {
|
|
2380
2793
|
const nodeId = await resolveFrontendNodeId(controller, document, locator, backendNodeId);
|
|
@@ -2668,6 +3081,58 @@ function normalizePointerHitAssessment(value, canonicalTarget) {
|
|
|
2668
3081
|
canonicalTarget
|
|
2669
3082
|
};
|
|
2670
3083
|
}
|
|
3084
|
+
async function buildLiveReplayPathForLocator(controller, document, locator, backendNodeId) {
|
|
3085
|
+
const raw = await callNodeFunction(controller, document, locator, backendNodeId, {
|
|
3086
|
+
functionDeclaration: BUILD_LIVE_REPLAY_PATH_DECLARATION,
|
|
3087
|
+
arguments: [{ value: LIVE_REPLAY_PATH_POLICY }, { value: BUILD_LIVE_REPLAY_PATH_SOURCE }],
|
|
3088
|
+
returnByValue: true
|
|
3089
|
+
});
|
|
3090
|
+
return requireReplayPath(raw, locator);
|
|
3091
|
+
}
|
|
3092
|
+
async function prefixIframeReplayPath(context, frameRef, localPath) {
|
|
3093
|
+
let currentPath = localPath;
|
|
3094
|
+
let currentFrame = context.requireFrame(frameRef);
|
|
3095
|
+
while (currentFrame.parentFrame() !== null) {
|
|
3096
|
+
const frameElement = await currentFrame.frameElement();
|
|
3097
|
+
try {
|
|
3098
|
+
const hostPath = await buildLiveReplayPathForHandle(frameElement);
|
|
3099
|
+
currentPath = {
|
|
3100
|
+
resolution: "deterministic",
|
|
3101
|
+
context: [
|
|
3102
|
+
...hostPath.context,
|
|
3103
|
+
{ kind: "iframe", host: hostPath.nodes },
|
|
3104
|
+
...currentPath.context
|
|
3105
|
+
],
|
|
3106
|
+
nodes: currentPath.nodes
|
|
3107
|
+
};
|
|
3108
|
+
} finally {
|
|
3109
|
+
await frameElement.dispose().catch(() => void 0);
|
|
3110
|
+
}
|
|
3111
|
+
currentFrame = currentFrame.parentFrame();
|
|
3112
|
+
}
|
|
3113
|
+
return currentPath;
|
|
3114
|
+
}
|
|
3115
|
+
async function buildLiveReplayPathForHandle(handle) {
|
|
3116
|
+
const raw = await handle.evaluate(
|
|
3117
|
+
(element, input) => {
|
|
3118
|
+
const buildReplayPath = (0, eval)(input.source);
|
|
3119
|
+
return buildReplayPath(element, input.policy);
|
|
3120
|
+
},
|
|
3121
|
+
{
|
|
3122
|
+
policy: LIVE_REPLAY_PATH_POLICY,
|
|
3123
|
+
source: BUILD_LIVE_REPLAY_PATH_SOURCE
|
|
3124
|
+
}
|
|
3125
|
+
);
|
|
3126
|
+
return requireReplayPath(raw);
|
|
3127
|
+
}
|
|
3128
|
+
function requireReplayPath(value, locator) {
|
|
3129
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || value.resolution !== "deterministic") {
|
|
3130
|
+
throw new Error(
|
|
3131
|
+
locator === void 0 ? "live DOM replay path builder returned an invalid result" : `live DOM replay path builder returned an invalid result for ${locator.nodeRef}`
|
|
3132
|
+
);
|
|
3133
|
+
}
|
|
3134
|
+
return value;
|
|
3135
|
+
}
|
|
2671
3136
|
function unionQuadBounds(quads) {
|
|
2672
3137
|
const bounds = quads.map((quad) => quadBounds(quad));
|
|
2673
3138
|
const minX = Math.min(...bounds.map((rect) => rect.x));
|
|
@@ -2960,6 +3425,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
2960
3425
|
document.documentEpoch,
|
|
2961
3426
|
this.nodeRefForBackendNode(document, backendNodeId)
|
|
2962
3427
|
),
|
|
3428
|
+
requireFrame: (frameRef) => this.requireLiveFrame(frameRef),
|
|
2963
3429
|
requireLiveNode: (locator) => this.requireLiveNode(locator)
|
|
2964
3430
|
});
|
|
2965
3431
|
return this.domActionBridge;
|
|
@@ -5106,6 +5572,18 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5106
5572
|
}
|
|
5107
5573
|
return frame;
|
|
5108
5574
|
}
|
|
5575
|
+
requireLiveFrame(frameRef) {
|
|
5576
|
+
const state = this.requireFrame(frameRef);
|
|
5577
|
+
const controller = this.requirePage(state.pageRef);
|
|
5578
|
+
for (const frame of controller.page.frames()) {
|
|
5579
|
+
if (controller.frameBindings.get(frame) === frameRef) {
|
|
5580
|
+
return frame;
|
|
5581
|
+
}
|
|
5582
|
+
}
|
|
5583
|
+
throw createBrowserCoreError("not-found", `frame ${frameRef} is not attached to a live page`, {
|
|
5584
|
+
details: { frameRef }
|
|
5585
|
+
});
|
|
5586
|
+
}
|
|
5109
5587
|
requireDocument(documentRef) {
|
|
5110
5588
|
const document = this.documents.get(documentRef);
|
|
5111
5589
|
if (!document) {
|
|
@@ -5307,6 +5785,9 @@ async function connectPlaywrightChromiumBrowser(input) {
|
|
|
5307
5785
|
...input.headers === void 0 ? {} : { headers: input.headers }
|
|
5308
5786
|
});
|
|
5309
5787
|
}
|
|
5788
|
+
async function disconnectPlaywrightChromiumBrowser(browser) {
|
|
5789
|
+
void browser.close().catch(() => void 0);
|
|
5790
|
+
}
|
|
5310
5791
|
function objectHeadersToEntries(headers) {
|
|
5311
5792
|
if (!headers) {
|
|
5312
5793
|
return [];
|
|
@@ -5464,5 +5945,6 @@ exports.PlaywrightBrowserCoreEngine = PlaywrightBrowserCoreEngine;
|
|
|
5464
5945
|
exports.capturePlaywrightStorageOrigins = capturePlaywrightStorageOrigins;
|
|
5465
5946
|
exports.connectPlaywrightChromiumBrowser = connectPlaywrightChromiumBrowser;
|
|
5466
5947
|
exports.createPlaywrightBrowserCoreEngine = createPlaywrightBrowserCoreEngine;
|
|
5948
|
+
exports.disconnectPlaywrightChromiumBrowser = disconnectPlaywrightChromiumBrowser;
|
|
5467
5949
|
//# sourceMappingURL=index.cjs.map
|
|
5468
5950
|
//# sourceMappingURL=index.cjs.map
|