1
+ import traceback
2
+ from selenium .common .exceptions import NoSuchElementException , WebDriverException , TimeoutException
3
+ from PIL import ImageChops , Image
4
+
5
+ #############################################################
6
+ ###### Find Elements
7
+ #############################################################
8
+
9
+ def find_elements (driver , id_ ):
10
+ '''
11
+ Only supports id, xpath, class_name and android_uiautomator
12
+ @params:
13
+ driver: a webdriver object
14
+ id_: can be any of the id, xpath, class_name and android_uiautomator
15
+ @returns:
16
+ a list of found elements
17
+ '''
18
+ # __handle_system_dialogs(driver)
19
+ if ':id/' in id_ :
20
+ return driver .find_elements_by_id (id_ )
21
+ elif id_ .startswith ('android.widget' ):
22
+ return driver .find_elements_by_class_name (id_ )
23
+ elif id_ .startswith ('new ' ):
24
+ return driver .find_elements_by_android_uiautomator (id_ )
25
+ else : # elif id_.startswith('//android.widget') or id_.startswith('//*[contains'):
26
+ return driver .find_elements_by_xpath (id_ )
27
+
28
+ def find_element (driver , id_ : str , index : int = 0 ):
29
+ '''
30
+ This function calls find_elements and returns the indexed element from it.
31
+ @params:
32
+ driver: a webdriver object
33
+ id_ (str): can be any of the id, xpath, class_name and android_uiautomator
34
+ index (int): the index of element found, default is 0
35
+ @returns:
36
+ the indexed element if found, otherwise False
37
+ '''
38
+ elements = find_elements (driver , id_ )
39
+ return elements [index ] if elements else False
40
+
41
+ def find_and_do (driver , id_ : str , operation , index : int = 0 ):
42
+ '''
43
+ Find the indexed element and do an operation on it.
44
+ @returns:
45
+ True if element is found otherwise False
46
+ '''
47
+ try :
48
+ elements = find_elements (driver , id_ )
49
+ if elements :
50
+ operation (elements [index ])
51
+ return True
52
+ return False
53
+ except :
54
+ return False
55
+
56
+ def click (driver , id_ : str , index : int = 0 ):
57
+ '''Find the indexed element and click it.'''
58
+ return find_and_do (driver , id_ , lambda x : x .click (), index )
59
+
60
+ def set_text (driver , id_ : str , text : str , index : int = 0 ):
61
+ '''Find the indexed element and set its text.'''
62
+ return find_and_do (driver , id_ , lambda x : x .set_text (text ), index )
63
+
64
+ def get_text (driver , id_ : str , index : int = 0 ):
65
+ '''
66
+ Find the indexed element and return its text. If not found, return ''.
67
+ '''
68
+ element = find_element (driver , id_ , index )
69
+ return element .text if element else ''
70
+
71
+ def get_attribute (driver , id_ : str , attribute : str , index : int = 0 ):
72
+ '''Find the indexed element and get its attribute.'''
73
+ element = find_element (driver , id_ , index )
74
+ return element .get_attribute (attribute ) if element else None
75
+
76
+ def is_selected (driver , id_ : str , index : int = 0 ):
77
+ '''Find if the indexed element has the attribute 'selected' equal to true.'''
78
+ return get_attribute (driver , id_ , 'selected' , index ) == 'true'
79
+
80
+ def is_checked (driver , id_ : str , index : int = 0 ):
81
+ '''Find if the indexed element has the attribute 'checked' equal to true.'''
82
+ return get_attribute (driver , id_ , 'checked' , index ) == 'true'
83
+
84
+ #############################################################
85
+ ###### SWIPE
86
+ #############################################################
87
+
88
+ def __swipe (driver , fromX , fromY , toX , toY , duration ) -> bool :
89
+ size = driver .get_window_size ()
90
+ width = size ['width' ]
91
+ height = size ['height' ]
92
+ try :
93
+ driver .swipe (width * fromX , height * fromY , width * toX , height * toY , 500 )
94
+ return True
95
+ except (NoSuchElementException , TimeoutException , WebDriverException ):
96
+ print (traceback .format_exc ())
97
+ return False
98
+
99
+ def swipe (driver , start_x_ratio , start_y_ratio , end_x_ratio , end_y_ratio , duration = 500 ):
100
+ '''
101
+ Swipe from (start_x_ratio * window_width, start_y_ratio * window * height) to (end_x_ratio * window_width, end_y_ratio * height)
102
+ @params:
103
+ driver: a webdriver object
104
+ start_x_ratio, start_y_ratio, end_x_ratio, end_y_ratio: Swipe from (start_x_ratio * window_width, start_y_ratio * window * height)
105
+ to (end_x_ratio * window_width, end_y_ratio * height)
106
+ duration: swipe time in milliseconds
107
+ @returns:
108
+ returns True if swipeable otherwise False
109
+ @raises:
110
+ AssertionException if start_x_ratio, start_y_ratio, end_x_ratio, end_y_ratio don't fall in range [0, 1]
111
+ '''
112
+ assert 0 <= start_x_ratio <= 1 and 0 <= start_y_ratio <= 1 and 0 <= end_x_ratio <= 1 and 0 <= end_y_ratio <= 1 , "Ratio doesn't fall in range [0, 1]"
113
+ return __swipe (driver , start_x_ratio , start_y_ratio , end_x_ratio , end_y_ratio , duration )
114
+
115
+ def swipe_left (driver , x_ratio = 7 / 8 , y_ratio = 1 / 2 ) -> bool :
116
+ '''
117
+ @params:
118
+ driver: a webdriver object
119
+ x_ratio, y_ratio: swipe from (x_ratio * window_width, y_ratio * window_height)
120
+ to ((1 - x_ratio) * window_width, y_ratio * window_height)
121
+ @returns:
122
+ returns True if swipeable otherwise False
123
+ @raises:
124
+ AssertionException if x_ratio doesn't fall in range (1/2, 1], y_ratio doesn't fall in range [0, 1]
125
+ '''
126
+ assert 1 / 2 < x_ratio <= 1 , f"x_ratio ({ x_ratio } ) doesn't fall in range (1/2, 1]"
127
+ assert 0 <= y_ratio <= 1 , f"y_ratio ({ y_ratio } ) doesn't fall in range [0, 1]"
128
+ return swipe (driver , x_ratio , y_ratio , 1 - x_ratio , y_ratio )
129
+
130
+ def swipe_right (driver , x_ratio = 1 / 8 , y_ratio = 1 / 2 ) -> bool :
131
+ '''
132
+ @params:
133
+ driver: a webdriver object
134
+ x_ratio, y_ratio: swipe from (x_ratio * window_width, y_ratio * window_height)
135
+ to ((1 - x_ratio) * window_width, y_ratio * window_height)
136
+ @returns:
137
+ returns True if swipeable otherwise False
138
+ @raises:
139
+ AssertionException if x_ratio doesn't fall in range [0, 1/2), y_ratio doesn't fall in range [0, 1]
140
+ '''
141
+ assert 0 <= x_ratio < 1 / 2 , f"x_ratio ({ x_ratio } ) doesn't fall in range [0, 1/2)"
142
+ assert 0 <= y_ratio <= 1 , f"y_ratio ({ y_ratio } ) doesn't fall in range [0, 1]"
143
+ return swipe (driver , x_ratio , y_ratio , 1 - x_ratio , y_ratio )
144
+
145
+ def swipe_up (driver , x_ratio = 1 / 2 , y_ratio = 3 / 5 ) -> bool :
146
+ '''
147
+ @params:
148
+ driver: a webdriver object
149
+ x_ratio, y_ratio: swipe from (x_ratio * window_width, y_ratio * window_height)
150
+ to (x_ratio * window_width, (1 - y_ratio) * window_height).
151
+ @returns:
152
+ returns True if swipeable otherwise False
153
+ @raises:
154
+ AssertionException if x_ratio doesn't fall in range [0, 1], y_ratio doesn't fall in range (1/2, 1]
155
+ '''
156
+ assert 0 <= x_ratio <= 1 , f"x_ratio ({ x_ratio } ) doesn't fall in range [0, 1]"
157
+ assert 1 / 2 < y_ratio <= 1 , f"y_ratio ({ y_ratio } ) doesn't fall in range (1/2, 1]"
158
+ return swipe (driver , x_ratio , y_ratio , x_ratio , 1 - y_ratio )
159
+
160
+ def swipe_down (driver , x_ratio = 1 / 2 , y_ratio = 2 / 5 ) -> bool :
161
+ '''
162
+ @params:
163
+ driver: a webdriver object
164
+ x_ratio, y_ratio: swipe from (x_ratio * window_width, y_ratio * window_height)
165
+ to (x_ratio * window_width, (1 - y_ratio) * window_height).
166
+ @returns:
167
+ returns True if swipeable otherwise False
168
+ @raises:
169
+ AssertionException if x_ratio doesn't fall in range [0, 1], y_ratio doesn't fall in range [0, 1/2)
170
+ '''
171
+ assert 0 <= x_ratio <= 1 , f"x_ratio ({ x_ratio } ) doesn't fall in range [0, 1]"
172
+ assert 0 <= y_ratio < 1 / 2 , f"y_ratio ({ y_ratio } ) doesn't fall in range [0, 1/2)"
173
+ return swipe (driver , x_ratio , y_ratio , x_ratio , 1 - y_ratio )
174
+
175
+ def compare_images (image1 : str , image2 : str ) -> bool :
176
+ '''
177
+ @params:
178
+ image1 (str): The path of image1.
179
+ image2 (str): The path of image2.
180
+ @returns:
181
+ True if two images are identical otherwise False.
182
+ '''
183
+ return ImageChops .difference (Image .open (image1 ), Image .open (image2 )).getbbox () is None
0 commit comments