@skrillex1224/playwright-toolkit 2.1.243 → 2.1.244

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
@@ -3802,6 +3802,47 @@ var scrollAwayFromObstruction = async (element, status) => {
3802
3802
  };
3803
3803
  }, status);
3804
3804
  };
3805
+ var getElementViewportSnapshot = async (element) => {
3806
+ return element.evaluate((el) => {
3807
+ const rect = el.getBoundingClientRect();
3808
+ return {
3809
+ top: rect.top,
3810
+ bottom: rect.bottom,
3811
+ left: rect.left,
3812
+ right: rect.right,
3813
+ width: rect.width,
3814
+ height: rect.height,
3815
+ scrollX: window.scrollX,
3816
+ scrollY: window.scrollY
3817
+ };
3818
+ });
3819
+ };
3820
+ var isTargetImmobileAfterScroll = (before, after) => {
3821
+ if (!before || !after) return false;
3822
+ const rectDeltaY = Number(after.top || 0) - Number(before.top || 0);
3823
+ const rectDeltaX = Number(after.left || 0) - Number(before.left || 0);
3824
+ const scrollDeltaY = Number(after.scrollY || 0) - Number(before.scrollY || 0);
3825
+ const scrollDeltaX = Number(after.scrollX || 0) - Number(before.scrollX || 0);
3826
+ const rectMoved = Math.abs(rectDeltaY) > 3 || Math.abs(rectDeltaX) > 3;
3827
+ const pageMoved = Math.abs(scrollDeltaY) > 3 || Math.abs(scrollDeltaX) > 3;
3828
+ if (!rectMoved && !pageMoved) return true;
3829
+ if (pageMoved && !rectMoved) return true;
3830
+ if (Math.abs(scrollDeltaY) > 12 && Math.abs(rectDeltaY) < Math.min(12, Math.abs(scrollDeltaY) * 0.2)) {
3831
+ return true;
3832
+ }
3833
+ return false;
3834
+ };
3835
+ var restoreWindowFromSnapshot = async (page, before, after) => {
3836
+ if (!before || !after) return;
3837
+ if (Math.abs(Number(after.scrollX || 0) - Number(before.scrollX || 0)) <= 2 && Math.abs(Number(after.scrollY || 0) - Number(before.scrollY || 0)) <= 2) {
3838
+ return;
3839
+ }
3840
+ await page.evaluate(
3841
+ (state) => window.scrollTo(state.x, state.y),
3842
+ { x: Number(before.scrollX || 0), y: Number(before.scrollY || 0) }
3843
+ ).catch(() => {
3844
+ });
3845
+ };
3805
3846
  var dispatchTouchSwipe = async (page, deltaY, options = {}) => {
3806
3847
  const viewport = resolveViewport(page);
3807
3848
  const rawRect = options.rect || null;
@@ -3982,11 +4023,11 @@ var MobileHumanize = {
3982
4023
  const scrollRect = await getScrollableRect(element);
3983
4024
  if (!scrollRect && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
3984
4025
  logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u4E0D\u5728\u89C6\u53E3\u5185\uFF0C\u9875\u9762\u6EDA\u52A8\u65E0\u6CD5\u6539\u53D8\u5176\u4F4D\u7F6E (direction=${status.direction || "unknown"})`);
3985
- return { element, didScroll, restore: null };
4026
+ return { element, didScroll, restore: null, unscrollable: true };
3986
4027
  }
3987
4028
  if (!scrollRect && status.isFixed && status.code === "OBSTRUCTED") {
3988
4029
  logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u88AB\u906E\u6321\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u89E3\u9664 (${status.obstruction?.tag || "unknown"})`);
3989
- return { element, didScroll, restore: null };
4030
+ return { element, didScroll, restore: null, unscrollable: true };
3990
4031
  }
3991
4032
  if (scrollRect && status.code === "OBSTRUCTED" && status.obstruction?.isFixed) {
3992
4033
  const moved = await scrollAwayFromObstruction(element, status);
@@ -4017,6 +4058,7 @@ var MobileHumanize = {
4017
4058
  }
4018
4059
  }
4019
4060
  const beforeWindowState = scrollRect ? await page.evaluate(() => ({ x: window.scrollX, y: window.scrollY })) : null;
4061
+ const beforeElementSnapshot = await getElementViewportSnapshot(element).catch(() => null);
4020
4062
  const beforeState = scrollRect ? await element.evaluate((el) => {
4021
4063
  const isScrollable = (node) => {
4022
4064
  const style = window.getComputedStyle(node);
@@ -4046,6 +4088,21 @@ var MobileHumanize = {
4046
4088
  logger7.debug(`humanScroll | \u7A97\u53E3\u6EDA\u52A8\u56DE\u6536 from=${Math.round(afterWindowState.y)} to=${Math.round(beforeWindowState.y)}`);
4047
4089
  }
4048
4090
  }
4091
+ let afterElementSnapshot = null;
4092
+ const readAfterElementSnapshot = async () => {
4093
+ if (!afterElementSnapshot) {
4094
+ afterElementSnapshot = await getElementViewportSnapshot(element).catch(() => null);
4095
+ }
4096
+ return afterElementSnapshot;
4097
+ };
4098
+ if (!scrollRect && beforeElementSnapshot) {
4099
+ const afterSnapshot = await readAfterElementSnapshot();
4100
+ if (isTargetImmobileAfterScroll(beforeElementSnapshot, afterSnapshot)) {
4101
+ await restoreWindowFromSnapshot(page, beforeElementSnapshot, afterSnapshot);
4102
+ logger7.warn(`humanScroll | \u76EE\u6807\u4E0D\u968F\u9875\u9762\u6EDA\u52A8\u79FB\u52A8\uFF0C\u9875\u9762\u6EDA\u52A8\u65E0\u6CD5\u6539\u53D8\u5176\u4F4D\u7F6E (status=${status.code}, direction=${status.direction || "unknown"})`);
4103
+ return { element, didScroll, restore: null, unscrollable: true };
4104
+ }
4105
+ }
4049
4106
  if (scrollRect && beforeState) {
4050
4107
  const afterState = await element.evaluate((el) => {
4051
4108
  const isScrollable = (node) => {
@@ -4083,6 +4140,14 @@ var MobileHumanize = {
4083
4140
  }
4084
4141
  }
4085
4142
  }
4143
+ if (scrollRect && beforeElementSnapshot) {
4144
+ const afterSnapshot = await getElementViewportSnapshot(element).catch(() => null);
4145
+ if (isTargetImmobileAfterScroll(beforeElementSnapshot, afterSnapshot)) {
4146
+ await restoreWindowFromSnapshot(page, beforeElementSnapshot, afterSnapshot);
4147
+ logger7.warn(`humanScroll | \u76EE\u6807\u4E0D\u968F\u6EDA\u52A8\u5BB9\u5668\u79FB\u52A8\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u6539\u53D8\u5176\u4F4D\u7F6E (status=${status.code}, direction=${status.direction || "unknown"})`);
4148
+ return { element, didScroll, restore: null, unscrollable: true };
4149
+ }
4150
+ }
4086
4151
  didScroll = true;
4087
4152
  }
4088
4153
  try {
@@ -4132,21 +4197,28 @@ var MobileHumanize = {
4132
4197
  logger7.warn(`humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${targetDesc}`);
4133
4198
  return false;
4134
4199
  }
4135
- if (scrollIfNeeded) {
4136
- await MobileHumanize.humanScroll(page, element, { throwOnMissing });
4137
- }
4200
+ const scrollResult = scrollIfNeeded ? await MobileHumanize.humanScroll(page, element, { throwOnMissing }) : null;
4138
4201
  const status = await checkElementVisibility(element).catch(() => null);
4139
4202
  if (status && status.code !== "VISIBLE") {
4140
- if (fallbackDomClick && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
4141
- const fallback = await withTimeout(
4203
+ if (fallbackDomClick && (status.code === "OUT_OF_VIEWPORT" || status.code === "OBSTRUCTED") && (status.isFixed || scrollResult?.unscrollable)) {
4204
+ let fallback = await withTimeout(
4142
4205
  () => activateElementFallback(element, null, {
4143
4206
  editableOnly: true
4144
4207
  }),
4145
4208
  activateFallbackTimeoutMs,
4146
4209
  "focus fallback"
4147
4210
  ).catch(() => null);
4211
+ if (!fallback?.activated) {
4212
+ fallback = await withTimeout(
4213
+ () => activateElementFallback(element, null, {
4214
+ editableOnly: false
4215
+ }),
4216
+ activateFallbackTimeoutMs,
4217
+ "activation fallback"
4218
+ ).catch(() => null);
4219
+ }
4148
4220
  if (fallback?.activated) {
4149
- logger7.warn(`humanClick: fixed/sticky \u76EE\u6807\u4E0D\u5728\u89C6\u53E3\u5185\uFF0C\u5DF2\u7528 ${fallback.method} \u6FC0\u6D3B`);
4221
+ logger7.warn(`humanClick: \u4E0D\u53EF\u6EDA\u52A8\u76EE\u6807\u4E0D\u53EF\u7269\u7406\u70B9\u51FB\uFF0C\u5DF2\u7528 ${fallback.method} \u6FC0\u6D3B`);
4150
4222
  return true;
4151
4223
  }
4152
4224
  }