From d667841d02e767ab707c52e13a5f1862518d3c1a Mon Sep 17 00:00:00 2001 From: Shuchang Zheng Date: Thu, 8 May 2025 22:52:12 -0700 Subject: [PATCH] fix hidden input element (#2314) --- skyvern/exceptions.py | 7 +++++++ skyvern/webeye/actions/handler.py | 6 ++++++ skyvern/webeye/scraper/domUtils.js | 1 + skyvern/webeye/utils/dom.py | 9 +++++++++ 4 files changed, 23 insertions(+) diff --git a/skyvern/exceptions.py b/skyvern/exceptions.py index 62bce444..80c0a9ac 100644 --- a/skyvern/exceptions.py +++ b/skyvern/exceptions.py @@ -619,6 +619,13 @@ class InteractWithDisabledElement(SkyvernException): ) +class InputToInvisibleElement(SkyvernException): + def __init__(self, element_id: str): + super().__init__( + f"The element(id={element_id}) now is not visible. Try to interact with other elements, or try to interact with it later when it's visible." + ) + + class FailedToParseActionInstruction(SkyvernException): def __init__(self, reason: str | None, error_type: str | None): super().__init__( diff --git a/skyvern/webeye/actions/handler.py b/skyvern/webeye/actions/handler.py index 8e394729..522f3d11 100644 --- a/skyvern/webeye/actions/handler.py +++ b/skyvern/webeye/actions/handler.py @@ -32,6 +32,7 @@ from skyvern.exceptions import ( FailToSelectByValue, IllegitComplete, ImaginaryFileUrl, + InputToInvisibleElement, InteractWithDisabledElement, InteractWithDropdownContainer, InvalidElementForTextInput, @@ -876,6 +877,11 @@ async def handle_input_text_action( await skyvern_element.blur() await incremental_scraped.stop_listen_dom_increment() + ### Start filling text logic + # check if the element has hidden attribute + if await skyvern_element.has_hidden_attr(): + return [ActionFailure(InputToInvisibleElement(skyvern_element.get_id()), stop_execution_on_failure=False)] + # force to move focus back to the element await skyvern_element.get_locator().focus(timeout=timeout) diff --git a/skyvern/webeye/scraper/domUtils.js b/skyvern/webeye/scraper/domUtils.js index 536d65b1..0ae577bd 100644 --- a/skyvern/webeye/scraper/domUtils.js +++ b/skyvern/webeye/scraper/domUtils.js @@ -277,6 +277,7 @@ function hasASPClientControl() { } // from playwright: https://github.com/microsoft/playwright/blob/1b65f26f0287c0352e76673bc5f85bc36c934b55/packages/playwright-core/src/server/injected/domUtils.ts#L100-L119 +// NOTE: According this logic, some elements with aria-hidden won't be considered as invisible. And the result shows they are indeed interactable. function isElementVisible(element) { // TODO: This is a hack to not check visibility for option elements // because they are not visible by default. We check their parent instead for visibility. diff --git a/skyvern/webeye/utils/dom.py b/skyvern/webeye/utils/dom.py index ffb5aa2e..b2adf6b0 100644 --- a/skyvern/webeye/utils/dom.py +++ b/skyvern/webeye/utils/dom.py @@ -297,6 +297,15 @@ class SkyvernElement: skyvern_frame = await SkyvernFrame.create_instance(self.get_frame()) return await skyvern_frame.is_sibling(await self.get_element_handler(), target) + async def has_hidden_attr(self) -> bool: + hidden: str | None = await self.get_attr("hidden", mode="dynamic") + aria_hidden: str | None = await self.get_attr("aria-hidden", mode="dynamic") + if hidden is not None and hidden.lower() != "false": + return True + if aria_hidden is not None and aria_hidden.lower() != "false": + return True + return False + def get_element_dict(self) -> dict: return self.__static_element