diff --git a/skyvern/exceptions.py b/skyvern/exceptions.py
index 1f944267..a120b543 100644
--- a/skyvern/exceptions.py
+++ b/skyvern/exceptions.py
@@ -297,3 +297,10 @@ class MissingElementDict(SkyvernException):
class MissingElementInIframe(SkyvernException):
def __init__(self, element_id: str) -> None:
super().__init__(f"Found no iframe includes the element. element_id={element_id}")
+
+
+class InputActionOnSelect2Dropdown(SkyvernException):
+ def __init__(self, element_id: str):
+ super().__init__(
+ f"Input action on a select element, please try to use select action on this element. element_id={element_id}"
+ )
diff --git a/skyvern/webeye/actions/handler.py b/skyvern/webeye/actions/handler.py
index 1881e0e3..ba782503 100644
--- a/skyvern/webeye/actions/handler.py
+++ b/skyvern/webeye/actions/handler.py
@@ -11,6 +11,7 @@ from playwright.async_api import Locator, Page, TimeoutError
from skyvern.constants import INPUT_TEXT_TIMEOUT, REPO_ROOT_DIR
from skyvern.exceptions import (
ImaginaryFileUrl,
+ InputActionOnSelect2Dropdown,
InvalidElementForTextInput,
MissingElement,
MissingFileUrl,
@@ -41,7 +42,7 @@ from skyvern.webeye.actions.actions import (
from skyvern.webeye.actions.responses import ActionFailure, ActionResult, ActionSuccess
from skyvern.webeye.browser_factory import BrowserState
from skyvern.webeye.scraper.scraper import ScrapedPage
-from skyvern.webeye.utils.dom import resolve_locator
+from skyvern.webeye.utils.dom import DomUtil, InteractiveElement, Select2Dropdown, resolve_locator
LOG = structlog.get_logger()
TEXT_INPUT_DELAY = 10 # 10ms between each character input
@@ -241,6 +242,11 @@ async def handle_input_text_action(
task: Task,
step: Step,
) -> list[ActionResult]:
+ dom = DomUtil(scraped_page, page)
+ skyvern_element = await dom.get_skyvern_element_by_id(action.element_id)
+ if await skyvern_element.is_select2_dropdown():
+ return [ActionFailure(InputActionOnSelect2Dropdown(element_id=action.element_id))]
+
xpath, frame = await validate_actions_in_dom(action, page, scraped_page)
locator = resolve_locator(scraped_page, page, frame, xpath)
@@ -392,6 +398,9 @@ async def handle_select_option_action(
task: Task,
step: Step,
) -> list[ActionResult]:
+ dom = DomUtil(scraped_page, page)
+ skyvern_element = await dom.get_skyvern_element_by_id(action.element_id)
+
xpath, frame = await validate_actions_in_dom(action, page, scraped_page)
locator = resolve_locator(scraped_page, page, frame, xpath)
@@ -428,17 +437,23 @@ async def handle_select_option_action(
# check if the element is an a tag first. If yes, click it instead of selecting the option
if tag_name == "label":
- # TODO: this is a hack to handle the case where the label is the only thing that's clickable
- # it's a label, look for the anchor tag
- child_anchor_xpath = get_anchor_to_click(scraped_page, action.element_id)
- if child_anchor_xpath:
- LOG.info(
- "SelectOptionAction is a label tag. Clicking the anchor tag instead of selecting the option",
- action=action,
- child_anchor_xpath=child_anchor_xpath,
- )
- click_action = ClickAction(element_id=action.element_id)
- return await chain_click(task, scraped_page, page, click_action, child_anchor_xpath, frame)
+ # label pointed to select2 element
+ select2_element_id: str | None = None
+ # search anchor first and then search anchor
+ select2_element_id = skyvern_element.find_element_id_in_label_children(InteractiveElement.A)
+ if select2_element_id is None:
+ select2_element_id = skyvern_element.find_element_id_in_label_children(InteractiveElement.INPUT)
+
+ if select2_element_id is not None:
+ select2_skyvern_element = await dom.get_skyvern_element_by_id(element_id=select2_element_id)
+ if await select2_skyvern_element.is_select2_dropdown():
+ LOG.info(
+ "SelectOptionAction is on