feat: add hover action support (#3994)
Co-authored-by: LawyZheng <lawyzheng1106@gmail.com>
This commit is contained in:
@@ -91,6 +91,7 @@ def sanitize_variable_name(name: str) -> str:
|
||||
|
||||
ACTION_MAP = {
|
||||
"click": "click",
|
||||
"hover": "hover",
|
||||
"input_text": "fill",
|
||||
"upload_file": "upload_file",
|
||||
"select_option": "select_option",
|
||||
@@ -108,6 +109,7 @@ ACTION_MAP = {
|
||||
}
|
||||
ACTIONS_WITH_XPATH = [
|
||||
"click",
|
||||
"hover",
|
||||
"input_text",
|
||||
"type",
|
||||
"fill",
|
||||
@@ -276,6 +278,19 @@ def _action_to_stmt(act: dict[str, Any], task: dict[str, Any], assign_to_output:
|
||||
),
|
||||
)
|
||||
)
|
||||
elif method == "hover":
|
||||
hold_seconds = act.get("hold_seconds")
|
||||
if hold_seconds and hold_seconds > 0:
|
||||
args.append(
|
||||
cst.Arg(
|
||||
keyword=cst.Name("hold_seconds"),
|
||||
value=_value(hold_seconds),
|
||||
whitespace_after_arg=cst.ParenthesizedWhitespace(
|
||||
indent=True,
|
||||
last_line=cst.SimpleWhitespace(INDENT),
|
||||
),
|
||||
)
|
||||
)
|
||||
elif method in ["type", "fill"]:
|
||||
# Use context.parameters if field_name is available, otherwise fallback to direct value
|
||||
if act.get("field_name"):
|
||||
|
||||
@@ -136,6 +136,7 @@ class ScriptSkyvernPage(SkyvernPage):
|
||||
ActionType.INPUT_TEXT: "⌨️",
|
||||
ActionType.UPLOAD_FILE: "📤",
|
||||
ActionType.DOWNLOAD_FILE: "📥",
|
||||
ActionType.HOVER: "🖱️",
|
||||
ActionType.SELECT_OPTION: "🎯",
|
||||
ActionType.WAIT: "⏳",
|
||||
ActionType.SOLVE_CAPTCHA: "🔓",
|
||||
|
||||
@@ -207,6 +207,27 @@ class SkyvernPage(Page):
|
||||
|
||||
return selector
|
||||
|
||||
@action_wrap(ActionType.HOVER)
|
||||
async def hover(
|
||||
self,
|
||||
selector: str,
|
||||
*,
|
||||
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
|
||||
hold_seconds: float = 0.0,
|
||||
intention: str | None = None,
|
||||
**kwargs: Any,
|
||||
) -> str:
|
||||
"""Move the mouse over the element identified by `selector`."""
|
||||
if not selector:
|
||||
raise ValueError("Hover requires a selector.")
|
||||
|
||||
locator = self.page.locator(selector, **kwargs)
|
||||
await locator.scroll_into_view_if_needed()
|
||||
await locator.hover(timeout=timeout)
|
||||
if hold_seconds and hold_seconds > 0:
|
||||
await asyncio.sleep(hold_seconds)
|
||||
return selector
|
||||
|
||||
@overload
|
||||
async def fill(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user