@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.js CHANGED
@@ -3411,6 +3411,11 @@ var DEFAULT_ACTIVATE_FALLBACK_TIMEOUT_MS = 900;
3411
3411
  var INTERACTIVE_SELECTOR = [
3412
3412
  "button",
3413
3413
  '[role="button"]',
3414
+ '[role="link"]',
3415
+ '[role="menuitem"]',
3416
+ '[role="tab"]',
3417
+ '[role="switch"]',
3418
+ '[role="checkbox"]',
3414
3419
  "a[href]",
3415
3420
  "label",
3416
3421
  "input",
@@ -3425,6 +3430,34 @@ var EDITABLE_SELECTOR = [
3425
3430
  "textarea",
3426
3431
  '[contenteditable="true"]'
3427
3432
  ].join(",");
3433
+ var INTERACTIVE_HINT_PATTERN = [
3434
+ "btn",
3435
+ "button",
3436
+ "send",
3437
+ "submit",
3438
+ "confirm",
3439
+ "cancel",
3440
+ "retry",
3441
+ "reload",
3442
+ "search",
3443
+ "copy",
3444
+ "share",
3445
+ "close",
3446
+ "more",
3447
+ "\u53D1\u9001",
3448
+ "\u63D0\u4EA4",
3449
+ "\u786E\u5B9A",
3450
+ "\u786E\u8BA4",
3451
+ "\u53D6\u6D88",
3452
+ "\u91CD\u8BD5",
3453
+ "\u641C\u7D22",
3454
+ "\u590D\u5236",
3455
+ "\u5206\u4EAB",
3456
+ "\u5173\u95ED",
3457
+ "\u66F4\u591A",
3458
+ "\u5C55\u5F00",
3459
+ "\u6536\u8D77"
3460
+ ].join("|");
3428
3461
  var clamp = (value, min, max) => Math.min(max, Math.max(min, value));
3429
3462
  var resolveViewport = (page) => page?.viewportSize?.() || { width: 390, height: 844 };
3430
3463
  var describeTarget = (target) => {
@@ -3464,7 +3497,47 @@ var withTimeout = async (operation, timeoutMs, label) => {
3464
3497
  }
3465
3498
  };
3466
3499
  var checkElementVisibility = async (element) => {
3467
- return element.evaluate((el, interactiveSelector) => {
3500
+ return element.evaluate((el, { interactiveSelector, interactiveHintPattern }) => {
3501
+ const interactiveHintRe = new RegExp(interactiveHintPattern, "i");
3502
+ const nodeClassName = (node) => {
3503
+ if (!node) return "";
3504
+ if (typeof node.className === "string") return node.className;
3505
+ if (node.className && typeof node.className.baseVal === "string") return node.className.baseVal;
3506
+ return "";
3507
+ };
3508
+ const interactiveScore = (node) => {
3509
+ if (!node || node.nodeType !== Node.ELEMENT_NODE) return 0;
3510
+ let score = 0;
3511
+ if (typeof node.matches === "function" && node.matches(interactiveSelector)) score += 8;
3512
+ const hints = [
3513
+ node.id || "",
3514
+ nodeClassName(node),
3515
+ node.getAttribute?.("aria-label") || "",
3516
+ node.getAttribute?.("title") || "",
3517
+ node.getAttribute?.("data-testid") || "",
3518
+ node.getAttribute?.("data-test") || "",
3519
+ node.getAttribute?.("data-click") || "",
3520
+ node.getAttribute?.("data-action") || "",
3521
+ node.getAttribute?.("onclick") || "",
3522
+ String(node.textContent || "").trim().slice(0, 24)
3523
+ ].join(" ");
3524
+ if (interactiveHintRe.test(hints)) score += 4;
3525
+ const style = window.getComputedStyle(node);
3526
+ if (style?.cursor === "pointer") score += 2;
3527
+ return score;
3528
+ };
3529
+ const closestInteractive = (node) => {
3530
+ let best = null;
3531
+ let bestScore = 0;
3532
+ for (let current = node; current && current !== document.body; current = current.parentElement) {
3533
+ const score = interactiveScore(current);
3534
+ if (score > bestScore || score > 0 && score === bestScore) {
3535
+ best = current;
3536
+ bestScore = score;
3537
+ }
3538
+ }
3539
+ return best;
3540
+ };
3468
3541
  const targetStyle = window.getComputedStyle(el);
3469
3542
  if (!targetStyle || targetStyle.display === "none" || targetStyle.visibility === "hidden" || targetStyle.visibility === "collapse") {
3470
3543
  return { code: "NOT_INTERACTABLE", reason: "\u5143\u7D20\u4E0D\u53EF\u89C1", direction: "down" };
@@ -3526,16 +3599,13 @@ var checkElementVisibility = async (element) => {
3526
3599
  positioning
3527
3600
  };
3528
3601
  }
3529
- const targetInteractive = typeof el.closest === "function" ? el.closest(interactiveSelector) : null;
3602
+ const targetInteractive = closestInteractive(el);
3530
3603
  const sameInteractiveTarget = (pointElement) => {
3531
3604
  if (!pointElement) return false;
3532
3605
  if (pointElement === el || el.contains(pointElement) || pointElement.contains(el)) {
3533
3606
  return true;
3534
3607
  }
3535
- if (!targetInteractive || typeof pointElement.closest !== "function") {
3536
- return false;
3537
- }
3538
- return pointElement.closest(interactiveSelector) === targetInteractive;
3608
+ return Boolean(targetInteractive && closestInteractive(pointElement) === targetInteractive);
3539
3609
  };
3540
3610
  const describeElement = (node) => {
3541
3611
  if (!node) return null;
@@ -3582,10 +3652,53 @@ var checkElementVisibility = async (element) => {
3582
3652
  };
3583
3653
  }
3584
3654
  return { code: "VISIBLE", isFixed, positioning };
3585
- }, INTERACTIVE_SELECTOR);
3655
+ }, {
3656
+ interactiveSelector: INTERACTIVE_SELECTOR,
3657
+ interactiveHintPattern: INTERACTIVE_HINT_PATTERN
3658
+ });
3586
3659
  };
3587
3660
  var resolveSafeTapPoint = async (element) => {
3588
- return element.evaluate((el, interactiveSelector) => {
3661
+ return element.evaluate((el, { interactiveSelector, interactiveHintPattern }) => {
3662
+ const interactiveHintRe = new RegExp(interactiveHintPattern, "i");
3663
+ const nodeClassName = (node) => {
3664
+ if (!node) return "";
3665
+ if (typeof node.className === "string") return node.className;
3666
+ if (node.className && typeof node.className.baseVal === "string") return node.className.baseVal;
3667
+ return "";
3668
+ };
3669
+ const interactiveScore = (node) => {
3670
+ if (!node || node.nodeType !== Node.ELEMENT_NODE) return 0;
3671
+ let score = 0;
3672
+ if (typeof node.matches === "function" && node.matches(interactiveSelector)) score += 8;
3673
+ const hints = [
3674
+ node.id || "",
3675
+ nodeClassName(node),
3676
+ node.getAttribute?.("aria-label") || "",
3677
+ node.getAttribute?.("title") || "",
3678
+ node.getAttribute?.("data-testid") || "",
3679
+ node.getAttribute?.("data-test") || "",
3680
+ node.getAttribute?.("data-click") || "",
3681
+ node.getAttribute?.("data-action") || "",
3682
+ node.getAttribute?.("onclick") || "",
3683
+ String(node.textContent || "").trim().slice(0, 24)
3684
+ ].join(" ");
3685
+ if (interactiveHintRe.test(hints)) score += 4;
3686
+ const style = window.getComputedStyle(node);
3687
+ if (style?.cursor === "pointer") score += 2;
3688
+ return score;
3689
+ };
3690
+ const closestInteractive = (node) => {
3691
+ let best = null;
3692
+ let bestScore = 0;
3693
+ for (let current = node; current && current !== document.body; current = current.parentElement) {
3694
+ const score = interactiveScore(current);
3695
+ if (score > bestScore || score > 0 && score === bestScore) {
3696
+ best = current;
3697
+ bestScore = score;
3698
+ }
3699
+ }
3700
+ return best;
3701
+ };
3589
3702
  const rect = el.getBoundingClientRect();
3590
3703
  if (!rect || rect.width <= 0 || rect.height <= 0) {
3591
3704
  return null;
@@ -3622,16 +3735,13 @@ var resolveSafeTapPoint = async (element) => {
3622
3735
  if (visibleWidth <= 1 || visibleHeight <= 1) {
3623
3736
  return null;
3624
3737
  }
3625
- const targetInteractive = typeof el.closest === "function" ? el.closest(interactiveSelector) : null;
3738
+ const targetInteractive = closestInteractive(el);
3626
3739
  const sameInteractiveTarget = (pointElement) => {
3627
3740
  if (!pointElement) return false;
3628
3741
  if (pointElement === el || el.contains(pointElement) || pointElement.contains(el)) {
3629
3742
  return true;
3630
3743
  }
3631
- if (!targetInteractive || typeof pointElement.closest !== "function") {
3632
- return false;
3633
- }
3634
- return pointElement.closest(interactiveSelector) === targetInteractive;
3744
+ return Boolean(targetInteractive && closestInteractive(pointElement) === targetInteractive);
3635
3745
  };
3636
3746
  const cx = visibleLeft + visibleWidth / 2;
3637
3747
  const cy = visibleTop + visibleHeight / 2;
@@ -3659,14 +3769,53 @@ var resolveSafeTapPoint = async (element) => {
3659
3769
  x: chosen.x,
3660
3770
  y: chosen.y
3661
3771
  };
3662
- }, INTERACTIVE_SELECTOR);
3772
+ }, {
3773
+ interactiveSelector: INTERACTIVE_SELECTOR,
3774
+ interactiveHintPattern: INTERACTIVE_HINT_PATTERN
3775
+ });
3663
3776
  };
3664
3777
  var activateElementFallback = async (element, point = null, options = {}) => {
3665
- return element.evaluate((el, { innerPoint, innerOptions, interactiveSelector, editableSelector }) => {
3778
+ return element.evaluate((el, { innerPoint, innerOptions, interactiveSelector, editableSelector, interactiveHintPattern }) => {
3779
+ const interactiveHintRe = new RegExp(interactiveHintPattern, "i");
3780
+ const nodeClassName = (node) => {
3781
+ if (!node) return "";
3782
+ if (typeof node.className === "string") return node.className;
3783
+ if (node.className && typeof node.className.baseVal === "string") return node.className.baseVal;
3784
+ return "";
3785
+ };
3786
+ const interactiveScore = (node) => {
3787
+ if (!node || node.nodeType !== Node.ELEMENT_NODE) return 0;
3788
+ let score = 0;
3789
+ if (typeof node.matches === "function" && node.matches(interactiveSelector)) score += 8;
3790
+ const hints = [
3791
+ node.id || "",
3792
+ nodeClassName(node),
3793
+ node.getAttribute?.("aria-label") || "",
3794
+ node.getAttribute?.("title") || "",
3795
+ node.getAttribute?.("data-testid") || "",
3796
+ node.getAttribute?.("data-test") || "",
3797
+ node.getAttribute?.("data-click") || "",
3798
+ node.getAttribute?.("data-action") || "",
3799
+ node.getAttribute?.("onclick") || "",
3800
+ String(node.textContent || "").trim().slice(0, 24)
3801
+ ].join(" ");
3802
+ if (interactiveHintRe.test(hints)) score += 4;
3803
+ const style = window.getComputedStyle(node);
3804
+ if (style?.cursor === "pointer") score += 2;
3805
+ return score;
3806
+ };
3666
3807
  const pointElement = innerPoint ? document.elementFromPoint(innerPoint.x, innerPoint.y) : null;
3667
3808
  const nearestInteractive = (node) => {
3668
- if (!node || typeof node.closest !== "function") return null;
3669
- return node.closest(interactiveSelector);
3809
+ let best = null;
3810
+ let bestScore = 0;
3811
+ for (let current = node; current && current !== document.body; current = current.parentElement) {
3812
+ const score = interactiveScore(current);
3813
+ if (score > bestScore || score > 0 && score === bestScore) {
3814
+ best = current;
3815
+ bestScore = score;
3816
+ }
3817
+ }
3818
+ return best;
3670
3819
  };
3671
3820
  const targetInteractive = nearestInteractive(el);
3672
3821
  const pointInteractive = nearestInteractive(pointElement);
@@ -3698,7 +3847,8 @@ var activateElementFallback = async (element, point = null, options = {}) => {
3698
3847
  innerPoint: point,
3699
3848
  innerOptions: options || {},
3700
3849
  interactiveSelector: INTERACTIVE_SELECTOR,
3701
- editableSelector: EDITABLE_SELECTOR
3850
+ editableSelector: EDITABLE_SELECTOR,
3851
+ interactiveHintPattern: INTERACTIVE_HINT_PATTERN
3702
3852
  });
3703
3853
  };
3704
3854
  var getScrollableRect = async (element) => {
@@ -4335,6 +4485,20 @@ var MobileHumanize = {
4335
4485
  const locator = page.locator(selector);
4336
4486
  await MobileHumanize.humanClick(page, locator, { scrollIfNeeded: true });
4337
4487
  await waitJitter(160, 0.4);
4488
+ const readValue = async () => {
4489
+ try {
4490
+ return await locator.inputValue({ timeout: 600 });
4491
+ } catch {
4492
+ return await locator.evaluate((el) => "value" in el ? String(el.value || "") : String(el.textContent || "")).catch(() => "");
4493
+ }
4494
+ };
4495
+ const currentValue = await readValue();
4496
+ if (!currentValue) return;
4497
+ await page.keyboard.press("ControlOrMeta+A");
4498
+ await waitJitter(90, 0.35);
4499
+ await page.keyboard.press("Backspace");
4500
+ await waitJitter(120, 0.35);
4501
+ if (!await readValue()) return;
4338
4502
  await locator.evaluate((el) => {
4339
4503
  if ("value" in el) {
4340
4504
  el.value = "";