@skrillex1224/playwright-toolkit 2.1.244 → 2.1.245

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 CHANGED
@@ -3439,6 +3439,11 @@ var DEFAULT_ACTIVATE_FALLBACK_TIMEOUT_MS = 900;
3439
3439
  var INTERACTIVE_SELECTOR = [
3440
3440
  "button",
3441
3441
  '[role="button"]',
3442
+ '[role="link"]',
3443
+ '[role="menuitem"]',
3444
+ '[role="tab"]',
3445
+ '[role="switch"]',
3446
+ '[role="checkbox"]',
3442
3447
  "a[href]",
3443
3448
  "label",
3444
3449
  "input",
@@ -3453,6 +3458,34 @@ var EDITABLE_SELECTOR = [
3453
3458
  "textarea",
3454
3459
  '[contenteditable="true"]'
3455
3460
  ].join(",");
3461
+ var INTERACTIVE_HINT_PATTERN = [
3462
+ "btn",
3463
+ "button",
3464
+ "send",
3465
+ "submit",
3466
+ "confirm",
3467
+ "cancel",
3468
+ "retry",
3469
+ "reload",
3470
+ "search",
3471
+ "copy",
3472
+ "share",
3473
+ "close",
3474
+ "more",
3475
+ "\u53D1\u9001",
3476
+ "\u63D0\u4EA4",
3477
+ "\u786E\u5B9A",
3478
+ "\u786E\u8BA4",
3479
+ "\u53D6\u6D88",
3480
+ "\u91CD\u8BD5",
3481
+ "\u641C\u7D22",
3482
+ "\u590D\u5236",
3483
+ "\u5206\u4EAB",
3484
+ "\u5173\u95ED",
3485
+ "\u66F4\u591A",
3486
+ "\u5C55\u5F00",
3487
+ "\u6536\u8D77"
3488
+ ].join("|");
3456
3489
  var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
3457
3490
  var resolveViewport = (page) => page?.viewportSize?.() || { width: 390, height: 844 };
3458
3491
  var describeTarget = (target) => {
@@ -3492,7 +3525,47 @@ var withTimeout = async (operation, timeoutMs, label) => {
3492
3525
  }
3493
3526
  };
3494
3527
  var checkElementVisibility = async (element) => {
3495
- return element.evaluate((el, interactiveSelector) => {
3528
+ return element.evaluate((el, { interactiveSelector, interactiveHintPattern }) => {
3529
+ const interactiveHintRe = new RegExp(interactiveHintPattern, "i");
3530
+ const nodeClassName = (node) => {
3531
+ if (!node) return "";
3532
+ if (typeof node.className === "string") return node.className;
3533
+ if (node.className && typeof node.className.baseVal === "string") return node.className.baseVal;
3534
+ return "";
3535
+ };
3536
+ const interactiveScore = (node) => {
3537
+ if (!node || node.nodeType !== Node.ELEMENT_NODE) return 0;
3538
+ let score = 0;
3539
+ if (typeof node.matches === "function" && node.matches(interactiveSelector)) score += 8;
3540
+ const hints = [
3541
+ node.id || "",
3542
+ nodeClassName(node),
3543
+ node.getAttribute?.("aria-label") || "",
3544
+ node.getAttribute?.("title") || "",
3545
+ node.getAttribute?.("data-testid") || "",
3546
+ node.getAttribute?.("data-test") || "",
3547
+ node.getAttribute?.("data-click") || "",
3548
+ node.getAttribute?.("data-action") || "",
3549
+ node.getAttribute?.("onclick") || "",
3550
+ String(node.textContent || "").trim().slice(0, 24)
3551
+ ].join(" ");
3552
+ if (interactiveHintRe.test(hints)) score += 4;
3553
+ const style = window.getComputedStyle(node);
3554
+ if (style?.cursor === "pointer") score += 2;
3555
+ return score;
3556
+ };
3557
+ const closestInteractive = (node) => {
3558
+ let best = null;
3559
+ let bestScore = 0;
3560
+ for (let current = node; current && current !== document.body; current = current.parentElement) {
3561
+ const score = interactiveScore(current);
3562
+ if (score > bestScore || score > 0 && score === bestScore) {
3563
+ best = current;
3564
+ bestScore = score;
3565
+ }
3566
+ }
3567
+ return best;
3568
+ };
3496
3569
  const targetStyle = window.getComputedStyle(el);
3497
3570
  if (!targetStyle || targetStyle.display === "none" || targetStyle.visibility === "hidden" || targetStyle.visibility === "collapse") {
3498
3571
  return { code: "NOT_INTERACTABLE", reason: "\u5143\u7D20\u4E0D\u53EF\u89C1", direction: "down" };
@@ -3554,16 +3627,13 @@ var checkElementVisibility = async (element) => {
3554
3627
  positioning
3555
3628
  };
3556
3629
  }
3557
- const targetInteractive = typeof el.closest === "function" ? el.closest(interactiveSelector) : null;
3630
+ const targetInteractive = closestInteractive(el);
3558
3631
  const sameInteractiveTarget = (pointElement) => {
3559
3632
  if (!pointElement) return false;
3560
3633
  if (pointElement === el || el.contains(pointElement) || pointElement.contains(el)) {
3561
3634
  return true;
3562
3635
  }
3563
- if (!targetInteractive || typeof pointElement.closest !== "function") {
3564
- return false;
3565
- }
3566
- return pointElement.closest(interactiveSelector) === targetInteractive;
3636
+ return Boolean(targetInteractive && closestInteractive(pointElement) === targetInteractive);
3567
3637
  };
3568
3638
  const describeElement = (node) => {
3569
3639
  if (!node) return null;
@@ -3610,10 +3680,53 @@ var checkElementVisibility = async (element) => {
3610
3680
  };
3611
3681
  }
3612
3682
  return { code: "VISIBLE", isFixed, positioning };
3613
- }, INTERACTIVE_SELECTOR);
3683
+ }, {
3684
+ interactiveSelector: INTERACTIVE_SELECTOR,
3685
+ interactiveHintPattern: INTERACTIVE_HINT_PATTERN
3686
+ });
3614
3687
  };
3615
3688
  var resolveSafeTapPoint = async (element) => {
3616
- return element.evaluate((el, interactiveSelector) => {
3689
+ return element.evaluate((el, { interactiveSelector, interactiveHintPattern }) => {
3690
+ const interactiveHintRe = new RegExp(interactiveHintPattern, "i");
3691
+ const nodeClassName = (node) => {
3692
+ if (!node) return "";
3693
+ if (typeof node.className === "string") return node.className;
3694
+ if (node.className && typeof node.className.baseVal === "string") return node.className.baseVal;
3695
+ return "";
3696
+ };
3697
+ const interactiveScore = (node) => {
3698
+ if (!node || node.nodeType !== Node.ELEMENT_NODE) return 0;
3699
+ let score = 0;
3700
+ if (typeof node.matches === "function" && node.matches(interactiveSelector)) score += 8;
3701
+ const hints = [
3702
+ node.id || "",
3703
+ nodeClassName(node),
3704
+ node.getAttribute?.("aria-label") || "",
3705
+ node.getAttribute?.("title") || "",
3706
+ node.getAttribute?.("data-testid") || "",
3707
+ node.getAttribute?.("data-test") || "",
3708
+ node.getAttribute?.("data-click") || "",
3709
+ node.getAttribute?.("data-action") || "",
3710
+ node.getAttribute?.("onclick") || "",
3711
+ String(node.textContent || "").trim().slice(0, 24)
3712
+ ].join(" ");
3713
+ if (interactiveHintRe.test(hints)) score += 4;
3714
+ const style = window.getComputedStyle(node);
3715
+ if (style?.cursor === "pointer") score += 2;
3716
+ return score;
3717
+ };
3718
+ const closestInteractive = (node) => {
3719
+ let best = null;
3720
+ let bestScore = 0;
3721
+ for (let current = node; current && current !== document.body; current = current.parentElement) {
3722
+ const score = interactiveScore(current);
3723
+ if (score > bestScore || score > 0 && score === bestScore) {
3724
+ best = current;
3725
+ bestScore = score;
3726
+ }
3727
+ }
3728
+ return best;
3729
+ };
3617
3730
  const rect = el.getBoundingClientRect();
3618
3731
  if (!rect || rect.width <= 0 || rect.height <= 0) {
3619
3732
  return null;
@@ -3650,16 +3763,13 @@ var resolveSafeTapPoint = async (element) => {
3650
3763
  if (visibleWidth <= 1 || visibleHeight <= 1) {
3651
3764
  return null;
3652
3765
  }
3653
- const targetInteractive = typeof el.closest === "function" ? el.closest(interactiveSelector) : null;
3766
+ const targetInteractive = closestInteractive(el);
3654
3767
  const sameInteractiveTarget = (pointElement) => {
3655
3768
  if (!pointElement) return false;
3656
3769
  if (pointElement === el || el.contains(pointElement) || pointElement.contains(el)) {
3657
3770
  return true;
3658
3771
  }
3659
- if (!targetInteractive || typeof pointElement.closest !== "function") {
3660
- return false;
3661
- }
3662
- return pointElement.closest(interactiveSelector) === targetInteractive;
3772
+ return Boolean(targetInteractive && closestInteractive(pointElement) === targetInteractive);
3663
3773
  };
3664
3774
  const cx = visibleLeft + visibleWidth / 2;
3665
3775
  const cy = visibleTop + visibleHeight / 2;
@@ -3687,14 +3797,53 @@ var resolveSafeTapPoint = async (element) => {
3687
3797
  x: chosen.x,
3688
3798
  y: chosen.y
3689
3799
  };
3690
- }, INTERACTIVE_SELECTOR);
3800
+ }, {
3801
+ interactiveSelector: INTERACTIVE_SELECTOR,
3802
+ interactiveHintPattern: INTERACTIVE_HINT_PATTERN
3803
+ });
3691
3804
  };
3692
3805
  var activateElementFallback = async (element, point = null, options = {}) => {
3693
- return element.evaluate((el, { innerPoint, innerOptions, interactiveSelector, editableSelector }) => {
3806
+ return element.evaluate((el, { innerPoint, innerOptions, interactiveSelector, editableSelector, interactiveHintPattern }) => {
3807
+ const interactiveHintRe = new RegExp(interactiveHintPattern, "i");
3808
+ const nodeClassName = (node) => {
3809
+ if (!node) return "";
3810
+ if (typeof node.className === "string") return node.className;
3811
+ if (node.className && typeof node.className.baseVal === "string") return node.className.baseVal;
3812
+ return "";
3813
+ };
3814
+ const interactiveScore = (node) => {
3815
+ if (!node || node.nodeType !== Node.ELEMENT_NODE) return 0;
3816
+ let score = 0;
3817
+ if (typeof node.matches === "function" && node.matches(interactiveSelector)) score += 8;
3818
+ const hints = [
3819
+ node.id || "",
3820
+ nodeClassName(node),
3821
+ node.getAttribute?.("aria-label") || "",
3822
+ node.getAttribute?.("title") || "",
3823
+ node.getAttribute?.("data-testid") || "",
3824
+ node.getAttribute?.("data-test") || "",
3825
+ node.getAttribute?.("data-click") || "",
3826
+ node.getAttribute?.("data-action") || "",
3827
+ node.getAttribute?.("onclick") || "",
3828
+ String(node.textContent || "").trim().slice(0, 24)
3829
+ ].join(" ");
3830
+ if (interactiveHintRe.test(hints)) score += 4;
3831
+ const style = window.getComputedStyle(node);
3832
+ if (style?.cursor === "pointer") score += 2;
3833
+ return score;
3834
+ };
3694
3835
  const pointElement = innerPoint ? document.elementFromPoint(innerPoint.x, innerPoint.y) : null;
3695
3836
  const nearestInteractive = (node) => {
3696
- if (!node || typeof node.closest !== "function") return null;
3697
- return node.closest(interactiveSelector);
3837
+ let best = null;
3838
+ let bestScore = 0;
3839
+ for (let current = node; current && current !== document.body; current = current.parentElement) {
3840
+ const score = interactiveScore(current);
3841
+ if (score > bestScore || score > 0 && score === bestScore) {
3842
+ best = current;
3843
+ bestScore = score;
3844
+ }
3845
+ }
3846
+ return best;
3698
3847
  };
3699
3848
  const targetInteractive = nearestInteractive(el);
3700
3849
  const pointInteractive = nearestInteractive(pointElement);
@@ -3726,7 +3875,8 @@ var activateElementFallback = async (element, point = null, options = {}) => {
3726
3875
  innerPoint: point,
3727
3876
  innerOptions: options || {},
3728
3877
  interactiveSelector: INTERACTIVE_SELECTOR,
3729
- editableSelector: EDITABLE_SELECTOR
3878
+ editableSelector: EDITABLE_SELECTOR,
3879
+ interactiveHintPattern: INTERACTIVE_HINT_PATTERN
3730
3880
  });
3731
3881
  };
3732
3882
  var getScrollableRect = async (element) => {
@@ -4363,6 +4513,20 @@ var MobileHumanize = {
4363
4513
  const locator = page.locator(selector);
4364
4514
  await MobileHumanize.humanClick(page, locator, { scrollIfNeeded: true });
4365
4515
  await waitJitter(160, 0.4);
4516
+ const readValue = async () => {
4517
+ try {
4518
+ return await locator.inputValue({ timeout: 600 });
4519
+ } catch {
4520
+ return await locator.evaluate((el) => "value" in el ? String(el.value || "") : String(el.textContent || "")).catch(() => "");
4521
+ }
4522
+ };
4523
+ const currentValue = await readValue();
4524
+ if (!currentValue) return;
4525
+ await page.keyboard.press("ControlOrMeta+A");
4526
+ await waitJitter(90, 0.35);
4527
+ await page.keyboard.press("Backspace");
4528
+ await waitJitter(120, 0.35);
4529
+ if (!await readValue()) return;
4366
4530
  await locator.evaluate((el) => {
4367
4531
  if ("value" in el) {
4368
4532
  el.value = "";