mirror of
https://github.com/CloakHQ/CloakBrowser.git
synced 2026-06-23 11:41:46 +02:00
fix(humanize): use shared deadline for timeout budget in frame and ElementHandle methods (#307)
Frame-level methods (click, dblclick, hover, dragAndDrop) passed the raw timeout to each sequential operation independently, causing 3x actual wait time when elements don't exist. ElementHandle methods had a similar 2x issue between actionability and pointer-events checks. Port the deadline + remainingMs() pattern already used by page-level methods. Also fix bot detection test selector after site added a hidden duplicate submit button.
This commit is contained in:
@@ -196,10 +196,12 @@ export function patchSingleElementHandle(
|
||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||
const force = options?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CLICK, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CLICK, remainingMs(), force);
|
||||
const info = await moveToElement(callCfg);
|
||||
if (!info) return origElClick(options);
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(timeout, 5000));
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(remainingMs(), 5000));
|
||||
await humanClick(raw, info.isInp, callCfg);
|
||||
};
|
||||
|
||||
@@ -216,10 +218,12 @@ export function patchSingleElementHandle(
|
||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||
const force = options?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CLICK, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CLICK, remainingMs(), force);
|
||||
const info = await moveToElement(callCfg);
|
||||
if (!info) return origElDblclick(options);
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(timeout, 5000));
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(remainingMs(), 5000));
|
||||
await raw.down({ clickCount: 2 });
|
||||
await sleep(rand(30, 60));
|
||||
await raw.up({ clickCount: 2 });
|
||||
@@ -235,7 +239,9 @@ export function patchSingleElementHandle(
|
||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||
const force = options?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_HOVER, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_HOVER, remainingMs(), force);
|
||||
const info = await moveToElement(callCfg);
|
||||
if (!info) return origElHover(options);
|
||||
};
|
||||
@@ -248,10 +254,12 @@ export function patchSingleElementHandle(
|
||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||
const force = (options as any)?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_INPUT, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_INPUT, remainingMs(), force);
|
||||
const info = await moveToElement(callCfg);
|
||||
if (!info) return origElType(text, options);
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(timeout, 5000));
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(remainingMs(), 5000));
|
||||
await humanClick(raw, info.isInp, callCfg);
|
||||
await sleep(rand(100, 250));
|
||||
let cdpSession: CDPSession | null = null;
|
||||
@@ -267,10 +275,12 @@ export function patchSingleElementHandle(
|
||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||
const force = options?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_INPUT, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_INPUT, remainingMs(), force);
|
||||
const info = await moveToElement(callCfg);
|
||||
if (!info) return origElFill(value, options);
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(timeout, 5000));
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(remainingMs(), 5000));
|
||||
await humanClick(raw, info.isInp, callCfg);
|
||||
await sleep(rand(100, 250));
|
||||
await originals.keyboardPress(SELECT_ALL);
|
||||
@@ -298,7 +308,9 @@ export function patchSingleElementHandle(
|
||||
}) => {
|
||||
const force = options?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_FOCUS, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_FOCUS, remainingMs(), force);
|
||||
const info = await moveToElement();
|
||||
if (!info) return origElSelectOption(values, options);
|
||||
await humanClick(raw, false, cfg);
|
||||
@@ -316,14 +328,16 @@ export function patchSingleElementHandle(
|
||||
}) => {
|
||||
const force = options?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CHECK, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CHECK, remainingMs(), force);
|
||||
try {
|
||||
const checked = await el.isChecked();
|
||||
if (checked) return;
|
||||
} catch {}
|
||||
const info = await moveToElement();
|
||||
if (!info) return origElCheck(options);
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(timeout, 5000));
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(remainingMs(), 5000));
|
||||
await humanClick(raw, info.isInp, cfg);
|
||||
};
|
||||
|
||||
@@ -337,14 +351,16 @@ export function patchSingleElementHandle(
|
||||
}) => {
|
||||
const force = options?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CHECK, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CHECK, remainingMs(), force);
|
||||
try {
|
||||
const checked = await el.isChecked();
|
||||
if (!checked) return;
|
||||
} catch {}
|
||||
const info = await moveToElement();
|
||||
if (!info) return origElUncheck(options);
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(timeout, 5000));
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(remainingMs(), 5000));
|
||||
await humanClick(raw, info.isInp, cfg);
|
||||
};
|
||||
|
||||
@@ -359,14 +375,16 @@ export function patchSingleElementHandle(
|
||||
}) => {
|
||||
const force = options?.force ?? false;
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CHECK, timeout, force);
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
if (!force) await ensureActionableHandle(el, CHECKS_CHECK, remainingMs(), force);
|
||||
try {
|
||||
const current = await el.isChecked();
|
||||
if (current === checked) return;
|
||||
} catch {}
|
||||
const info = await moveToElement();
|
||||
if (!info) return origElSetChecked(checked, options);
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(timeout, 5000));
|
||||
if (!force) await checkPointerEventsHandle(el, cursor.x, cursor.y, Math.min(remainingMs(), 5000));
|
||||
await humanClick(raw, info.isInp, cfg);
|
||||
};
|
||||
}
|
||||
|
||||
+29
-12
@@ -691,7 +691,12 @@ function patchSingleFrame(
|
||||
const origFrameTap = (frame as any).tap?.bind(frame);
|
||||
const origFrameDragAndDrop = frame.dragAndDrop.bind(frame);
|
||||
|
||||
const moveToFrameSelector = async (selector: string, options?: HumanActionOptions, inputBias = false) => {
|
||||
const moveToFrameSelector = async (
|
||||
selector: string,
|
||||
options: HumanActionOptions | undefined,
|
||||
inputBias: boolean,
|
||||
remainingMs: () => number,
|
||||
) => {
|
||||
const callCfg = mergeConfig(cfg, options?.human_config ?? options);
|
||||
if (callCfg.idle_between_actions) {
|
||||
await humanIdle(raw, cursor.x, cursor.y, callCfg);
|
||||
@@ -699,9 +704,9 @@ function patchSingleFrame(
|
||||
|
||||
const locator = firstFrameLocator(frame, selector);
|
||||
if (typeof locator.scrollIntoViewIfNeeded === 'function') {
|
||||
await locator.scrollIntoViewIfNeeded({ timeout: options?.timeout }).catch(() => undefined);
|
||||
await locator.scrollIntoViewIfNeeded({ timeout: Math.max(1, remainingMs()) }).catch(() => undefined);
|
||||
}
|
||||
const box = await locator.boundingBox({ timeout: options?.timeout ?? 30000 }).catch(() => null);
|
||||
const box = await locator.boundingBox({ timeout: Math.max(1, remainingMs()) }).catch(() => null);
|
||||
if (!box) return null;
|
||||
|
||||
const isInput = inputBias || await isFrameInputElement(frame, selector);
|
||||
@@ -713,23 +718,32 @@ function patchSingleFrame(
|
||||
};
|
||||
|
||||
const frameClick = async (selector: string, options?: HumanActionOptions) => {
|
||||
const moved = await moveToFrameSelector(selector, options);
|
||||
if (!moved) return origFrameClick(selector, options);
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
const moved = await moveToFrameSelector(selector, options, false, remainingMs);
|
||||
if (!moved) return origFrameClick(selector, { ...options, timeout: Math.max(1, remainingMs()) });
|
||||
await humanClick(raw, moved.isInput, moved.callCfg);
|
||||
};
|
||||
|
||||
const getFrameCdp = async () => stealth.getCdpSession().catch(() => null);
|
||||
|
||||
const frameHover = async (selector: string, options?: HumanActionOptions) => {
|
||||
const moved = await moveToFrameSelector(selector, options, false);
|
||||
if (!moved) return origFrameHover(selector, options);
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
const moved = await moveToFrameSelector(selector, options, false, remainingMs);
|
||||
if (!moved) return origFrameHover(selector, { ...options, timeout: Math.max(1, remainingMs()) });
|
||||
};
|
||||
|
||||
(frame as any).click = frameClick;
|
||||
|
||||
(frame as any).dblclick = async (selector: string, options?: HumanActionOptions) => {
|
||||
const moved = await moveToFrameSelector(selector, options);
|
||||
if (!moved) return origFrameDblclick(selector, options);
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(0, deadline - Date.now());
|
||||
const moved = await moveToFrameSelector(selector, options, false, remainingMs);
|
||||
if (!moved) return origFrameDblclick(selector, { ...options, timeout: Math.max(1, remainingMs()) });
|
||||
await raw.down({ clickCount: 2 });
|
||||
await sleep(rand(30, 60));
|
||||
await raw.up({ clickCount: 2 });
|
||||
@@ -820,8 +834,11 @@ function patchSingleFrame(
|
||||
timeout?: number;
|
||||
trial?: boolean;
|
||||
}) => {
|
||||
const srcBox = await firstFrameLocator(frame, source).boundingBox({ timeout: options?.timeout ?? 30000 }).catch(() => null);
|
||||
const tgtBox = await firstFrameLocator(frame, target).boundingBox({ timeout: options?.timeout ?? 30000 }).catch(() => null);
|
||||
const timeout = options?.timeout ?? 30000;
|
||||
const deadline = Date.now() + timeout;
|
||||
const remainingMs = () => Math.max(1, deadline - Date.now());
|
||||
const srcBox = await firstFrameLocator(frame, source).boundingBox({ timeout: remainingMs() }).catch(() => null);
|
||||
const tgtBox = await firstFrameLocator(frame, target).boundingBox({ timeout: remainingMs() }).catch(() => null);
|
||||
|
||||
if (srcBox && tgtBox) {
|
||||
const sx = srcBox.x + srcBox.width / 2;
|
||||
@@ -837,7 +854,7 @@ function patchSingleFrame(
|
||||
await sleep(rand(80, 150));
|
||||
await originals.mouseUp();
|
||||
} else {
|
||||
return origFrameDragAndDrop(source, target, options);
|
||||
return origFrameDragAndDrop(source, target, { ...options, timeout: Math.max(1, remainingMs()) });
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user