feat: add hover action support (#3994)
Co-authored-by: LawyZheng <lawyzheng1106@gmail.com>
This commit is contained in:
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user