@skrillex1224/playwright-toolkit 2.1.232 → 2.1.234
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/README.md +10 -3
- package/dist/browser.js +1 -0
- package/dist/browser.js.map +2 -2
- package/dist/index.cjs +454 -205
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +454 -205
- package/dist/index.js.map +4 -4
- package/index.d.ts +35 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -285,6 +285,7 @@ var ActorInfo = {
|
|
|
285
285
|
name: "\u901A\u4E49\u5343\u95EE",
|
|
286
286
|
domain: "www.qianwen.com",
|
|
287
287
|
path: "/chat",
|
|
288
|
+
device: Device.Mobile,
|
|
288
289
|
share: {
|
|
289
290
|
mode: "response",
|
|
290
291
|
prefix: "https://www.qianwen.com/share/chat/",
|
|
@@ -442,6 +443,9 @@ function createInternalLogger(moduleName, explicitLogger) {
|
|
|
442
443
|
// src/internals/screenshot.js
|
|
443
444
|
import delay from "delay";
|
|
444
445
|
|
|
446
|
+
// src/internals/constants.js
|
|
447
|
+
var PageRuntimeStateKey = "__playwright_toolkit_runtime_state__";
|
|
448
|
+
|
|
445
449
|
// src/internals/viewport.js
|
|
446
450
|
var toPositiveInt = (value) => {
|
|
447
451
|
const number = Math.round(Number(value) || 0);
|
|
@@ -478,9 +482,7 @@ var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["png", "jpeg", "webp"]);
|
|
|
478
482
|
var EXPANDED_SCROLLABLE_CLASS = "__pk_expanded__";
|
|
479
483
|
var DEFAULT_MAX_HEIGHT = 8e3;
|
|
480
484
|
var DEFAULT_SETTLE_MS = 1e3;
|
|
481
|
-
var
|
|
482
|
-
var DEFAULT_BUFFER_MIN = 120;
|
|
483
|
-
var DEFAULT_BUFFER_MAX = 320;
|
|
485
|
+
var DEFAULT_MOBILE_SETTLE_MS = 50;
|
|
484
486
|
var toPositiveNumber = (value, fallback = 0) => {
|
|
485
487
|
const n = Number(value);
|
|
486
488
|
if (!Number.isFinite(n) || n <= 0) return fallback;
|
|
@@ -490,10 +492,6 @@ var toPositiveInteger = (value, fallback = 0) => {
|
|
|
490
492
|
const number = Math.round(Number(value) || 0);
|
|
491
493
|
return number > 0 ? number : fallback;
|
|
492
494
|
};
|
|
493
|
-
var resolveDefaultBuffer = (viewport = {}) => {
|
|
494
|
-
const height = Math.max(1, Number(viewport.height) || 0);
|
|
495
|
-
return Math.round(Math.min(DEFAULT_BUFFER_MAX, Math.max(DEFAULT_BUFFER_MIN, height * DEFAULT_BUFFER_RATIO)));
|
|
496
|
-
};
|
|
497
495
|
var normalizeType = (value) => {
|
|
498
496
|
const raw = String(value || "png").trim().toLowerCase();
|
|
499
497
|
if (!SUPPORTED_TYPES.has(raw)) return "png";
|
|
@@ -507,6 +505,7 @@ var normalizeQuality = (value, type) => {
|
|
|
507
505
|
if (rounded < 0 || rounded > 100) return void 0;
|
|
508
506
|
return rounded;
|
|
509
507
|
};
|
|
508
|
+
var resolvePageDevice = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
|
|
510
509
|
var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
|
|
511
510
|
const contentSize = metrics && typeof metrics === "object" ? metrics.contentSize || null : null;
|
|
512
511
|
const width = Math.max(1, Math.ceil(viewport.width || contentSize?.width || 1));
|
|
@@ -523,7 +522,7 @@ var buildFullPageClip = (metrics, viewport, maxClipHeight) => {
|
|
|
523
522
|
};
|
|
524
523
|
};
|
|
525
524
|
var expandScrollableContent = async (page, options = {}) => {
|
|
526
|
-
return await page.evaluate(({ className, forceScrollableHeight, visibleOnly }) => {
|
|
525
|
+
return await page.evaluate(({ className, forceScrollableHeight, visibleOnly, expandDocumentElements }) => {
|
|
527
526
|
const body = document.body;
|
|
528
527
|
const root = document.documentElement;
|
|
529
528
|
const scrollingElement = document.scrollingElement;
|
|
@@ -548,8 +547,8 @@ var expandScrollableContent = async (page, options = {}) => {
|
|
|
548
547
|
if (Number(style.opacity) === 0) return false;
|
|
549
548
|
return rect.width > 0 && rect.height > 0;
|
|
550
549
|
};
|
|
551
|
-
const rememberOriginalBoxStyles = (el) => {
|
|
552
|
-
if (!el || isDocumentElement(el) || el.classList.contains(className)) {
|
|
550
|
+
const rememberOriginalBoxStyles = (el, { includeDocumentElement = false } = {}) => {
|
|
551
|
+
if (!el || !includeDocumentElement && isDocumentElement(el) || el.classList.contains(className)) {
|
|
553
552
|
return;
|
|
554
553
|
}
|
|
555
554
|
el.dataset.pkOrigOverflow = el.style.overflow;
|
|
@@ -562,6 +561,19 @@ var expandScrollableContent = async (page, options = {}) => {
|
|
|
562
561
|
el.dataset.pkOrigMaxHeightPriority = el.style.getPropertyPriority("max-height") || "";
|
|
563
562
|
el.classList.add(className);
|
|
564
563
|
};
|
|
564
|
+
const expandDocumentElementsToHeight = (height) => {
|
|
565
|
+
if (!expandDocumentElements) return;
|
|
566
|
+
const targetHeight = Math.ceil(Number(height) || 0);
|
|
567
|
+
if (targetHeight <= 0) return;
|
|
568
|
+
[root, body, scrollingElement].forEach((el) => {
|
|
569
|
+
if (!el) return;
|
|
570
|
+
rememberOriginalBoxStyles(el, { includeDocumentElement: true });
|
|
571
|
+
el.style.setProperty("overflow", "visible", "important");
|
|
572
|
+
el.style.setProperty("height", `${targetHeight}px`, "important");
|
|
573
|
+
el.style.setProperty("min-height", `${targetHeight}px`, "important");
|
|
574
|
+
el.style.setProperty("max-height", "none", "important");
|
|
575
|
+
});
|
|
576
|
+
};
|
|
565
577
|
const isScrollableY = (el, style, rect) => {
|
|
566
578
|
if (!el || el.scrollHeight <= el.clientHeight + 1) {
|
|
567
579
|
return false;
|
|
@@ -598,6 +610,7 @@ var expandScrollableContent = async (page, options = {}) => {
|
|
|
598
610
|
return documentTop + scrollHeight;
|
|
599
611
|
};
|
|
600
612
|
const scrollableElements = [];
|
|
613
|
+
const expandedAncestors = [];
|
|
601
614
|
const expandElementToScrollHeight = (el) => {
|
|
602
615
|
if (!el || isDocumentElement(el)) return;
|
|
603
616
|
const scrollHeight = Math.ceil(el.scrollHeight || 0);
|
|
@@ -620,13 +633,44 @@ var expandScrollableContent = async (page, options = {}) => {
|
|
|
620
633
|
rememberOriginalBoxStyles(node);
|
|
621
634
|
node.style.setProperty("overflow", "visible", "important");
|
|
622
635
|
node.style.setProperty("max-height", "none", "important");
|
|
623
|
-
|
|
636
|
+
expandedAncestors.push(node);
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
const expandAncestorsToCurrentScrollHeight = () => {
|
|
640
|
+
const ancestors = [...new Set(expandedAncestors)];
|
|
641
|
+
for (let pass = 0; pass < 2; pass += 1) {
|
|
642
|
+
ancestors.forEach((node) => {
|
|
643
|
+
if (!node || isDocumentElement(node)) return;
|
|
624
644
|
const scrollHeight = Math.ceil(node.scrollHeight || 0);
|
|
645
|
+
if (scrollHeight <= node.clientHeight + 1) return;
|
|
646
|
+
rememberOriginalBoxStyles(node);
|
|
625
647
|
node.style.setProperty("height", `${scrollHeight}px`, "important");
|
|
626
648
|
node.style.setProperty("min-height", `${scrollHeight}px`, "important");
|
|
627
|
-
|
|
649
|
+
node.style.setProperty("max-height", "none", "important");
|
|
650
|
+
});
|
|
628
651
|
}
|
|
629
652
|
};
|
|
653
|
+
const measureExpandedRenderedBottom = () => {
|
|
654
|
+
let renderedBottom = maxHeight;
|
|
655
|
+
const scrollY = window.scrollY || window.pageYOffset || 0;
|
|
656
|
+
candidates.forEach((el) => {
|
|
657
|
+
if (!el || isDocumentElement(el)) return;
|
|
658
|
+
if (!el.classList.contains(className) && !el.closest(`.${className}`)) return;
|
|
659
|
+
const style = window.getComputedStyle(el);
|
|
660
|
+
const rect = el.getBoundingClientRect();
|
|
661
|
+
if (!isVisible(el, style, rect)) return;
|
|
662
|
+
renderedBottom = Math.max(renderedBottom, Math.ceil(rect.bottom + scrollY));
|
|
663
|
+
});
|
|
664
|
+
return renderedBottom;
|
|
665
|
+
};
|
|
666
|
+
const measureDocumentScrollHeight = () => {
|
|
667
|
+
return Math.max(
|
|
668
|
+
maxHeight,
|
|
669
|
+
Math.ceil(root?.scrollHeight || 0),
|
|
670
|
+
Math.ceil(body?.scrollHeight || 0),
|
|
671
|
+
Math.ceil(scrollingElement?.scrollHeight || 0)
|
|
672
|
+
);
|
|
673
|
+
};
|
|
630
674
|
candidates.forEach((el) => {
|
|
631
675
|
const style = window.getComputedStyle(el);
|
|
632
676
|
const rect = el.getBoundingClientRect();
|
|
@@ -657,46 +701,69 @@ var expandScrollableContent = async (page, options = {}) => {
|
|
|
657
701
|
el.style.height = "auto";
|
|
658
702
|
el.style.maxHeight = "none";
|
|
659
703
|
});
|
|
704
|
+
expandAncestorsToCurrentScrollHeight();
|
|
660
705
|
scrollableElements.forEach((el) => {
|
|
661
706
|
const neededHeight = measureNeededHeight(el);
|
|
662
707
|
if (neededHeight > maxHeight) {
|
|
663
708
|
maxHeight = neededHeight;
|
|
664
709
|
}
|
|
665
710
|
});
|
|
666
|
-
|
|
711
|
+
maxHeight = Math.max(maxHeight, measureDocumentScrollHeight(), measureExpandedRenderedBottom());
|
|
712
|
+
if (expandDocumentElements) {
|
|
713
|
+
for (let pass = 0; pass < 2; pass += 1) {
|
|
714
|
+
expandDocumentElementsToHeight(maxHeight);
|
|
715
|
+
maxHeight = Math.max(maxHeight, measureDocumentScrollHeight(), measureExpandedRenderedBottom());
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
return Math.ceil(maxHeight);
|
|
667
719
|
}, {
|
|
668
720
|
className: EXPANDED_SCROLLABLE_CLASS,
|
|
669
721
|
forceScrollableHeight: options.forceScrollableHeight !== false,
|
|
670
|
-
visibleOnly: options.visibleOnly !== false
|
|
722
|
+
visibleOnly: options.visibleOnly !== false,
|
|
723
|
+
expandDocumentElements: options.expandDocumentElements === true
|
|
671
724
|
});
|
|
672
725
|
};
|
|
673
726
|
var prepareExpandedFullPageScreenshot = async (page, options = {}) => {
|
|
674
727
|
const originalViewport = await resolveCurrentViewportSize(page);
|
|
675
|
-
const defaultBuffer = resolveDefaultBuffer(originalViewport);
|
|
676
|
-
const buffer = options.buffer ?? defaultBuffer;
|
|
677
728
|
const maxHeight = toPositiveInteger(options.maxHeight, DEFAULT_MAX_HEIGHT);
|
|
678
|
-
const
|
|
729
|
+
const preserveViewport = options.preserveViewport ?? resolvePageDevice(page) === Device.Mobile;
|
|
730
|
+
const defaultSettleMs = preserveViewport ? DEFAULT_MOBILE_SETTLE_MS : DEFAULT_SETTLE_MS;
|
|
731
|
+
const requestedSettleMs = Math.max(0, Number(options.settleMs ?? defaultSettleMs) || 0);
|
|
732
|
+
const settleMs = preserveViewport ? Math.min(requestedSettleMs, DEFAULT_MOBILE_SETTLE_MS) : requestedSettleMs;
|
|
679
733
|
const maxScrollHeight = await expandScrollableContent(page, {
|
|
680
734
|
forceScrollableHeight: options.forceScrollableHeight,
|
|
681
|
-
visibleOnly: options.visibleOnly !== false
|
|
682
|
-
|
|
683
|
-
const targetHeight = Math.min(maxScrollHeight + buffer, maxHeight);
|
|
684
|
-
await page.setViewportSize({
|
|
685
|
-
width: originalViewport.width,
|
|
686
|
-
height: targetHeight
|
|
735
|
+
visibleOnly: options.visibleOnly !== false,
|
|
736
|
+
expandDocumentElements: preserveViewport
|
|
687
737
|
});
|
|
738
|
+
const targetHeight = Math.min(maxScrollHeight, maxHeight);
|
|
739
|
+
let viewportResized = false;
|
|
740
|
+
if (!preserveViewport) {
|
|
741
|
+
await page.setViewportSize({
|
|
742
|
+
width: originalViewport.width,
|
|
743
|
+
height: targetHeight
|
|
744
|
+
});
|
|
745
|
+
viewportResized = true;
|
|
746
|
+
}
|
|
688
747
|
if (settleMs > 0) {
|
|
689
748
|
await delay(settleMs);
|
|
690
749
|
}
|
|
691
750
|
return {
|
|
692
751
|
originalViewport,
|
|
693
752
|
maxScrollHeight,
|
|
694
|
-
targetHeight
|
|
753
|
+
targetHeight,
|
|
754
|
+
preserveViewport,
|
|
755
|
+
viewportResized
|
|
695
756
|
};
|
|
696
757
|
};
|
|
697
758
|
var restoreExpandedFullPageScreenshot = async (page, state = {}) => {
|
|
698
759
|
await page.evaluate((className) => {
|
|
699
|
-
|
|
760
|
+
const targets = new Set([
|
|
761
|
+
...document.querySelectorAll(`.${className}`),
|
|
762
|
+
document.documentElement,
|
|
763
|
+
document.body,
|
|
764
|
+
document.scrollingElement
|
|
765
|
+
].filter((el) => el?.classList?.contains(className)));
|
|
766
|
+
targets.forEach((el) => {
|
|
700
767
|
el.style.setProperty("overflow", el.dataset.pkOrigOverflow || "", el.dataset.pkOrigOverflowPriority || "");
|
|
701
768
|
el.style.setProperty("height", el.dataset.pkOrigHeight || "", el.dataset.pkOrigHeightPriority || "");
|
|
702
769
|
el.style.setProperty("min-height", el.dataset.pkOrigMinHeight || "", el.dataset.pkOrigMinHeightPriority || "");
|
|
@@ -712,7 +779,7 @@ var restoreExpandedFullPageScreenshot = async (page, state = {}) => {
|
|
|
712
779
|
el.classList.remove(className);
|
|
713
780
|
});
|
|
714
781
|
}, EXPANDED_SCROLLABLE_CLASS);
|
|
715
|
-
if (state?.originalViewport) {
|
|
782
|
+
if (state?.originalViewport && state?.viewportResized) {
|
|
716
783
|
await page.setViewportSize(state.originalViewport);
|
|
717
784
|
}
|
|
718
785
|
};
|
|
@@ -1209,9 +1276,6 @@ var ProxyMeterRuntime = {
|
|
|
1209
1276
|
getProxyMeterSnapshot
|
|
1210
1277
|
};
|
|
1211
1278
|
|
|
1212
|
-
// src/internals/constants.js
|
|
1213
|
-
var PageRuntimeStateKey = "__playwright_toolkit_runtime_state__";
|
|
1214
|
-
|
|
1215
1279
|
// src/runtime-env.js
|
|
1216
1280
|
var BROWSER_PROFILE_SCHEMA_VERSION = 1;
|
|
1217
1281
|
var rememberedRuntimeState = null;
|
|
@@ -2322,6 +2386,358 @@ var AntiCheat = {
|
|
|
2322
2386
|
}
|
|
2323
2387
|
};
|
|
2324
2388
|
|
|
2389
|
+
// src/device-input.js
|
|
2390
|
+
var resolveDeviceFromPage = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
|
|
2391
|
+
var assertPage = (page, method) => {
|
|
2392
|
+
if (!page || typeof page !== "object") {
|
|
2393
|
+
throw new Error(`DeviceInput.${method} requires a Playwright page`);
|
|
2394
|
+
}
|
|
2395
|
+
};
|
|
2396
|
+
var isPoint = (value) => value && typeof value === "object" && Number.isFinite(Number(value.x)) && Number.isFinite(Number(value.y));
|
|
2397
|
+
var pointFromArgs = (pointOrX, maybeY) => {
|
|
2398
|
+
if (isPoint(pointOrX)) {
|
|
2399
|
+
return { x: Number(pointOrX.x), y: Number(pointOrX.y) };
|
|
2400
|
+
}
|
|
2401
|
+
return { x: Number(pointOrX), y: Number(maybeY) };
|
|
2402
|
+
};
|
|
2403
|
+
var resolveNativeTarget = (page, target) => {
|
|
2404
|
+
if (!target) return null;
|
|
2405
|
+
if (typeof target === "string") return page.locator(target);
|
|
2406
|
+
return target;
|
|
2407
|
+
};
|
|
2408
|
+
var normalizeSelectorOptions = (options = {}) => ({
|
|
2409
|
+
targetParent: Boolean(options.targetParent ?? options.parent ?? false),
|
|
2410
|
+
pick: options.pick === "last" || options.last ? "last" : "first",
|
|
2411
|
+
visibleOnly: options.visibleOnly !== false,
|
|
2412
|
+
fallbackDomClick: Boolean(options.fallbackDomClick),
|
|
2413
|
+
forceMouse: Boolean(options.forceMouse),
|
|
2414
|
+
forceClick: Boolean(options.forceClick),
|
|
2415
|
+
mouseOptions: options.mouseOptions || {},
|
|
2416
|
+
clickOptions: options.clickOptions || {},
|
|
2417
|
+
tapOptions: options.tapOptions || {}
|
|
2418
|
+
});
|
|
2419
|
+
var waitFor = (page, timeout) => {
|
|
2420
|
+
if (!timeout) return Promise.resolve();
|
|
2421
|
+
if (page && typeof page.waitForTimeout === "function") {
|
|
2422
|
+
return page.waitForTimeout(timeout);
|
|
2423
|
+
}
|
|
2424
|
+
return new Promise((resolve) => setTimeout(resolve, timeout));
|
|
2425
|
+
};
|
|
2426
|
+
var getTargetBoundingBox = async (target) => {
|
|
2427
|
+
if (!target) return null;
|
|
2428
|
+
if (typeof target.boundingBox === "function") return target.boundingBox();
|
|
2429
|
+
if (typeof target.elementHandle === "function") {
|
|
2430
|
+
const handle = await target.elementHandle();
|
|
2431
|
+
try {
|
|
2432
|
+
return await handle?.boundingBox?.();
|
|
2433
|
+
} finally {
|
|
2434
|
+
if (handle && typeof handle.dispose === "function") {
|
|
2435
|
+
await handle.dispose().catch(() => {
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
return null;
|
|
2441
|
+
};
|
|
2442
|
+
var assertPoint = (point) => {
|
|
2443
|
+
if (!Number.isFinite(point.x) || !Number.isFinite(point.y)) {
|
|
2444
|
+
throw new Error(`Invalid input point: ${JSON.stringify(point)}`);
|
|
2445
|
+
}
|
|
2446
|
+
};
|
|
2447
|
+
var dispatchMouseMove = (page, point, options = {}) => page.mouse.move(point.x, point.y, options);
|
|
2448
|
+
var dispatchMouseStart = (page, options = {}) => page.mouse.down(options);
|
|
2449
|
+
var dispatchMouseEnd = (page, options = {}) => page.mouse.up(options);
|
|
2450
|
+
var dragWithMouse = async (page, points, options = {}) => {
|
|
2451
|
+
await dispatchMouseMove(page, points.start, { steps: 8 });
|
|
2452
|
+
await waitFor(page, options.initialDelayMs ?? 250);
|
|
2453
|
+
await dispatchMouseStart(page);
|
|
2454
|
+
await waitFor(page, options.holdDelayMs ?? 350);
|
|
2455
|
+
await dispatchMouseMove(page, points.lift, { steps: 6 });
|
|
2456
|
+
await waitFor(page, options.liftDelayMs ?? 250);
|
|
2457
|
+
for (let step = 1; step <= points.steps; step += 1) {
|
|
2458
|
+
const progress = step / points.steps;
|
|
2459
|
+
const easedProgress = 1 - (1 - progress) * (1 - progress);
|
|
2460
|
+
await dispatchMouseMove(page, {
|
|
2461
|
+
x: points.lift.x + (points.end.x - points.lift.x) * easedProgress,
|
|
2462
|
+
y: points.lift.y + (points.end.y - points.lift.y) * easedProgress
|
|
2463
|
+
}, { steps: 2 });
|
|
2464
|
+
await waitFor(page, options.stepDelayMs ?? 90);
|
|
2465
|
+
}
|
|
2466
|
+
await waitFor(page, options.beforeReleaseDelayMs ?? 100);
|
|
2467
|
+
await dispatchMouseEnd(page);
|
|
2468
|
+
await waitFor(page, options.afterReleaseDelayMs ?? 100);
|
|
2469
|
+
return true;
|
|
2470
|
+
};
|
|
2471
|
+
var dragWithTouch = async (page, points, options = {}) => {
|
|
2472
|
+
let client = null;
|
|
2473
|
+
try {
|
|
2474
|
+
client = await page.context().newCDPSession(page);
|
|
2475
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
2476
|
+
type: "touchStart",
|
|
2477
|
+
touchPoints: [{ x: points.start.x, y: points.start.y, id: 1 }]
|
|
2478
|
+
});
|
|
2479
|
+
await waitFor(page, options.holdDelayMs ?? 350);
|
|
2480
|
+
const totalSteps = points.steps + 1;
|
|
2481
|
+
for (let step = 1; step <= totalSteps; step += 1) {
|
|
2482
|
+
const progress = step / totalSteps;
|
|
2483
|
+
const easedProgress = 1 - (1 - progress) * (1 - progress);
|
|
2484
|
+
const from = step === 1 ? points.start : points.lift;
|
|
2485
|
+
const to = points.end;
|
|
2486
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
2487
|
+
type: "touchMove",
|
|
2488
|
+
touchPoints: [{
|
|
2489
|
+
x: from.x + (to.x - from.x) * easedProgress,
|
|
2490
|
+
y: from.y + (to.y - from.y) * easedProgress,
|
|
2491
|
+
id: 1
|
|
2492
|
+
}]
|
|
2493
|
+
});
|
|
2494
|
+
await waitFor(page, options.stepDelayMs ?? 90);
|
|
2495
|
+
}
|
|
2496
|
+
await waitFor(page, options.beforeReleaseDelayMs ?? 100);
|
|
2497
|
+
await client.send("Input.dispatchTouchEvent", {
|
|
2498
|
+
type: "touchEnd",
|
|
2499
|
+
touchPoints: []
|
|
2500
|
+
});
|
|
2501
|
+
await waitFor(page, options.afterReleaseDelayMs ?? 100);
|
|
2502
|
+
return true;
|
|
2503
|
+
} finally {
|
|
2504
|
+
if (client && typeof client.detach === "function") {
|
|
2505
|
+
await client.detach().catch(() => {
|
|
2506
|
+
});
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
};
|
|
2510
|
+
var clickTargetWithDevice = async (page, target, options = {}) => {
|
|
2511
|
+
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2512
|
+
const resolvedDevice = resolveDeviceFromPage(page);
|
|
2513
|
+
if (target && resolvedDevice === Device.Mobile && !normalizedOptions.forceClick) {
|
|
2514
|
+
if (typeof target.tap === "function") {
|
|
2515
|
+
await target.tap(normalizedOptions.tapOptions);
|
|
2516
|
+
return true;
|
|
2517
|
+
}
|
|
2518
|
+
const box = await getTargetBoundingBox(target);
|
|
2519
|
+
if (box) {
|
|
2520
|
+
await DeviceInput.clickPoint(page, {
|
|
2521
|
+
x: box.x + box.width / 2,
|
|
2522
|
+
y: box.y + box.height / 2
|
|
2523
|
+
}, normalizedOptions);
|
|
2524
|
+
return true;
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
if (!target || typeof target.click !== "function") {
|
|
2528
|
+
throw new Error("DeviceInput click target does not expose click()");
|
|
2529
|
+
}
|
|
2530
|
+
await target.click(normalizedOptions.clickOptions || options);
|
|
2531
|
+
return true;
|
|
2532
|
+
};
|
|
2533
|
+
var DeviceInput = {
|
|
2534
|
+
device(page) {
|
|
2535
|
+
return resolveDeviceFromPage(page);
|
|
2536
|
+
},
|
|
2537
|
+
isMobile(page) {
|
|
2538
|
+
return resolveDeviceFromPage(page) === Device.Mobile;
|
|
2539
|
+
},
|
|
2540
|
+
async clickPoint(page, pointOrX, maybeY, options = {}) {
|
|
2541
|
+
assertPage(page, "clickPoint");
|
|
2542
|
+
const clickOptions = isPoint(pointOrX) && maybeY && typeof maybeY === "object" ? maybeY : options;
|
|
2543
|
+
const point = pointFromArgs(pointOrX, maybeY);
|
|
2544
|
+
assertPoint(point);
|
|
2545
|
+
if (resolveDeviceFromPage(page) === Device.Mobile && !clickOptions.forceMouse && page.touchscreen && typeof page.touchscreen.tap === "function") {
|
|
2546
|
+
await page.touchscreen.tap(point.x, point.y);
|
|
2547
|
+
return true;
|
|
2548
|
+
}
|
|
2549
|
+
await page.mouse.click(point.x, point.y, clickOptions.mouseOptions || {});
|
|
2550
|
+
return true;
|
|
2551
|
+
},
|
|
2552
|
+
async tapPoint(page, pointOrX, maybeY, options = {}) {
|
|
2553
|
+
return DeviceInput.clickPoint(page, pointOrX, maybeY, options);
|
|
2554
|
+
},
|
|
2555
|
+
async click(page, target, options = {}) {
|
|
2556
|
+
assertPage(page, "click");
|
|
2557
|
+
if (isPoint(target)) {
|
|
2558
|
+
return DeviceInput.clickPoint(page, target, void 0, options);
|
|
2559
|
+
}
|
|
2560
|
+
const nativeTarget = resolveNativeTarget(page, target);
|
|
2561
|
+
return clickTargetWithDevice(page, nativeTarget, options);
|
|
2562
|
+
},
|
|
2563
|
+
async tap(page, target, options = {}) {
|
|
2564
|
+
return DeviceInput.click(page, target, options);
|
|
2565
|
+
},
|
|
2566
|
+
async move(page, pointOrX, maybeY, options = {}) {
|
|
2567
|
+
assertPage(page, "move");
|
|
2568
|
+
const moveOptions = isPoint(pointOrX) && maybeY && typeof maybeY === "object" ? maybeY : options;
|
|
2569
|
+
const point = pointFromArgs(pointOrX, maybeY);
|
|
2570
|
+
assertPoint(point);
|
|
2571
|
+
if (resolveDeviceFromPage(page) === Device.Mobile && !moveOptions.forceMouse) {
|
|
2572
|
+
return true;
|
|
2573
|
+
}
|
|
2574
|
+
await page.mouse.move(point.x, point.y, moveOptions.mouseOptions || moveOptions);
|
|
2575
|
+
return true;
|
|
2576
|
+
},
|
|
2577
|
+
async focus(page, target, options = {}) {
|
|
2578
|
+
assertPage(page, "focus");
|
|
2579
|
+
const nativeTarget = resolveNativeTarget(page, target);
|
|
2580
|
+
if (!nativeTarget || typeof nativeTarget.focus !== "function") {
|
|
2581
|
+
throw new Error("DeviceInput focus target does not expose focus()");
|
|
2582
|
+
}
|
|
2583
|
+
await nativeTarget.focus(options);
|
|
2584
|
+
return true;
|
|
2585
|
+
},
|
|
2586
|
+
async fill(page, target, value, options = {}) {
|
|
2587
|
+
assertPage(page, "fill");
|
|
2588
|
+
const nativeTarget = resolveNativeTarget(page, target);
|
|
2589
|
+
if (!nativeTarget || typeof nativeTarget.fill !== "function") {
|
|
2590
|
+
throw new Error("DeviceInput fill target does not expose fill()");
|
|
2591
|
+
}
|
|
2592
|
+
await nativeTarget.fill(value, options);
|
|
2593
|
+
return true;
|
|
2594
|
+
},
|
|
2595
|
+
async keyboardType(page, text, options = {}) {
|
|
2596
|
+
assertPage(page, "keyboardType");
|
|
2597
|
+
await page.keyboard.type(text, options);
|
|
2598
|
+
return true;
|
|
2599
|
+
},
|
|
2600
|
+
async type(page, targetOrText, maybeText, options = {}) {
|
|
2601
|
+
assertPage(page, "type");
|
|
2602
|
+
if (maybeText == null || typeof maybeText === "object" && !Array.isArray(maybeText)) {
|
|
2603
|
+
return DeviceInput.keyboardType(page, targetOrText, maybeText || options);
|
|
2604
|
+
}
|
|
2605
|
+
const nativeTarget = resolveNativeTarget(page, targetOrText);
|
|
2606
|
+
if (!nativeTarget || typeof nativeTarget.type !== "function") {
|
|
2607
|
+
throw new Error("DeviceInput type target does not expose type()");
|
|
2608
|
+
}
|
|
2609
|
+
await nativeTarget.type(maybeText, options);
|
|
2610
|
+
return true;
|
|
2611
|
+
},
|
|
2612
|
+
async press(page, targetOrKey, maybeKey, options = {}) {
|
|
2613
|
+
assertPage(page, "press");
|
|
2614
|
+
const hasTarget = typeof maybeKey === "string";
|
|
2615
|
+
const key = hasTarget ? maybeKey : targetOrKey;
|
|
2616
|
+
const pressOptions = hasTarget ? options : maybeKey || options;
|
|
2617
|
+
if (hasTarget) {
|
|
2618
|
+
await DeviceInput.click(page, targetOrKey, pressOptions.clickOptions || {});
|
|
2619
|
+
}
|
|
2620
|
+
await page.keyboard.press(key, pressOptions.keyboardOptions || pressOptions);
|
|
2621
|
+
return true;
|
|
2622
|
+
},
|
|
2623
|
+
async selectorCenterPoint(page, selector, options = {}) {
|
|
2624
|
+
assertPage(page, "selectorCenterPoint");
|
|
2625
|
+
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2626
|
+
return page.evaluate(({ innerSelector, innerOptions }) => {
|
|
2627
|
+
const nodes = Array.from(document.querySelectorAll(innerSelector));
|
|
2628
|
+
const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
|
|
2629
|
+
let rect = null;
|
|
2630
|
+
for (const node of ordered) {
|
|
2631
|
+
if (!node) continue;
|
|
2632
|
+
const target = innerOptions.targetParent ? node.parentElement || node : node;
|
|
2633
|
+
rect = target.getBoundingClientRect?.() || null;
|
|
2634
|
+
const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
|
|
2635
|
+
if (innerOptions.visibleOnly && !isVisible) continue;
|
|
2636
|
+
break;
|
|
2637
|
+
}
|
|
2638
|
+
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
2639
|
+
return {
|
|
2640
|
+
x: rect.left + rect.width / 2,
|
|
2641
|
+
y: rect.top + rect.height / 2
|
|
2642
|
+
};
|
|
2643
|
+
}, { innerSelector: selector, innerOptions: normalizedOptions });
|
|
2644
|
+
},
|
|
2645
|
+
async domClick(page, selector, options = {}) {
|
|
2646
|
+
assertPage(page, "domClick");
|
|
2647
|
+
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2648
|
+
return page.evaluate(({ innerSelector, innerOptions }) => {
|
|
2649
|
+
const nodes = Array.from(document.querySelectorAll(innerSelector));
|
|
2650
|
+
const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
|
|
2651
|
+
let target = null;
|
|
2652
|
+
for (const node of ordered) {
|
|
2653
|
+
if (!node) continue;
|
|
2654
|
+
const candidate = innerOptions.targetParent ? node.parentElement || node : node;
|
|
2655
|
+
const rect = candidate.getBoundingClientRect?.() || null;
|
|
2656
|
+
const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
|
|
2657
|
+
if (innerOptions.visibleOnly && !isVisible) continue;
|
|
2658
|
+
target = candidate;
|
|
2659
|
+
break;
|
|
2660
|
+
}
|
|
2661
|
+
if (!target || typeof target.click !== "function") return false;
|
|
2662
|
+
target.click();
|
|
2663
|
+
return true;
|
|
2664
|
+
}, { innerSelector: selector, innerOptions: normalizedOptions });
|
|
2665
|
+
},
|
|
2666
|
+
async clickSelectorCenter(page, selector, options = {}) {
|
|
2667
|
+
assertPage(page, "clickSelectorCenter");
|
|
2668
|
+
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2669
|
+
try {
|
|
2670
|
+
const point = await DeviceInput.selectorCenterPoint(page, selector, normalizedOptions);
|
|
2671
|
+
if (point) {
|
|
2672
|
+
await DeviceInput.clickPoint(page, point, void 0, normalizedOptions);
|
|
2673
|
+
return true;
|
|
2674
|
+
}
|
|
2675
|
+
} catch (error) {
|
|
2676
|
+
if (!normalizedOptions.fallbackDomClick) throw error;
|
|
2677
|
+
}
|
|
2678
|
+
if (normalizedOptions.fallbackDomClick) {
|
|
2679
|
+
return DeviceInput.domClick(page, selector, normalizedOptions);
|
|
2680
|
+
}
|
|
2681
|
+
return false;
|
|
2682
|
+
},
|
|
2683
|
+
async clickText(frameOrPage, texts, options = {}) {
|
|
2684
|
+
for (const text of texts || []) {
|
|
2685
|
+
if (!text) continue;
|
|
2686
|
+
const candidates = [
|
|
2687
|
+
frameOrPage.getByText(text, { exact: false }).first(),
|
|
2688
|
+
frameOrPage.locator(`text=${text}`).first()
|
|
2689
|
+
];
|
|
2690
|
+
for (const candidate of candidates) {
|
|
2691
|
+
const isVisible = await candidate.isVisible({
|
|
2692
|
+
timeout: options.visibleTimeoutMs ?? options.actionVisibleTimeoutMs ?? 1500
|
|
2693
|
+
}).catch(() => false);
|
|
2694
|
+
if (!isVisible) continue;
|
|
2695
|
+
const page = options.page || (frameOrPage && typeof frameOrPage.context === "function" ? frameOrPage : null) || candidate.page?.();
|
|
2696
|
+
if (!page) {
|
|
2697
|
+
throw new Error("DeviceInput.clickText requires options.page when used with a frame locator");
|
|
2698
|
+
}
|
|
2699
|
+
await DeviceInput.click(page, candidate, options);
|
|
2700
|
+
return true;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
return false;
|
|
2704
|
+
},
|
|
2705
|
+
async drag(page, sourceLocator, targetLocator, options = {}) {
|
|
2706
|
+
assertPage(page, "drag");
|
|
2707
|
+
const sourceBox = await sourceLocator.boundingBox();
|
|
2708
|
+
const targetBox = await targetLocator.boundingBox();
|
|
2709
|
+
if (!sourceBox || !targetBox) {
|
|
2710
|
+
throw new Error("Unable to resolve drag coordinates.");
|
|
2711
|
+
}
|
|
2712
|
+
const steps = options.steps || 10;
|
|
2713
|
+
const liftOffsetX = Math.min(18, Math.max(8, sourceBox.width * 0.12));
|
|
2714
|
+
const liftOffsetY = Math.min(12, Math.max(4, sourceBox.height * 0.08));
|
|
2715
|
+
const points = {
|
|
2716
|
+
start: {
|
|
2717
|
+
x: sourceBox.x + sourceBox.width / 2,
|
|
2718
|
+
y: sourceBox.y + sourceBox.height / 2
|
|
2719
|
+
},
|
|
2720
|
+
lift: {
|
|
2721
|
+
x: sourceBox.x + sourceBox.width / 2 + liftOffsetX,
|
|
2722
|
+
y: sourceBox.y + sourceBox.height / 2 + liftOffsetY
|
|
2723
|
+
},
|
|
2724
|
+
end: {
|
|
2725
|
+
x: targetBox.x + targetBox.width / 2,
|
|
2726
|
+
y: targetBox.y + targetBox.height / 2
|
|
2727
|
+
},
|
|
2728
|
+
steps
|
|
2729
|
+
};
|
|
2730
|
+
if (resolveDeviceFromPage(page) === Device.Mobile && !options.forceMouse) {
|
|
2731
|
+
try {
|
|
2732
|
+
return await dragWithTouch(page, points, options);
|
|
2733
|
+
} catch (error) {
|
|
2734
|
+
if (options.allowMouseFallback === false) throw error;
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
return dragWithMouse(page, points, options);
|
|
2738
|
+
}
|
|
2739
|
+
};
|
|
2740
|
+
|
|
2325
2741
|
// src/internals/humanize/desktop.js
|
|
2326
2742
|
import delay2 from "delay";
|
|
2327
2743
|
import { createCursor } from "ghost-cursor-playwright";
|
|
@@ -2837,141 +3253,6 @@ var Humanize = {
|
|
|
2837
3253
|
}
|
|
2838
3254
|
};
|
|
2839
3255
|
|
|
2840
|
-
// src/internals/humanize/machine.js
|
|
2841
|
-
var resolveDeviceFromPage = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
|
|
2842
|
-
var isPoint = (value) => value && typeof value === "object" && Number.isFinite(Number(value.x)) && Number.isFinite(Number(value.y));
|
|
2843
|
-
var resolveNativeTarget = (page, target) => {
|
|
2844
|
-
if (!target) return null;
|
|
2845
|
-
if (typeof target === "string") {
|
|
2846
|
-
return page.locator(target);
|
|
2847
|
-
}
|
|
2848
|
-
return target;
|
|
2849
|
-
};
|
|
2850
|
-
var normalizeSelectorOptions = (options = {}) => ({
|
|
2851
|
-
targetParent: Boolean(options.targetParent ?? options.parent ?? false),
|
|
2852
|
-
pick: options.pick === "last" || options.last ? "last" : "first",
|
|
2853
|
-
visibleOnly: options.visibleOnly !== false,
|
|
2854
|
-
fallbackDomClick: Boolean(options.fallbackDomClick),
|
|
2855
|
-
forceMouse: Boolean(options.forceMouse)
|
|
2856
|
-
});
|
|
2857
|
-
var MachineHumanize = {
|
|
2858
|
-
async clickPoint(page, pointOrX, maybeY, options = {}) {
|
|
2859
|
-
const clickOptions = isPoint(pointOrX) && maybeY && typeof maybeY === "object" ? maybeY : options;
|
|
2860
|
-
const point = isPoint(pointOrX) ? pointOrX : { x: pointOrX, y: maybeY };
|
|
2861
|
-
const x = Number(point.x);
|
|
2862
|
-
const y = Number(point.y);
|
|
2863
|
-
if (!Number.isFinite(x) || !Number.isFinite(y)) {
|
|
2864
|
-
throw new Error(`Invalid click point: ${JSON.stringify(point)}`);
|
|
2865
|
-
}
|
|
2866
|
-
const resolvedDevice = resolveDeviceFromPage(page);
|
|
2867
|
-
if (resolvedDevice === Device.Mobile && !clickOptions.forceMouse && page.touchscreen && typeof page.touchscreen.tap === "function") {
|
|
2868
|
-
await page.touchscreen.tap(x, y);
|
|
2869
|
-
return true;
|
|
2870
|
-
}
|
|
2871
|
-
await page.mouse.click(x, y, clickOptions.mouseOptions || {});
|
|
2872
|
-
return true;
|
|
2873
|
-
},
|
|
2874
|
-
async click(page, target, options = {}) {
|
|
2875
|
-
if (isPoint(target)) {
|
|
2876
|
-
return MachineHumanize.clickPoint(page, target, void 0, options);
|
|
2877
|
-
}
|
|
2878
|
-
const nativeTarget = resolveNativeTarget(page, target);
|
|
2879
|
-
if (!nativeTarget || typeof nativeTarget.click !== "function") {
|
|
2880
|
-
throw new Error("Machine click target does not expose click()");
|
|
2881
|
-
}
|
|
2882
|
-
await nativeTarget.click(options.clickOptions || options);
|
|
2883
|
-
return true;
|
|
2884
|
-
},
|
|
2885
|
-
async focus(page, target, options = {}) {
|
|
2886
|
-
const nativeTarget = resolveNativeTarget(page, target);
|
|
2887
|
-
if (!nativeTarget || typeof nativeTarget.focus !== "function") {
|
|
2888
|
-
throw new Error("Machine focus target does not expose focus()");
|
|
2889
|
-
}
|
|
2890
|
-
await nativeTarget.focus(options);
|
|
2891
|
-
return true;
|
|
2892
|
-
},
|
|
2893
|
-
async fill(page, target, value, options = {}) {
|
|
2894
|
-
const nativeTarget = resolveNativeTarget(page, target);
|
|
2895
|
-
if (!nativeTarget || typeof nativeTarget.fill !== "function") {
|
|
2896
|
-
throw new Error("Machine fill target does not expose fill()");
|
|
2897
|
-
}
|
|
2898
|
-
await nativeTarget.fill(value, options);
|
|
2899
|
-
return true;
|
|
2900
|
-
},
|
|
2901
|
-
async keyboardType(page, text, options = {}) {
|
|
2902
|
-
await page.keyboard.type(text, options);
|
|
2903
|
-
return true;
|
|
2904
|
-
},
|
|
2905
|
-
async type(page, targetOrText, maybeText, options = {}) {
|
|
2906
|
-
if (maybeText == null || typeof maybeText === "object" && !Array.isArray(maybeText)) {
|
|
2907
|
-
return MachineHumanize.keyboardType(page, targetOrText, maybeText || options);
|
|
2908
|
-
}
|
|
2909
|
-
const nativeTarget = resolveNativeTarget(page, targetOrText);
|
|
2910
|
-
if (!nativeTarget || typeof nativeTarget.type !== "function") {
|
|
2911
|
-
throw new Error("Machine type target does not expose type()");
|
|
2912
|
-
}
|
|
2913
|
-
await nativeTarget.type(maybeText, options);
|
|
2914
|
-
return true;
|
|
2915
|
-
},
|
|
2916
|
-
async selectorCenterPoint(page, selector, options = {}) {
|
|
2917
|
-
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2918
|
-
return page.evaluate(({ innerSelector, innerOptions }) => {
|
|
2919
|
-
const nodes = Array.from(document.querySelectorAll(innerSelector));
|
|
2920
|
-
const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
|
|
2921
|
-
let rect = null;
|
|
2922
|
-
for (const node of ordered) {
|
|
2923
|
-
if (!node) continue;
|
|
2924
|
-
const target = innerOptions.targetParent ? node.parentElement || node : node;
|
|
2925
|
-
rect = target.getBoundingClientRect?.() || null;
|
|
2926
|
-
const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
|
|
2927
|
-
if (innerOptions.visibleOnly && !isVisible) continue;
|
|
2928
|
-
break;
|
|
2929
|
-
}
|
|
2930
|
-
if (!rect || rect.width <= 0 || rect.height <= 0) return null;
|
|
2931
|
-
return {
|
|
2932
|
-
x: rect.left + rect.width / 2,
|
|
2933
|
-
y: rect.top + rect.height / 2
|
|
2934
|
-
};
|
|
2935
|
-
}, { innerSelector: selector, innerOptions: normalizedOptions });
|
|
2936
|
-
},
|
|
2937
|
-
async domClick(page, selector, options = {}) {
|
|
2938
|
-
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2939
|
-
return page.evaluate(({ innerSelector, innerOptions }) => {
|
|
2940
|
-
const nodes = Array.from(document.querySelectorAll(innerSelector));
|
|
2941
|
-
const ordered = innerOptions.pick === "last" ? nodes.reverse() : nodes;
|
|
2942
|
-
let target = null;
|
|
2943
|
-
for (const node of ordered) {
|
|
2944
|
-
if (!node) continue;
|
|
2945
|
-
const candidate = innerOptions.targetParent ? node.parentElement || node : node;
|
|
2946
|
-
const rect = candidate.getBoundingClientRect?.() || null;
|
|
2947
|
-
const isVisible = Boolean(rect && rect.width > 0 && rect.height > 0);
|
|
2948
|
-
if (innerOptions.visibleOnly && !isVisible) continue;
|
|
2949
|
-
target = candidate;
|
|
2950
|
-
break;
|
|
2951
|
-
}
|
|
2952
|
-
if (!target || typeof target.click !== "function") return false;
|
|
2953
|
-
target.click();
|
|
2954
|
-
return true;
|
|
2955
|
-
}, { innerSelector: selector, innerOptions: normalizedOptions });
|
|
2956
|
-
},
|
|
2957
|
-
async clickSelectorCenter(page, selector, options = {}) {
|
|
2958
|
-
const normalizedOptions = normalizeSelectorOptions(options);
|
|
2959
|
-
try {
|
|
2960
|
-
const point = await MachineHumanize.selectorCenterPoint(page, selector, normalizedOptions);
|
|
2961
|
-
if (point) {
|
|
2962
|
-
await MachineHumanize.clickPoint(page, point, void 0, normalizedOptions);
|
|
2963
|
-
return true;
|
|
2964
|
-
}
|
|
2965
|
-
} catch (error) {
|
|
2966
|
-
if (!normalizedOptions.fallbackDomClick) throw error;
|
|
2967
|
-
}
|
|
2968
|
-
if (normalizedOptions.fallbackDomClick) {
|
|
2969
|
-
return MachineHumanize.domClick(page, selector, normalizedOptions);
|
|
2970
|
-
}
|
|
2971
|
-
return false;
|
|
2972
|
-
}
|
|
2973
|
-
};
|
|
2974
|
-
|
|
2975
3256
|
// src/internals/humanize/shared.js
|
|
2976
3257
|
import delay3 from "delay";
|
|
2977
3258
|
var jitterMs = (base, jitterPercent = 0.3) => {
|
|
@@ -3800,9 +4081,6 @@ var callDelegate = (method, page, args) => {
|
|
|
3800
4081
|
return delegate[method](page, ...args);
|
|
3801
4082
|
};
|
|
3802
4083
|
var Humanize2 = {
|
|
3803
|
-
// M = Machine: native/mechanical operations for兼容路径。
|
|
3804
|
-
// 这组 API 不做人类化处理,只保留原生 click / focus / fill / type 等语义。
|
|
3805
|
-
M: MachineHumanize,
|
|
3806
4084
|
jitterMs(base, jitterPercent = 0.3) {
|
|
3807
4085
|
return Humanize.jitterMs(base, jitterPercent);
|
|
3808
4086
|
},
|
|
@@ -4378,42 +4656,14 @@ var clickCaptchaAction = async (frame, texts, options) => {
|
|
|
4378
4656
|
if (!isVisible) {
|
|
4379
4657
|
continue;
|
|
4380
4658
|
}
|
|
4381
|
-
await
|
|
4659
|
+
await DeviceInput.click(options.page, candidate);
|
|
4382
4660
|
return true;
|
|
4383
4661
|
}
|
|
4384
4662
|
}
|
|
4385
4663
|
return false;
|
|
4386
4664
|
};
|
|
4387
|
-
var
|
|
4388
|
-
|
|
4389
|
-
const targetBox = await targetLocator.boundingBox();
|
|
4390
|
-
if (!sourceBox || !targetBox) {
|
|
4391
|
-
throw new Error("Unable to resolve captcha drag coordinates.");
|
|
4392
|
-
}
|
|
4393
|
-
const startX = sourceBox.x + sourceBox.width / 2;
|
|
4394
|
-
const startY = sourceBox.y + sourceBox.height / 2;
|
|
4395
|
-
const endX = targetBox.x + targetBox.width / 2;
|
|
4396
|
-
const endY = targetBox.y + targetBox.height / 2;
|
|
4397
|
-
const steps = 10;
|
|
4398
|
-
const liftOffsetX = Math.min(18, Math.max(8, sourceBox.width * 0.12));
|
|
4399
|
-
const liftOffsetY = Math.min(12, Math.max(4, sourceBox.height * 0.08));
|
|
4400
|
-
await page.mouse.move(startX, startY, { steps: 8 });
|
|
4401
|
-
await page.waitForTimeout(250);
|
|
4402
|
-
await page.mouse.down();
|
|
4403
|
-
await page.waitForTimeout(350);
|
|
4404
|
-
await page.mouse.move(startX + liftOffsetX, startY + liftOffsetY, { steps: 6 });
|
|
4405
|
-
await page.waitForTimeout(250);
|
|
4406
|
-
for (let step = 1; step <= steps; step++) {
|
|
4407
|
-
const progress = step / steps;
|
|
4408
|
-
const easedProgress = 1 - (1 - progress) * (1 - progress);
|
|
4409
|
-
const currentX = startX + liftOffsetX + (endX - startX - liftOffsetX) * easedProgress;
|
|
4410
|
-
const currentY = startY + liftOffsetY + (endY - startY - liftOffsetY) * easedProgress;
|
|
4411
|
-
await page.mouse.move(currentX, currentY, { steps: 2 });
|
|
4412
|
-
await page.waitForTimeout(90);
|
|
4413
|
-
}
|
|
4414
|
-
await page.waitForTimeout(100);
|
|
4415
|
-
await page.mouse.up();
|
|
4416
|
-
await page.waitForTimeout(100);
|
|
4665
|
+
var dragCaptchaAction = async (page, sourceLocator, targetLocator) => {
|
|
4666
|
+
await DeviceInput.drag(page, sourceLocator, targetLocator);
|
|
4417
4667
|
};
|
|
4418
4668
|
|
|
4419
4669
|
// src/internals/captcha/bytedance.js
|
|
@@ -4509,7 +4759,7 @@ var getVerifycenterCaptchaContext = async (page, options) => {
|
|
|
4509
4759
|
return { iframeLocator, frame };
|
|
4510
4760
|
};
|
|
4511
4761
|
var refreshCaptcha = async (page, frame, options) => {
|
|
4512
|
-
const clicked = await clickCaptchaAction(frame, options.refreshTexts, options).catch(() => false);
|
|
4762
|
+
const clicked = await clickCaptchaAction(frame, options.refreshTexts, { ...options, page }).catch(() => false);
|
|
4513
4763
|
if (!clicked) {
|
|
4514
4764
|
logger10.warn("Refresh button not found.");
|
|
4515
4765
|
return false;
|
|
@@ -4635,9 +4885,9 @@ async function solveCaptcha(page, options = {}, dependencies = {}) {
|
|
|
4635
4885
|
state: "visible",
|
|
4636
4886
|
timeout: config.sourceImageVisibleTimeoutMs
|
|
4637
4887
|
});
|
|
4638
|
-
await
|
|
4888
|
+
await dragCaptchaAction(page, sourceImage, dropTarget);
|
|
4639
4889
|
}
|
|
4640
|
-
const submitted = await clickCaptchaAction(frame, config.submitTexts, config).catch(() => false);
|
|
4890
|
+
const submitted = await clickCaptchaAction(frame, config.submitTexts, { ...config, page }).catch(() => false);
|
|
4641
4891
|
if (!submitted) {
|
|
4642
4892
|
logger10.warn("\u672A\u627E\u5230\u63D0\u4EA4\u6309\u94AE\uFF0C\u53EF\u80FD\u4F1A\u81EA\u52A8\u63D0\u4EA4\u3002");
|
|
4643
4893
|
}
|
|
@@ -7140,11 +7390,11 @@ var resolveScreenshotWatermarkifyMeta = async (page, options = {}) => {
|
|
|
7140
7390
|
watermark: options.watermark,
|
|
7141
7391
|
strip: options.strip,
|
|
7142
7392
|
stripLogoSrc,
|
|
7143
|
-
device:
|
|
7393
|
+
device: resolvePageDevice2(page)
|
|
7144
7394
|
};
|
|
7145
7395
|
};
|
|
7146
7396
|
var buildFontFamily = () => 'MiSans, "SF Pro Display", "PingFang SC", "Helvetica Neue", Arial, sans-serif';
|
|
7147
|
-
var
|
|
7397
|
+
var resolvePageDevice2 = (page) => normalizeDevice(page?.[PageRuntimeStateKey]?.device);
|
|
7148
7398
|
var findStripSegment = (segments, kind) => {
|
|
7149
7399
|
const found = Array.isArray(segments) ? segments.find((segment) => segment?.kind === kind) : null;
|
|
7150
7400
|
return found && typeof found === "object" ? found : {};
|
|
@@ -8343,7 +8593,6 @@ var Share = {
|
|
|
8343
8593
|
*
|
|
8344
8594
|
* @param {import('playwright').Page} page
|
|
8345
8595
|
* @param {Object} [options]
|
|
8346
|
-
* @param {number} [options.buffer] 额外缓冲高度;默认按视口高度自动计算,传 0 可关闭
|
|
8347
8596
|
* @param {boolean} [options.restore]
|
|
8348
8597
|
* @param {number} [options.maxHeight]
|
|
8349
8598
|
* @param {number} [options.maxBytes] 默认 5MiB,返回 base64 超过后会压缩
|
|
@@ -8356,7 +8605,6 @@ var Share = {
|
|
|
8356
8605
|
const screenshotWatermarkify = resolveCaptureScreenWatermarkify(page, options.watermarkify);
|
|
8357
8606
|
const compression = resolveImageCompression(options);
|
|
8358
8607
|
const captureOptions = {
|
|
8359
|
-
...Object.prototype.hasOwnProperty.call(options, "buffer") ? { buffer: options.buffer } : {},
|
|
8360
8608
|
restore,
|
|
8361
8609
|
maxHeight: options.maxHeight,
|
|
8362
8610
|
type: "png",
|
|
@@ -8382,6 +8630,7 @@ var usePlaywrightToolKit = () => {
|
|
|
8382
8630
|
return {
|
|
8383
8631
|
ApifyKit,
|
|
8384
8632
|
AntiCheat,
|
|
8633
|
+
DeviceInput,
|
|
8385
8634
|
Humanize: Humanize2,
|
|
8386
8635
|
Launch,
|
|
8387
8636
|
LiveView,
|