@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.cjs CHANGED
@@ -3830,6 +3830,47 @@ var scrollAwayFromObstruction = async (element, status) => {
3830
3830
  };
3831
3831
  }, status);
3832
3832
  };
3833
+ var getElementViewportSnapshot = async (element) => {
3834
+ return element.evaluate((el) => {
3835
+ const rect = el.getBoundingClientRect();
3836
+ return {
3837
+ top: rect.top,
3838
+ bottom: rect.bottom,
3839
+ left: rect.left,
3840
+ right: rect.right,
3841
+ width: rect.width,
3842
+ height: rect.height,
3843
+ scrollX: window.scrollX,
3844
+ scrollY: window.scrollY
3845
+ };
3846
+ });
3847
+ };
3848
+ var isTargetImmobileAfterScroll = (before, after) => {
3849
+ if (!before || !after) return false;
3850
+ const rectDeltaY = Number(after.top || 0) - Number(before.top || 0);
3851
+ const rectDeltaX = Number(after.left || 0) - Number(before.left || 0);
3852
+ const scrollDeltaY = Number(after.scrollY || 0) - Number(before.scrollY || 0);
3853
+ const scrollDeltaX = Number(after.scrollX || 0) - Number(before.scrollX || 0);
3854
+ const rectMoved = Math.abs(rectDeltaY) > 3 || Math.abs(rectDeltaX) > 3;
3855
+ const pageMoved = Math.abs(scrollDeltaY) > 3 || Math.abs(scrollDeltaX) > 3;
3856
+ if (!rectMoved && !pageMoved) return true;
3857
+ if (pageMoved && !rectMoved) return true;
3858
+ if (Math.abs(scrollDeltaY) > 12 && Math.abs(rectDeltaY) < Math.min(12, Math.abs(scrollDeltaY) * 0.2)) {
3859
+ return true;
3860
+ }
3861
+ return false;
3862
+ };
3863
+ var restoreWindowFromSnapshot = async (page, before, after) => {
3864
+ if (!before || !after) return;
3865
+ if (Math.abs(Number(after.scrollX || 0) - Number(before.scrollX || 0)) <= 2 && Math.abs(Number(after.scrollY || 0) - Number(before.scrollY || 0)) <= 2) {
3866
+ return;
3867
+ }
3868
+ await page.evaluate(
3869
+ (state) => window.scrollTo(state.x, state.y),
3870
+ { x: Number(before.scrollX || 0), y: Number(before.scrollY || 0) }
3871
+ ).catch(() => {
3872
+ });
3873
+ };
3833
3874
  var dispatchTouchSwipe = async (page, deltaY, options = {}) => {
3834
3875
  const viewport = resolveViewport(page);
3835
3876
  const rawRect = options.rect || null;
@@ -4010,11 +4051,11 @@ var MobileHumanize = {
4010
4051
  const scrollRect = await getScrollableRect(element);
4011
4052
  if (!scrollRect && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
4012
4053
  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"})`);
4013
- return { element, didScroll, restore: null };
4054
+ return { element, didScroll, restore: null, unscrollable: true };
4014
4055
  }
4015
4056
  if (!scrollRect && status.isFixed && status.code === "OBSTRUCTED") {
4016
4057
  logger7.warn(`humanScroll | fixed/sticky \u76EE\u6807\u88AB\u906E\u6321\uFF0C\u6EDA\u52A8\u65E0\u6CD5\u89E3\u9664 (${status.obstruction?.tag || "unknown"})`);
4017
- return { element, didScroll, restore: null };
4058
+ return { element, didScroll, restore: null, unscrollable: true };
4018
4059
  }
4019
4060
  if (scrollRect && status.code === "OBSTRUCTED" && status.obstruction?.isFixed) {
4020
4061
  const moved = await scrollAwayFromObstruction(element, status);
@@ -4045,6 +4086,7 @@ var MobileHumanize = {
4045
4086
  }
4046
4087
  }
4047
4088
  const beforeWindowState = scrollRect ? await page.evaluate(() => ({ x: window.scrollX, y: window.scrollY })) : null;
4089
+ const beforeElementSnapshot = await getElementViewportSnapshot(element).catch(() => null);
4048
4090
  const beforeState = scrollRect ? await element.evaluate((el) => {
4049
4091
  const isScrollable = (node) => {
4050
4092
  const style = window.getComputedStyle(node);
@@ -4074,6 +4116,21 @@ var MobileHumanize = {
4074
4116
  logger7.debug(`humanScroll | \u7A97\u53E3\u6EDA\u52A8\u56DE\u6536 from=${Math.round(afterWindowState.y)} to=${Math.round(beforeWindowState.y)}`);
4075
4117
  }
4076
4118
  }
4119
+ let afterElementSnapshot = null;
4120
+ const readAfterElementSnapshot = async () => {
4121
+ if (!afterElementSnapshot) {
4122
+ afterElementSnapshot = await getElementViewportSnapshot(element).catch(() => null);
4123
+ }
4124
+ return afterElementSnapshot;
4125
+ };
4126
+ if (!scrollRect && beforeElementSnapshot) {
4127
+ const afterSnapshot = await readAfterElementSnapshot();
4128
+ if (isTargetImmobileAfterScroll(beforeElementSnapshot, afterSnapshot)) {
4129
+ await restoreWindowFromSnapshot(page, beforeElementSnapshot, afterSnapshot);
4130
+ 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"})`);
4131
+ return { element, didScroll, restore: null, unscrollable: true };
4132
+ }
4133
+ }
4077
4134
  if (scrollRect && beforeState) {
4078
4135
  const afterState = await element.evaluate((el) => {
4079
4136
  const isScrollable = (node) => {
@@ -4111,6 +4168,14 @@ var MobileHumanize = {
4111
4168
  }
4112
4169
  }
4113
4170
  }
4171
+ if (scrollRect && beforeElementSnapshot) {
4172
+ const afterSnapshot = await getElementViewportSnapshot(element).catch(() => null);
4173
+ if (isTargetImmobileAfterScroll(beforeElementSnapshot, afterSnapshot)) {
4174
+ await restoreWindowFromSnapshot(page, beforeElementSnapshot, afterSnapshot);
4175
+ 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"})`);
4176
+ return { element, didScroll, restore: null, unscrollable: true };
4177
+ }
4178
+ }
4114
4179
  didScroll = true;
4115
4180
  }
4116
4181
  try {
@@ -4160,21 +4225,28 @@ var MobileHumanize = {
4160
4225
  logger7.warn(`humanClick: \u5143\u7D20\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u70B9\u51FB ${targetDesc}`);
4161
4226
  return false;
4162
4227
  }
4163
- if (scrollIfNeeded) {
4164
- await MobileHumanize.humanScroll(page, element, { throwOnMissing });
4165
- }
4228
+ const scrollResult = scrollIfNeeded ? await MobileHumanize.humanScroll(page, element, { throwOnMissing }) : null;
4166
4229
  const status = await checkElementVisibility(element).catch(() => null);
4167
4230
  if (status && status.code !== "VISIBLE") {
4168
- if (fallbackDomClick && status.isFixed && status.code === "OUT_OF_VIEWPORT") {
4169
- const fallback = await withTimeout(
4231
+ if (fallbackDomClick && (status.code === "OUT_OF_VIEWPORT" || status.code === "OBSTRUCTED") && (status.isFixed || scrollResult?.unscrollable)) {
4232
+ let fallback = await withTimeout(
4170
4233
  () => activateElementFallback(element, null, {
4171
4234
  editableOnly: true
4172
4235
  }),
4173
4236
  activateFallbackTimeoutMs,
4174
4237
  "focus fallback"
4175
4238
  ).catch(() => null);
4239
+ if (!fallback?.activated) {
4240
+ fallback = await withTimeout(
4241
+ () => activateElementFallback(element, null, {
4242
+ editableOnly: false
4243
+ }),
4244
+ activateFallbackTimeoutMs,
4245
+ "activation fallback"
4246
+ ).catch(() => null);
4247
+ }
4176
4248
  if (fallback?.activated) {
4177
- logger7.warn(`humanClick: fixed/sticky \u76EE\u6807\u4E0D\u5728\u89C6\u53E3\u5185\uFF0C\u5DF2\u7528 ${fallback.method} \u6FC0\u6D3B`);
4249
+ logger7.warn(`humanClick: \u4E0D\u53EF\u6EDA\u52A8\u76EE\u6807\u4E0D\u53EF\u7269\u7406\u70B9\u51FB\uFF0C\u5DF2\u7528 ${fallback.method} \u6FC0\u6D3B`);
4178
4250
  return true;
4179
4251
  }
4180
4252
  }