UNPKG

@hyperbrowser/agent

Version:

Hyperbrowsers Web Agent

106 lines (105 loc) 3.98 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ClickElementActionDefinition = void 0; const zod_1 = require("zod"); const utils_1 = require("../../utils"); const utils_2 = require("./utils"); const ClickElementAction = zod_1.z .object({ index: zod_1.z.number().describe("The numeric index of the element to click."), }) .describe("Click on an element identified by its index"); const MAX_STABLE_CHECKS = 2; const CLICK_CHECK_TIMEOUT_PERIOD = 2500; exports.ClickElementActionDefinition = { type: "clickElement", actionParams: ClickElementAction, run: async function (ctx, action) { const { index } = action; const locator = (0, utils_2.getLocator)(ctx, index); if (!locator) { return { success: false, message: "Element not found" }; } const exists = (await locator.count()) > 0; if (!exists) { return { success: false, message: "Element not found on page" }; } await locator.scrollIntoViewIfNeeded({ timeout: CLICK_CHECK_TIMEOUT_PERIOD, }); await Promise.all([ locator.waitFor({ state: "visible", timeout: CLICK_CHECK_TIMEOUT_PERIOD, }), waitForElementToBeEnabled(locator, CLICK_CHECK_TIMEOUT_PERIOD), waitForElementToBeStable(locator, CLICK_CHECK_TIMEOUT_PERIOD), ]); await locator.click({ force: true }); return { success: true, message: `Clicked element with index ${index}` }; }, pprintAction: function (params) { return `Click element at index ${params.index}`; }, }; /** * Waits for an element to become enabled with a timeout * @param locator The Playwright locator to check * @param timeout Maximum time to wait in milliseconds * @returns Promise that resolves when element is enabled or rejects on timeout */ async function waitForElementToBeEnabled(locator, timeout = 5000) { return Promise.race([ (async () => { while (true) { if (await locator.isEnabled()) { return; } await (0, utils_1.sleep)(100); } })(), new Promise((_, reject) => { setTimeout(() => reject(new Error("Timeout waiting for element to be enabled")), timeout); }), ]); } /** * Waits for an element to become stable (not moving) with a timeout * @param locator The Playwright locator to check * @param timeout Maximum time to wait in milliseconds * @returns Promise that resolves when element is stable or rejects on timeout */ async function waitForElementToBeStable(locator, timeout = 5000) { return Promise.race([ (async () => { let previousRect = null; let stableCount = 0; while (true) { const currentRect = await locator.boundingBox(); if (!currentRect) { await (0, utils_1.sleep)(100); continue; } if (previousRect && previousRect.x === currentRect.x && previousRect.y === currentRect.y && currentRect.width === (previousRect.width ?? 0) && currentRect.height === (previousRect.height ?? 0)) { stableCount++; if (stableCount >= MAX_STABLE_CHECKS) { // Element stable for {{ MAX_STABLE_CHECKS }} consecutive checks return; } } else { stableCount = 0; } previousRect = currentRect; await (0, utils_1.sleep)(100); } })(), new Promise((_, reject) => { setTimeout(() => reject(new Error("Timeout waiting for element to be stable")), timeout); }), ]); }