77from selenium .webdriver .common .actions .action_builder import ActionBuilder
88from selenium .webdriver .common .actions .pointer_input import PointerInput
99from selenium .webdriver .remote .webelement import WebElement
10- from selenium .webdriver .support import expected_conditions as EC
10+ from selenium .webdriver .support import expected_conditions as ec
1111from selenium .webdriver .support .wait import WebDriverWait
1212from selenium .common .exceptions import TimeoutException , NoSuchElementException
1313
1414Locator = Tuple [str , str ]
15+ type Condition = Literal ["clickable" , "visible" , "present" ]
1516
1617
1718class WaitType (Enum ):
@@ -34,19 +35,20 @@ def __init__(self, driver):
3435 )
3536
3637 def _get_waiter (self , wait_type : Optional [WaitType ] = None ) -> WebDriverWait :
38+ """Returns the appropriate waiter based on the given wait_type."""
3739 return self .waiters .get (wait_type , self .waiters [WaitType .DEFAULT ])
3840
3941 def wait_for (
4042 self ,
4143 locator : Locator ,
42- condition : Literal [ "clickable" , "visible" , "present" ] = "visible" ,
44+ condition : Condition = "visible" ,
4345 waiter : Optional [WebDriverWait ] = None ,
4446 ) -> WebElement :
4547 waiter = waiter or self ._get_waiter ()
4648 conditions = {
47- "clickable" : EC .element_to_be_clickable (locator ),
48- "visible" : EC .visibility_of_element_located (locator ),
49- "present" : EC .presence_of_element_located (locator ),
49+ "clickable" : ec .element_to_be_clickable (locator ),
50+ "visible" : ec .visibility_of_element_located (locator ),
51+ "present" : ec .presence_of_element_located (locator ),
5052 }
5153 if condition not in conditions :
5254 raise ValueError (f"Unknown condition: { condition } " )
@@ -61,7 +63,7 @@ def element(
6163 self ,
6264 locator : Locator ,
6365 n : int = 3 ,
64- condition : Literal [ "clickable" , "visible" , "present" ] = "visible" ,
66+ condition : Condition = "visible" ,
6567 wait_type : Optional [WaitType ] = WaitType .DEFAULT ,
6668 ):
6769 for attempt in range (1 , n + 1 ):
@@ -80,7 +82,7 @@ def elements(
8082 self ,
8183 locator : Locator ,
8284 n : int = 3 ,
83- condition : Literal [ "clickable" , "visible" , "present" ] = "visible" ,
85+ condition : Condition = "visible" ,
8486 wait_type : Optional [WaitType ] = WaitType .DEFAULT ,
8587 ) -> List [WebElement ]:
8688 for attempt in range (1 , n + 1 ):
@@ -100,7 +102,7 @@ def is_displayed(
100102 locator : Locator ,
101103 expected : bool = True ,
102104 n : int = 3 ,
103- condition : Literal [ "clickable" , "visible" , "present" ] = "visible" ,
105+ condition : Condition = "visible" ,
104106 wait_type : Optional [WaitType ] = None ,
105107 ) -> None :
106108 wait_type = wait_type or WaitType .DEFAULT
@@ -125,30 +127,55 @@ def is_exist(
125127 locator : Locator ,
126128 expected : bool = True ,
127129 n : int = 3 ,
128- condition : Literal ["clickable" , "visible" , "present" ] = "visible" ,
129- wait_type : Optional [WaitType ] = WaitType .DEFAULT ,
130+ condition : Condition = "visible" ,
131+ wait_type : Optional [WaitType ] = WaitType .SHORT ,
132+ retry_delay : float = 0.5 ,
130133 ) -> bool :
134+ """
135+ Checks if an element exists on the screen within a specified number of retries.
136+
137+ :param retry_delay: delay between retry
138+ :param locator: The locator tuple (strategy, value) used to find the element.
139+ :param expected: Determines whether the element should exist (True) or not (False).
140+ :param n: The number of attempts to check for the element before returning a result.
141+ :param condition: The condition to check for the element's existence.
142+ - "clickable": Ensures the element is interactable.
143+ - "visible": Ensures the element is visible on the page.
144+ - "present": Ensures the element exists in the DOM (even if not visible).
145+ :param wait_type: Specifies the wait strategy (default is WaitType.DEFAULT).
146+ :return: True if the element matches the expected state, False otherwise.
147+ :rtype: bool
148+
149+
150+ **Usage Example:**
151+
152+ screen.is_exist(("id", "login-button"))
153+ True
154+
155+ screen.is_exist(("id", "error-popup"), expected=False)
156+ True
157+ """
131158 for _ in range (n ):
132159 try :
133160 element = self .element (
134161 locator , n = 1 , condition = condition , wait_type = wait_type
135162 )
136163 return element .is_displayed () == expected
137- except NoSuchElementException :
164+ except ( NoSuchElementException , TimeoutException ) :
138165 if not expected :
139166 return True
140- except Exception :
141- pass
142- time .sleep (0.5 )
167+ except Exception as e :
168+ print ( f"Unexpected error in is_exist: { e } " )
169+ time .sleep (retry_delay )
143170 return not expected
144-
171+
145172 def scroll_by_coordinates (
146- self ,
147- start_x : int ,
148- start_y : int ,
149- end_x : int ,
150- end_y : int ,
151- duration : Optional [int ] = None ,
173+ self ,
174+ start_x : int ,
175+ start_y : int ,
176+ end_x : int ,
177+ end_y : int ,
178+ duration : Optional [int ] = None ,
152179 ):
153180 """Scrolls from one set of coordinates to another.
154181
@@ -161,17 +188,18 @@ def scroll_by_coordinates(
161188 """
162189 if duration is None :
163190 duration = 700
164-
191+
165192 touch_input = PointerInput (interaction .POINTER_TOUCH , "touch" )
166193 actions = ActionChains (self .driver )
167-
168- actions .w3c_actions = ActionBuilder (self .driver , mouse = touch_input )
194+
195+ actions .w3c_actions = ActionBuilder (self .driver , mouse = touch_input )
169196 actions .w3c_actions .pointer_action .move_to_location (start_x , start_y )
170197 actions .w3c_actions .pointer_action .pointer_down ()
171- actions .w3c_actions = ActionBuilder (self .driver , mouse = touch_input , duration = duration )
172-
198+ actions .w3c_actions = ActionBuilder (
199+ self .driver , mouse = touch_input , duration = duration
200+ )
201+
173202 actions .w3c_actions .pointer_action .move_to_location (end_x , end_y )
174203 actions .w3c_actions .pointer_action .release ()
175-
204+
176205 actions .perform ()
177-
0 commit comments