feat: add hover action support (#3994)

Co-authored-by: LawyZheng <lawyzheng1106@gmail.com>
This commit is contained in:
Mohamed Khalil
2025-12-09 17:27:26 +02:00
committed by GitHub
parent 0e8d667959
commit f49b07f30d
22 changed files with 281 additions and 13 deletions

View File

@@ -133,6 +133,7 @@ class SkyvernElement:
self._id_cache = static_element.get("id", "")
self._tag_name = static_element.get("tagName", "")
self._selectable = static_element.get("isSelectable", False)
self._hover_only = static_element.get("hoverOnly", False)
self._frame_id = static_element.get("frame", "")
self._attributes = static_element.get("attributes", {})
self._rect: FloatRect | None = None
@@ -401,6 +402,49 @@ class SkyvernElement:
def get_attributes(self) -> dict:
return self._attributes
def requires_hover(self) -> bool:
return bool(self._hover_only)
async def hover_to_reveal(
self,
max_depth: int = 4,
timeout: float = settings.BROWSER_ACTION_TIMEOUT_MS,
settle_delay_s: float = 0.15,
) -> bool:
if not self.requires_hover():
return False
hover_target = self.get_locator()
for depth in range(max_depth):
try:
await hover_target.scroll_into_view_if_needed()
await hover_target.hover(timeout=timeout)
await asyncio.sleep(settle_delay_s)
if await self.get_locator().is_visible(timeout=timeout):
LOG.debug("Hover reveal succeeded", element_id=self.get_id(), depth=depth)
return True
except Exception:
LOG.debug(
"Hover attempt failed while trying to reveal element",
exc_info=True,
element_id=self.get_id(),
depth=depth,
)
parent_locator = hover_target.locator("..")
try:
if await parent_locator.count() != 1:
break
except Exception:
LOG.debug(
"Unable to evaluate parent locator during hover reveal", exc_info=True, element_id=self.get_id()
)
break
hover_target = parent_locator
LOG.debug("Hover reveal attempts exhausted", element_id=self.get_id())
return False
def get_options(self) -> list[SkyvernOptionType]:
options = self.__static_element.get("options", None)
if options is None: