77import sys , time , re
88import inspect
99import traceback
10+ from typing import Literal
1011from pathlib import Path
1112from Framework .Utilities import CommonUtil
1213from Framework .Utilities .CommonUtil import passed_tag_list , failed_tag_list
2627global driver_type
2728driver_type = None
2829
29-
3030MODULE_NAME = inspect .getmodulename (__file__ )
3131
32+ def build_css_selector_query (dataset :list [list [str ]]) -> str :
33+ """ Builds css selector query from dataset """
34+ try :
35+ sModuleInfo = inspect .currentframe ().f_code .co_name + " : " + MODULE_NAME
36+ query = ""
37+ element_parameter_list = []
38+ parent_parameter_list = []
39+ for left , mid , right in dataset :
40+ mid_ = mid .replace (" " , "" ).lower ()
41+ if "elementparameter" == mid_ :
42+ element_parameter_list .append ((left , right ))
43+ if left == "css selector" :
44+ return right
45+ elif "parent" in mid_ and "parameter" in mid_ :
46+ parent_parameter_list .append ([left , right ])
47+ elif "sibling" in mid_ and "parameter" in mid_ :
48+ CommonUtil .ExecLog (sModuleInfo , "Sibling parameter is not supported in css selector" , 2 )
49+ elif "child" in mid_ and "parameter" in mid_ :
50+ CommonUtil .ExecLog (sModuleInfo , "Child parameter is not supported in css selector" , 2 )
51+ elif "preceding" in mid_ and "parameter" in mid_ :
52+ CommonUtil .ExecLog (sModuleInfo , "Preceding parameter is not supported in css selector" , 2 )
53+ elif "following" in mid_ and "parameter" in mid_ :
54+ CommonUtil .ExecLog (sModuleInfo , "Following parameter is not supported in css selector" , 2 )
55+
56+ for left , right in parent_parameter_list :
57+ if left == "tag" :
58+ query = right + query
59+ break
60+ else :
61+ if len (parent_parameter_list ) > 0 :
62+ query = "*" + query
63+
64+ for left , right in parent_parameter_list :
65+ if left == "tag" :
66+ pass
67+ elif left == "text" :
68+ CommonUtil .ExecLog (sModuleInfo , "Text parameter is not supported in css selector" , 2 )
69+ elif left == "xpath" :
70+ CommonUtil .ExecLog (sModuleInfo , "xpath parameter is not supported in css selector" , 2 )
71+ elif left != "index" :
72+ quote = "'" if '"' in right else '"'
73+ query += f"[{ left } ={ quote } { right } { quote } ]"
74+
75+ if len (parent_parameter_list ) > 0 :
76+ query += " "
77+
78+ for left , right in element_parameter_list :
79+ if left == "tag" :
80+ query += right
81+ break
82+ else :
83+ query += "*"
84+
85+ for left , right in element_parameter_list :
86+ if left == "tag" :
87+ pass
88+ elif left == "text" :
89+ CommonUtil .ExecLog (sModuleInfo , "Text parameter is not supported in css selector" , 2 )
90+ elif left == "xpath" :
91+ CommonUtil .ExecLog (sModuleInfo , "xpath parameter is not supported in css selector" , 2 )
92+ elif left != "index" :
93+ quote = "'" if '"' in right else '"'
94+ query += f"[{ left } ={ quote } { right } { quote } ]"
3295
33- def Get_Element (step_data_set , driver , query_debug = False , return_all_elements = False , element_wait = None ):
96+ return query
97+
98+ except :
99+ CommonUtil .Exception_Handler (sys .exc_info ())
100+ return ""
101+
102+ get_element_return_type = list [selenium .webdriver .remote .webelement .WebElement ] | Literal ["zeuz_failed" ] | selenium .webdriver .remote .webelement .WebElement
103+ def shadow_root_elements (shadow_root_ds : list [list [str ]], element_ds : list [list [str ]], Filter : str , element_wait : float , return_all_elements : bool ) -> get_element_return_type :
104+ """ Finds the shadow root container and the element inside there, both in css-selector method"""
105+ try :
106+ sModuleInfo = inspect .currentframe ().f_code .co_name + " : " + MODULE_NAME
107+ child_shadow_root_ds = []
108+ for left , mid , right in shadow_root_ds :
109+ mid = mid .strip ().lower ()
110+ if mid .startswith ("sr" ):
111+ child_shadow_root_ds .append ((left , mid , right ))
112+ if len (child_shadow_root_ds ) > 0 :
113+ # handle nested roots later
114+ CommonUtil .ExecLog (sModuleInfo , "Nested shadow root is not supported yet" , 2 )
115+ return "zeuz_failed"
116+ else :
117+ element_query = build_css_selector_query (shadow_root_ds )
118+ index = _locate_index_number (shadow_root_ds )
119+ index = 0 if index is None else index
120+ elements = generic_driver .find_elements (By .CSS_SELECTOR , element_query )
121+ filtered_elements = filter_elements (elements , Filter )
122+ shadow_container_element = filtered_elements [index ]
123+ shadow_root_element = generic_driver .execute_script ('return arguments[0].shadowRoot' , shadow_container_element )
124+
125+ element_query = build_css_selector_query (element_ds )
126+ index = _locate_index_number (element_ds )
127+ index = 0 if index is None else index
128+ elements = shadow_root_element .find_elements (By .CSS_SELECTOR , element_query )
129+ filtered_elements = filter_elements (elements , Filter )
130+ if return_all_elements :
131+ return filtered_elements
132+ elif len (filtered_elements ) == 0 :
133+ return []
134+ else :
135+ return filtered_elements [index ]
136+ except :
137+ return CommonUtil .Exception_Handler (sys .exc_info ())
138+
139+
140+ def Get_Element (step_data_set , driver , query_debug = False , return_all_elements = False , element_wait = None ) -> get_element_return_type :
34141 """
35- This funciton will return "zeuz_failed" if something went wrong, else it will always return a single element
142+ This function will return "zeuz_failed" if something went wrong, else it will always return a single element
36143 if you are trying to produce a query from a step dataset, make sure you provide query_debug =True. This is
37144 good when you are just trying to see how your step data would be converted to a query for testing local runs
38145 """
@@ -62,19 +169,8 @@ def Get_Element(step_data_set, driver, query_debug=False, return_all_elements=Fa
62169 # We need to switch to default content just in case previous action switched to something else
63170 try :
64171 if driver_type == "selenium" :
65- pass #generic_driver.switch_to.default_content()
66- # we need to see if there are more than one handles. Since we cannot know if we had switch
67- # windows before, we are going to assume that we can always safely switch to default handle 0
68- """
69- try:
70- all_windows = generic_driver.window_handles
71- generic_driver.switch_to.window(all_windows[0])
72- True
73- except:
74- True
75- """
172+ pass
76173 elif driver_type == "appium" :
77-
78174 # If we find a '|' character in the left column, then try to check the platform
79175 # and filter the appropriate data for the left column by removing '|'
80176 device_platform = (
@@ -128,6 +224,8 @@ def Get_Element(step_data_set, driver, query_debug=False, return_all_elements=Fa
128224 get_parameter = ""
129225 Filter = ""
130226 text_filter_cond = False
227+ shadow_root_ds = []
228+ element_ds = []
131229 for row in step_data_set :
132230 if row [1 ] == "save parameter" :
133231 if row [2 ] != "ignore" :
@@ -147,7 +245,13 @@ def Get_Element(step_data_set, driver, query_debug=False, return_all_elements=Fa
147245 element_wait = float (right )
148246 elif left == "text filter" :
149247 text_filter_cond = right in ("yes" , "true" , "ok" , "enable" )
248+ elif row [1 ].strip ().lower ().startswith ("sr" ):
249+ shadow_root_ds .append ([row [0 ], row [1 ][2 :].strip (), row [2 ]])
250+ else :
251+ element_ds .append ([row [0 ], row [1 ], row [2 ]])
150252
253+ if len (shadow_root_ds ) > 0 :
254+ return shadow_root_elements (shadow_root_ds , element_ds , Filter , element_wait , return_all_elements )
151255
152256 if get_parameter != "" :
153257
@@ -238,9 +342,9 @@ def text_filter(step_data_set, Filter, element_wait, return_all_elements):
238342 """
239343 suppose dom has <div>Hello World</div>
240344 the text will be converted to "<something unknown>Hello world<something unknown>"
241- Thats why (text, element parameter, Hello world) does not work
345+ That's why (text, element parameter, Hello world) does not work
242346 But (*text, element parameter, Hello world) works!
243- So for now we don't need this python script for now as we have an existing solution
347+ So for now we don't need this python script as we have an existing solution
244348 """
245349 try :
246350 sModuleInfo = inspect .currentframe ().f_code .co_name + " : " + MODULE_NAME
@@ -1084,7 +1188,8 @@ def filter_elements(all_matching_elements_visible_invisible, Filter):
10841188 return all_matching_elements
10851189 else :
10861190 return all_matching_elements_visible_invisible
1087- except :
1191+ except Exception as e :
1192+ CommonUtil .Exception_Handler (sys .exc_info ())
10881193 all_matching_elements = []
10891194 return all_matching_elements
10901195
0 commit comments