How to use convert_to_css_selector method in SeleniumBase

Best Python code snippet using SeleniumBase

base_case.py

Source:base_case.py Github

copy

Full Screen

...765 attribute = re.escape(attribute)766 attribute = self.__escape_quotes_if_needed(attribute)767 value = re.escape(value)768 value = self.__escape_quotes_if_needed(value)769 css_selector = self.convert_to_css_selector(selector, by=by)770 css_selector = re.escape(css_selector)771 css_selector = self.__escape_quotes_if_needed(css_selector)772 script = ("""document.querySelector('%s').setAttribute('%s','%s');"""773 % (css_selector, attribute, value))774 self.execute_script(script)775 def set_attributes(self, selector, attribute, value, by=By.CSS_SELECTOR):776 """ This method uses JavaScript to set/update a common attribute.777 All matching selectors from querySelectorAll() are used.778 Example => (Make all links on a website redirect to Google):779 self.set_attributes("a", "href", "https://google.com") """780 selector, by = self.__recalculate_selector(selector, by)781 attribute = re.escape(attribute)782 attribute = self.__escape_quotes_if_needed(attribute)783 value = re.escape(value)784 value = self.__escape_quotes_if_needed(value)785 css_selector = self.convert_to_css_selector(selector, by=by)786 css_selector = re.escape(css_selector)787 css_selector = self.__escape_quotes_if_needed(css_selector)788 script = ("""var $elements = document.querySelectorAll('%s');789 var index = 0, length = $elements.length;790 for(; index < length; index++){791 $elements[index].setAttribute('%s','%s');}"""792 % (css_selector, attribute, value))793 try:794 self.execute_script(script)795 except Exception:796 pass797 def set_attribute_all(self, selector, attribute, value,798 by=By.CSS_SELECTOR):799 """ Same as set_attributes(), but using querySelectorAll naming scheme.800 This method uses JavaScript to set/update a common attribute.801 All matching selectors from querySelectorAll() are used.802 Example => (Make all links on a website redirect to Google):803 self.set_attribute_all("a", "href", "https://google.com") """804 self.set_attributes(selector, attribute, value, by=by)805 def remove_attribute(self, selector, attribute, by=By.CSS_SELECTOR,806 timeout=None):807 """ This method uses JavaScript to remove an attribute.808 Only the first matching selector from querySelector() is used. """809 if not timeout:810 timeout = settings.SMALL_TIMEOUT811 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:812 timeout = self.__get_new_timeout(timeout)813 selector, by = self.__recalculate_selector(selector, by)814 if self.is_element_visible(selector, by=by):815 try:816 self.scroll_to(selector, by=by, timeout=timeout)817 except Exception:818 pass819 attribute = re.escape(attribute)820 attribute = self.__escape_quotes_if_needed(attribute)821 css_selector = self.convert_to_css_selector(selector, by=by)822 css_selector = re.escape(css_selector)823 css_selector = self.__escape_quotes_if_needed(css_selector)824 script = ("""document.querySelector('%s').removeAttribute('%s');"""825 % (css_selector, attribute))826 self.execute_script(script)827 def remove_attributes(self, selector, attribute, by=By.CSS_SELECTOR):828 """ This method uses JavaScript to remove a common attribute.829 All matching selectors from querySelectorAll() are used. """830 selector, by = self.__recalculate_selector(selector, by)831 attribute = re.escape(attribute)832 attribute = self.__escape_quotes_if_needed(attribute)833 css_selector = self.convert_to_css_selector(selector, by=by)834 css_selector = re.escape(css_selector)835 css_selector = self.__escape_quotes_if_needed(css_selector)836 script = ("""var $elements = document.querySelectorAll('%s');837 var index = 0, length = $elements.length;838 for(; index < length; index++){839 $elements[index].removeAttribute('%s');}"""840 % (css_selector, attribute))841 try:842 self.execute_script(script)843 except Exception:844 pass845 def get_property_value(self, selector, property, by=By.CSS_SELECTOR,846 timeout=None):847 """ Returns the property value of a page element's computed style.848 Example:849 opacity = self.get_property_value("html body a", "opacity")850 self.assertTrue(float(opacity) > 0, "Element not visible!") """851 if not timeout:852 timeout = settings.SMALL_TIMEOUT853 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:854 timeout = self.__get_new_timeout(timeout)855 selector, by = self.__recalculate_selector(selector, by)856 self.wait_for_ready_state_complete()857 page_actions.wait_for_element_present(858 self.driver, selector, by, timeout)859 try:860 selector = self.convert_to_css_selector(selector, by=by)861 except Exception:862 # Don't run action if can't convert to CSS_Selector for JavaScript863 raise Exception(864 "Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!" % (865 selector, by))866 selector = re.escape(selector)867 selector = self.__escape_quotes_if_needed(selector)868 script = ("""var $elm = document.querySelector('%s');869 $val = window.getComputedStyle($elm).getPropertyValue('%s');870 return $val;"""871 % (selector, property))872 value = self.execute_script(script)873 if value is not None:874 return value875 else:876 return "" # Return an empty string if the property doesn't exist877 def get_image_url(self, selector, by=By.CSS_SELECTOR, timeout=None):878 """ Extracts the URL from an image element on the page. """879 if not timeout:880 timeout = settings.SMALL_TIMEOUT881 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:882 timeout = self.__get_new_timeout(timeout)883 return self.get_attribute(selector,884 attribute='src', by=by, timeout=timeout)885 def find_elements(self, selector, by=By.CSS_SELECTOR, limit=0):886 """ Returns a list of matching WebElements.887 Elements could be either hidden or visible on the page.888 If "limit" is set and > 0, will only return that many elements. """889 selector, by = self.__recalculate_selector(selector, by)890 self.wait_for_ready_state_complete()891 time.sleep(0.05)892 elements = self.driver.find_elements(by=by, value=selector)893 if limit and limit > 0 and len(elements) > limit:894 elements = elements[:limit]895 return elements896 def find_visible_elements(self, selector, by=By.CSS_SELECTOR, limit=0):897 """ Returns a list of matching WebElements that are visible.898 If "limit" is set and > 0, will only return that many elements. """899 selector, by = self.__recalculate_selector(selector, by)900 self.wait_for_ready_state_complete()901 time.sleep(0.05)902 v_elems = page_actions.find_visible_elements(self.driver, selector, by)903 if limit and limit > 0 and len(v_elems) > limit:904 v_elems = v_elems[:limit]905 return v_elems906 def click_visible_elements(self, selector, by=By.CSS_SELECTOR, limit=0):907 """ Finds all matching page elements and clicks visible ones in order.908 If a click reloads or opens a new page, the clicking will stop.909 If no matching elements appear, an Exception will be raised.910 If "limit" is set and > 0, will only click that many elements.911 Also clicks elements that become visible from previous clicks.912 Works best for actions such as clicking all checkboxes on a page.913 Example: self.click_visible_elements('input[type="checkbox"]') """914 selector, by = self.__recalculate_selector(selector, by)915 self.wait_for_element_present(916 selector, by=by, timeout=settings.SMALL_TIMEOUT)917 elements = self.find_elements(selector, by=by)918 if self.browser == "safari":919 if not limit:920 limit = 0921 num_elements = len(elements)922 if num_elements == 0:923 raise Exception(924 "No matching elements found for selector {%s}!" % selector)925 elif num_elements < limit or limit == 0:926 limit = num_elements927 selector, by = self.__recalculate_selector(selector, by)928 css_selector = self.convert_to_css_selector(selector, by=by)929 last_css_chunk = css_selector.split(' ')[-1]930 if ":" in last_css_chunk:931 self.__js_click_all(css_selector)932 self.wait_for_ready_state_complete()933 return934 else:935 for i in range(1, limit+1):936 new_selector = css_selector + ":nth-of-type(%s)" % str(i)937 if self.is_element_visible(new_selector):938 self.__js_click(new_selector)939 self.wait_for_ready_state_complete()940 return941 click_count = 0942 for element in elements:943 if limit and limit > 0 and click_count >= limit:944 return945 try:946 if element.is_displayed():947 self.__scroll_to_element(element)948 element.click()949 click_count += 1950 self.wait_for_ready_state_complete()951 except ECI_Exception:952 continue # ElementClickInterceptedException (Overlay likely)953 except (StaleElementReferenceException, ENI_Exception):954 self.wait_for_ready_state_complete()955 time.sleep(0.03)956 try:957 if element.is_displayed():958 self.__scroll_to_element(element)959 element.click()960 click_count += 1961 self.wait_for_ready_state_complete()962 except (StaleElementReferenceException, ENI_Exception):963 return # Probably on new page / Elements are all stale964 def click_nth_visible_element(self, selector, number, by=By.CSS_SELECTOR):965 """ Finds all matching page elements and clicks the nth visible one.966 Example: self.click_nth_visible_element('[type="checkbox"]', 5)967 (Clicks the 5th visible checkbox on the page.) """968 elements = self.find_visible_elements(selector, by=by)969 if len(elements) < number:970 raise Exception("Not enough matching {%s} elements of type {%s} to"971 " click number %s!" % (selector, by, number))972 number = number - 1973 if number < 0:974 number = 0975 element = elements[number]976 self.wait_for_ready_state_complete()977 try:978 self.__scroll_to_element(element)979 element.click()980 except (StaleElementReferenceException, ENI_Exception):981 self.wait_for_ready_state_complete()982 time.sleep(0.05)983 self.__scroll_to_element(element)984 element.click()985 def click_if_visible(self, selector, by=By.CSS_SELECTOR):986 """ If the page selector exists and is visible, clicks on the element.987 This method only clicks on the first matching element found.988 (Use click_visible_elements() to click all matching elements.) """989 self.wait_for_ready_state_complete()990 if self.is_element_visible(selector, by=by):991 self.click(selector, by=by)992 def is_checked(self, selector, by=By.CSS_SELECTOR, timeout=None):993 """ Determines if a checkbox or a radio button element is checked.994 Returns True if the element is checked.995 Returns False if the element is not checked.996 If the element is not present on the page, raises an exception.997 If the element is not a checkbox or radio, raises an exception. """998 if not timeout:999 timeout = settings.SMALL_TIMEOUT1000 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1001 timeout = self.__get_new_timeout(timeout)1002 selector, by = self.__recalculate_selector(selector, by)1003 kind = self.get_attribute(selector, "type", by=by, timeout=timeout)1004 if kind != "checkbox" and kind != "radio":1005 raise Exception("Expecting a checkbox or a radio button element!")1006 is_checked = self.get_attribute(1007 selector, "checked", by=by, timeout=timeout, hard_fail=False)1008 if is_checked:1009 return True1010 else: # (NoneType)1011 return False1012 def is_selected(self, selector, by=By.CSS_SELECTOR, timeout=None):1013 """ Same as is_checked() """1014 return self.is_checked(selector, by=by, timeout=timeout)1015 def check_if_unchecked(self, selector, by=By.CSS_SELECTOR):1016 """ If a checkbox or radio button is not checked, will check it. """1017 selector, by = self.__recalculate_selector(selector, by)1018 if not self.is_checked(selector, by=by):1019 if self.is_element_visible(selector, by=by):1020 self.click(selector, by=by)1021 else:1022 selector = self.convert_to_css_selector(selector, by=by)1023 self.js_click(selector, by=By.CSS_SELECTOR)1024 def select_if_unselected(self, selector, by=By.CSS_SELECTOR):1025 """ Same as check_if_unchecked() """1026 self.check_if_unchecked(selector, by=by)1027 def uncheck_if_checked(self, selector, by=By.CSS_SELECTOR):1028 """ If a checkbox is checked, will uncheck it. """1029 selector, by = self.__recalculate_selector(selector, by)1030 if self.is_checked(selector, by=by):1031 if self.is_element_visible(selector, by=by):1032 self.click(selector, by=by)1033 else:1034 selector = self.convert_to_css_selector(selector, by=by)1035 self.js_click(selector, by=By.CSS_SELECTOR)1036 def unselect_if_selected(self, selector, by=By.CSS_SELECTOR):1037 """ Same as uncheck_if_checked() """1038 self.uncheck_if_checked(selector, by=by)1039 def is_element_in_an_iframe(self, selector, by=By.CSS_SELECTOR):1040 """ Returns True if the selector's element is located in an iframe.1041 Otherwise returns False. """1042 selector, by = self.__recalculate_selector(selector, by)1043 if self.is_element_present(selector, by=by):1044 return False1045 soup = self.get_beautiful_soup()1046 iframe_list = soup.select('iframe')1047 for iframe in iframe_list:1048 iframe_identifier = None1049 if iframe.has_attr('name') and len(iframe['name']) > 0:1050 iframe_identifier = iframe['name']1051 elif iframe.has_attr('id') and len(iframe['id']) > 0:1052 iframe_identifier = iframe['id']1053 elif iframe.has_attr('class') and len(iframe['class']) > 0:1054 iframe_class = " ".join(iframe["class"])1055 iframe_identifier = '[class="%s"]' % iframe_class1056 else:1057 continue1058 self.switch_to_frame(iframe_identifier)1059 if self.is_element_present(selector, by=by):1060 self.switch_to_default_content()1061 return True1062 self.switch_to_default_content()1063 return False1064 def switch_to_frame_of_element(self, selector, by=By.CSS_SELECTOR):1065 """ Set driver control to the iframe containing element (assuming the1066 element is in a single-nested iframe) and returns the iframe name.1067 If element is not in an iframe, returns None, and nothing happens.1068 May not work if multiple iframes are nested within each other. """1069 selector, by = self.__recalculate_selector(selector, by)1070 if self.is_element_present(selector, by=by):1071 return None1072 soup = self.get_beautiful_soup()1073 iframe_list = soup.select('iframe')1074 for iframe in iframe_list:1075 iframe_identifier = None1076 if iframe.has_attr('name') and len(iframe['name']) > 0:1077 iframe_identifier = iframe['name']1078 elif iframe.has_attr('id') and len(iframe['id']) > 0:1079 iframe_identifier = iframe['id']1080 elif iframe.has_attr('class') and len(iframe['class']) > 0:1081 iframe_class = " ".join(iframe["class"])1082 iframe_identifier = '[class="%s"]' % iframe_class1083 else:1084 continue1085 try:1086 self.switch_to_frame(iframe_identifier, timeout=1)1087 if self.is_element_present(selector, by=by):1088 return iframe_identifier1089 except Exception:1090 pass1091 self.switch_to_default_content()1092 try:1093 self.switch_to_frame(selector, timeout=1)1094 return selector1095 except Exception:1096 if self.is_element_present(selector, by=by):1097 return ""1098 raise Exception("Could not switch to iframe containing "1099 "element {%s}!" % selector)1100 def hover_on_element(self, selector, by=By.CSS_SELECTOR):1101 selector, by = self.__recalculate_selector(selector, by)1102 if page_utils.is_xpath_selector(selector):1103 selector = self.convert_to_css_selector(selector, By.XPATH)1104 by = By.CSS_SELECTOR1105 self.wait_for_element_visible(1106 selector, by=by, timeout=settings.SMALL_TIMEOUT)1107 self.__demo_mode_highlight_if_active(selector, by)1108 self.scroll_to(selector, by=by)1109 time.sleep(0.05) # Settle down from scrolling before hovering1110 return page_actions.hover_on_element(self.driver, selector)1111 def hover_and_click(self, hover_selector, click_selector,1112 hover_by=By.CSS_SELECTOR, click_by=By.CSS_SELECTOR,1113 timeout=None):1114 """ When you want to hover over an element or dropdown menu,1115 and then click an element that appears after that. """1116 if not timeout:1117 timeout = settings.SMALL_TIMEOUT1118 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1119 timeout = self.__get_new_timeout(timeout)1120 hover_selector, hover_by = self.__recalculate_selector(1121 hover_selector, hover_by)1122 hover_selector = self.convert_to_css_selector(1123 hover_selector, hover_by)1124 hover_by = By.CSS_SELECTOR1125 click_selector, click_by = self.__recalculate_selector(1126 click_selector, click_by)1127 dropdown_element = self.wait_for_element_visible(1128 hover_selector, by=hover_by, timeout=timeout)1129 self.__demo_mode_highlight_if_active(hover_selector, hover_by)1130 self.scroll_to(hover_selector, by=hover_by)1131 pre_action_url = self.driver.current_url1132 outdated_driver = False1133 element = None1134 try:1135 if self.mobile_emulator:1136 # On mobile, click to hover the element1137 dropdown_element.click()1138 elif self.browser == "safari":1139 # Use the workaround for hover-clicking on Safari1140 raise Exception("This Exception will be caught.")1141 else:1142 page_actions.hover_element(self.driver, dropdown_element)1143 except Exception:1144 outdated_driver = True1145 element = self.wait_for_element_present(1146 click_selector, click_by, timeout)1147 if click_by == By.LINK_TEXT:1148 self.open(self.__get_href_from_link_text(click_selector))1149 elif click_by == By.PARTIAL_LINK_TEXT:1150 self.open(self.__get_href_from_partial_link_text(1151 click_selector))1152 else:1153 self.js_click(click_selector, by=click_by)1154 if outdated_driver:1155 pass # Already did the click workaround1156 elif self.mobile_emulator:1157 self.click(click_selector, by=click_by)1158 elif not outdated_driver:1159 element = page_actions.hover_and_click(1160 self.driver, hover_selector, click_selector,1161 hover_by, click_by, timeout)1162 if self.demo_mode:1163 if self.driver.current_url != pre_action_url:1164 self.__demo_mode_pause_if_active()1165 else:1166 self.__demo_mode_pause_if_active(tiny=True)1167 elif self.slow_mode:1168 self.__slow_mode_pause_if_active()1169 return element1170 def hover_and_double_click(self, hover_selector, click_selector,1171 hover_by=By.CSS_SELECTOR,1172 click_by=By.CSS_SELECTOR,1173 timeout=None):1174 """ When you want to hover over an element or dropdown menu,1175 and then double-click an element that appears after that. """1176 if not timeout:1177 timeout = settings.SMALL_TIMEOUT1178 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1179 timeout = self.__get_new_timeout(timeout)1180 hover_selector, hover_by = self.__recalculate_selector(1181 hover_selector, hover_by)1182 hover_selector = self.convert_to_css_selector(1183 hover_selector, hover_by)1184 click_selector, click_by = self.__recalculate_selector(1185 click_selector, click_by)1186 dropdown_element = self.wait_for_element_visible(1187 hover_selector, by=hover_by, timeout=timeout)1188 self.__demo_mode_highlight_if_active(hover_selector, hover_by)1189 self.scroll_to(hover_selector, by=hover_by)1190 pre_action_url = self.driver.current_url1191 outdated_driver = False1192 element = None1193 try:1194 page_actions.hover_element(self.driver, dropdown_element)1195 except Exception:1196 outdated_driver = True1197 element = self.wait_for_element_present(1198 click_selector, click_by, timeout)1199 if click_by == By.LINK_TEXT:1200 self.open(self.__get_href_from_link_text(click_selector))1201 elif click_by == By.PARTIAL_LINK_TEXT:1202 self.open(self.__get_href_from_partial_link_text(1203 click_selector))1204 else:1205 self.js_click(click_selector, click_by)1206 if not outdated_driver:1207 element = page_actions.hover_element_and_double_click(1208 self.driver, dropdown_element, click_selector,1209 click_by=By.CSS_SELECTOR, timeout=timeout)1210 if self.demo_mode:1211 if self.driver.current_url != pre_action_url:1212 self.__demo_mode_pause_if_active()1213 else:1214 self.__demo_mode_pause_if_active(tiny=True)1215 elif self.slow_mode:1216 self.__slow_mode_pause_if_active()1217 return element1218 def __select_option(self, dropdown_selector, option,1219 dropdown_by=By.CSS_SELECTOR, option_by="text",1220 timeout=None):1221 """ Selects an HTML <select> option by specification.1222 Option specifications are by "text", "index", or "value".1223 Defaults to "text" if option_by is unspecified or unknown. """1224 from selenium.webdriver.support.ui import Select1225 if not timeout:1226 timeout = settings.SMALL_TIMEOUT1227 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1228 timeout = self.__get_new_timeout(timeout)1229 if page_utils.is_xpath_selector(dropdown_selector):1230 dropdown_by = By.XPATH1231 self.wait_for_ready_state_complete()1232 element = self.wait_for_element_present(1233 dropdown_selector, by=dropdown_by, timeout=timeout)1234 if self.is_element_visible(dropdown_selector, by=dropdown_by):1235 self.__demo_mode_highlight_if_active(1236 dropdown_selector, dropdown_by)1237 pre_action_url = self.driver.current_url1238 try:1239 if option_by == "index":1240 Select(element).select_by_index(option)1241 elif option_by == "value":1242 Select(element).select_by_value(option)1243 else:1244 Select(element).select_by_visible_text(option)1245 except (StaleElementReferenceException, ENI_Exception):1246 self.wait_for_ready_state_complete()1247 time.sleep(0.05)1248 element = self.wait_for_element_present(1249 dropdown_selector, by=dropdown_by, timeout=timeout)1250 if option_by == "index":1251 Select(element).select_by_index(option)1252 elif option_by == "value":1253 Select(element).select_by_value(option)1254 else:1255 Select(element).select_by_visible_text(option)1256 if settings.WAIT_FOR_RSC_ON_CLICKS:1257 self.wait_for_ready_state_complete()1258 if self.demo_mode:1259 if self.driver.current_url != pre_action_url:1260 self.__demo_mode_pause_if_active()1261 else:1262 self.__demo_mode_pause_if_active(tiny=True)1263 elif self.slow_mode:1264 self.__slow_mode_pause_if_active()1265 def select_option_by_text(self, dropdown_selector, option,1266 dropdown_by=By.CSS_SELECTOR,1267 timeout=None):1268 """ Selects an HTML <select> option by option text.1269 @Params1270 dropdown_selector - the <select> selector1271 option - the text of the option """1272 if not timeout:1273 timeout = settings.SMALL_TIMEOUT1274 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1275 timeout = self.__get_new_timeout(timeout)1276 self.__select_option(dropdown_selector, option,1277 dropdown_by=dropdown_by, option_by="text",1278 timeout=timeout)1279 def select_option_by_index(self, dropdown_selector, option,1280 dropdown_by=By.CSS_SELECTOR,1281 timeout=None):1282 """ Selects an HTML <select> option by option index.1283 @Params1284 dropdown_selector - the <select> selector1285 option - the index number of the option """1286 if not timeout:1287 timeout = settings.SMALL_TIMEOUT1288 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1289 timeout = self.__get_new_timeout(timeout)1290 self.__select_option(dropdown_selector, option,1291 dropdown_by=dropdown_by, option_by="index",1292 timeout=timeout)1293 def select_option_by_value(self, dropdown_selector, option,1294 dropdown_by=By.CSS_SELECTOR,1295 timeout=None):1296 """ Selects an HTML <select> option by option value.1297 @Params1298 dropdown_selector - the <select> selector1299 option - the value property of the option """1300 if not timeout:1301 timeout = settings.SMALL_TIMEOUT1302 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1303 timeout = self.__get_new_timeout(timeout)1304 self.__select_option(dropdown_selector, option,1305 dropdown_by=dropdown_by, option_by="value",1306 timeout=timeout)1307 def load_html_string(self, html_string, new_page=True):1308 """ Loads an HTML string into the web browser.1309 If new_page==True, the page will switch to: "data:text/html,"1310 If new_page==False, will load HTML into the current page. """1311 soup = self.get_beautiful_soup(html_string)1312 found_base = False1313 links = soup.findAll("link")1314 href = None1315 for link in links:1316 if link.get("rel") == ["canonical"] and link.get("href"):1317 found_base = True1318 href = link.get("href")1319 href = self.get_domain_url(href)1320 if found_base and html_string.count("<head>") == 1 and (1321 html_string.count("<base") == 0):1322 html_string = html_string.replace(1323 "<head>", '<head><base href="%s">' % href)1324 elif not found_base:1325 bases = soup.findAll("base")1326 for base in bases:1327 if base.get("href"):1328 href = base.get("href")1329 if href:1330 html_string = html_string.replace(1331 'base: "."', 'base: "%s"' % href)1332 soup = self.get_beautiful_soup(html_string)1333 scripts = soup.findAll("script")1334 for script in scripts:1335 if script.get("type") != "application/json":1336 html_string = html_string.replace(str(script), "")1337 soup = self.get_beautiful_soup(html_string)1338 found_head = False1339 found_body = False1340 html_head = None1341 html_body = None1342 if soup.head and len(str(soup.head)) > 12:1343 found_head = True1344 html_head = str(soup.head)1345 html_head = re.escape(html_head)1346 html_head = self.__escape_quotes_if_needed(html_head)1347 html_head = html_head.replace('\\ ', ' ')1348 if soup.body and len(str(soup.body)) > 12:1349 found_body = True1350 html_body = str(soup.body)1351 html_body = html_body.replace("\xc2\xa0", "&#xA0;")1352 html_body = html_body.replace("\xc2\xa1", "&#xA1;")1353 html_body = html_body.replace("\xc2\xa9", "&#xA9;")1354 html_body = html_body.replace("\xc2\xb7", "&#xB7;")1355 html_body = html_body.replace("\xc2\xbf", "&#xBF;")1356 html_body = html_body.replace("\xc3\x97", "&#xD7;")1357 html_body = html_body.replace("\xc3\xb7", "&#xF7;")1358 html_body = re.escape(html_body)1359 html_body = self.__escape_quotes_if_needed(html_body)1360 html_body = html_body.replace('\\ ', ' ')1361 html_string = re.escape(html_string)1362 html_string = self.__escape_quotes_if_needed(html_string)1363 html_string = html_string.replace('\\ ', ' ')1364 if new_page:1365 self.open("data:text/html,")1366 inner_head = '''document.getElementsByTagName("head")[0].innerHTML'''1367 inner_body = '''document.getElementsByTagName("body")[0].innerHTML'''1368 if not found_body:1369 self.execute_script(1370 '''%s = \"%s\"''' % (inner_body, html_string))1371 elif found_body and not found_head:1372 self.execute_script(1373 '''%s = \"%s\"''' % (inner_body, html_body))1374 elif found_body and found_head:1375 self.execute_script(1376 '''%s = \"%s\"''' % (inner_head, html_head))1377 self.execute_script(1378 '''%s = \"%s\"''' % (inner_body, html_body))1379 else:1380 raise Exception("Logic Error!")1381 for script in scripts:1382 js_code = script.string1383 js_src = script.get("src")1384 if js_code and script.get("type") != "application/json":1385 js_code_lines = js_code.split('\n')1386 new_lines = []1387 for line in js_code_lines:1388 line = line.strip()1389 new_lines.append(line)1390 js_code = '\n'.join(new_lines)1391 js_utils.add_js_code(self.driver, js_code)1392 elif js_src:1393 js_utils.add_js_link(self.driver, js_src)1394 else:1395 pass1396 def load_html_file(self, html_file, new_page=True):1397 """ Loads a local html file into the browser from a relative file path.1398 If new_page==True, the page will switch to: "data:text/html,"1399 If new_page==False, will load HTML into the current page.1400 Local images and other local src content WILL BE IGNORED. """1401 if self.__looks_like_a_page_url(html_file):1402 self.open(html_file)1403 return1404 if len(html_file) < 6 or not html_file.endswith(".html"):1405 raise Exception('Expecting a ".html" file!')1406 abs_path = os.path.abspath('.')1407 file_path = None1408 if abs_path in html_file:1409 file_path = html_file1410 else:1411 file_path = abs_path + "/%s" % html_file1412 html_string = None1413 with open(file_path, 'r') as f:1414 html_string = f.read().strip()1415 self.load_html_string(html_string, new_page)1416 def open_html_file(self, html_file):1417 """ Opens a local html file into the browser from a relative file path.1418 The URL displayed in the web browser will start with "file://". """1419 if self.__looks_like_a_page_url(html_file):1420 self.open(html_file)1421 return1422 if len(html_file) < 6 or not html_file.endswith(".html"):1423 raise Exception('Expecting a ".html" file!')1424 abs_path = os.path.abspath('.')1425 file_path = None1426 if abs_path in html_file:1427 file_path = html_file1428 else:1429 file_path = abs_path + "/%s" % html_file1430 self.open("file://" + file_path)1431 def execute_script(self, script):1432 return self.driver.execute_script(script)1433 def execute_async_script(self, script, timeout=None):1434 if not timeout:1435 timeout = settings.EXTREME_TIMEOUT1436 return js_utils.execute_async_script(self.driver, script, timeout)1437 def safe_execute_script(self, script):1438 """ When executing a script that contains a jQuery command,1439 it's important that the jQuery library has been loaded first.1440 This method will load jQuery if it wasn't already loaded. """1441 try:1442 self.execute_script(script)1443 except Exception:1444 # The likely reason this fails is because: "jQuery is not defined"1445 self.activate_jquery() # It's a good thing we can define it here1446 self.execute_script(script)1447 def set_window_rect(self, x, y, width, height):1448 self.driver.set_window_rect(x, y, width, height)1449 self.__demo_mode_pause_if_active()1450 def set_window_size(self, width, height):1451 self.driver.set_window_size(width, height)1452 self.__demo_mode_pause_if_active()1453 def maximize_window(self):1454 self.driver.maximize_window()1455 self.__demo_mode_pause_if_active()1456 def switch_to_frame(self, frame, timeout=None):1457 """1458 Wait for an iframe to appear, and switch to it. This should be1459 usable as a drop-in replacement for driver.switch_to.frame().1460 @Params1461 frame - the frame element, name, id, index, or selector1462 timeout - the time to wait for the alert in seconds1463 """1464 if not timeout:1465 timeout = settings.SMALL_TIMEOUT1466 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1467 timeout = self.__get_new_timeout(timeout)1468 page_actions.switch_to_frame(self.driver, frame, timeout)1469 def switch_to_default_content(self):1470 """ Brings driver control outside the current iframe.1471 (If driver control is inside an iframe, the driver control1472 will be set to one level above the current frame. If the driver1473 control is not currenly in an iframe, nothing will happen.) """1474 self.driver.switch_to.default_content()1475 def open_new_window(self, switch_to=True):1476 """ Opens a new browser tab/window and switches to it by default. """1477 self.driver.execute_script("window.open('');")1478 time.sleep(0.01)1479 if switch_to:1480 self.switch_to_window(len(self.driver.window_handles) - 1)1481 def switch_to_window(self, window, timeout=None):1482 if not timeout:1483 timeout = settings.SMALL_TIMEOUT1484 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:1485 timeout = self.__get_new_timeout(timeout)1486 page_actions.switch_to_window(self.driver, window, timeout)1487 def switch_to_default_window(self):1488 self.switch_to_window(0)1489 def get_new_driver(self, browser=None, headless=None,1490 servername=None, port=None, proxy=None, agent=None,1491 switch_to=True, cap_file=None, cap_string=None,1492 disable_csp=None, enable_sync=None, use_auto_ext=None,1493 no_sandbox=None, disable_gpu=None,1494 incognito=None, guest_mode=None, devtools=None,1495 user_data_dir=None, extension_zip=None,1496 extension_dir=None, is_mobile=False,1497 d_width=None, d_height=None, d_p_r=None):1498 """ This method spins up an extra browser for tests that require1499 more than one. The first browser is already provided by tests1500 that import base_case.BaseCase from seleniumbase. If parameters1501 aren't specified, the method uses the same as the default driver.1502 @Params1503 browser - the browser to use. (Ex: "chrome", "firefox")1504 headless - the option to run webdriver in headless mode1505 servername - if using a Selenium Grid, set the host address here1506 port - if using a Selenium Grid, set the host port here1507 proxy - if using a proxy server, specify the "host:port" combo here1508 switch_to - the option to switch to the new driver (default = True)1509 cap_file - the file containing desired capabilities for the browser1510 cap_string - the string with desired capabilities for the browser1511 disable_csp - an option to disable Chrome's Content Security Policy1512 enable_sync - the option to enable the Chrome Sync feature (Chrome)1513 use_auto_ext - the option to enable Chrome's Automation Extension1514 no_sandbox - the option to enable the "No-Sandbox" feature (Chrome)1515 disable_gpu - the option to enable Chrome's "Disable GPU" feature1516 incognito - the option to enable Chrome's Incognito mode (Chrome)1517 guest - the option to enable Chrome's Guest mode (Chrome)1518 devtools - the option to open Chrome's DevTools on start (Chrome)1519 user_data_dir - Chrome's User Data Directory to use (Chrome-only)1520 extension_zip - A Chrome Extension ZIP file to use (Chrome-only)1521 extension_dir - A Chrome Extension folder to use (Chrome-only)1522 is_mobile - the option to use the mobile emulator (Chrome-only)1523 d_width - the device width of the mobile emulator (Chrome-only)1524 d_height - the device height of the mobile emulator (Chrome-only)1525 d_p_r - the device pixel ratio of the mobile emulator (Chrome-only)1526 """1527 if self.browser == "remote" and self.servername == "localhost":1528 raise Exception('Cannot use "remote" browser driver on localhost!'1529 ' Did you mean to connect to a remote Grid server'1530 ' such as BrowserStack or Sauce Labs? In that'1531 ' case, you must specify the "server" and "port"'1532 ' parameters on the command line! '1533 'Example: '1534 '--server=user:key@hub.browserstack.com --port=80')1535 browserstack_ref = (1536 'https://browserstack.com/automate/capabilities')1537 sauce_labs_ref = (1538 'https://wiki.saucelabs.com/display/DOCS/Platform+Configurator#/')1539 if self.browser == "remote" and not (self.cap_file or self.cap_string):1540 raise Exception('Need to specify a desired capabilities file when '1541 'using "--browser=remote". Add "--cap_file=FILE". '1542 'File should be in the Python format used by: '1543 '%s OR '1544 '%s '1545 'See SeleniumBase/examples/sample_cap_file_BS.py '1546 'and SeleniumBase/examples/sample_cap_file_SL.py'1547 % (browserstack_ref, sauce_labs_ref))1548 if browser is None:1549 browser = self.browser1550 browser_name = browser1551 if headless is None:1552 headless = self.headless1553 if servername is None:1554 servername = self.servername1555 if port is None:1556 port = self.port1557 use_grid = False1558 if servername != "localhost":1559 # Use Selenium Grid (Use "127.0.0.1" for localhost Grid)1560 use_grid = True1561 proxy_string = proxy1562 if proxy_string is None:1563 proxy_string = self.proxy_string1564 user_agent = agent1565 if user_agent is None:1566 user_agent = self.user_agent1567 if disable_csp is None:1568 disable_csp = self.disable_csp1569 if enable_sync is None:1570 enable_sync = self.enable_sync1571 if use_auto_ext is None:1572 use_auto_ext = self.use_auto_ext1573 if no_sandbox is None:1574 no_sandbox = self.no_sandbox1575 if disable_gpu is None:1576 disable_gpu = self.disable_gpu1577 if incognito is None:1578 incognito = self.incognito1579 if guest_mode is None:1580 guest_mode = self.guest_mode1581 if devtools is None:1582 devtools = self.devtools1583 if user_data_dir is None:1584 user_data_dir = self.user_data_dir1585 if extension_zip is None:1586 extension_zip = self.extension_zip1587 if extension_dir is None:1588 extension_dir = self.extension_dir1589 # Due to https://stackoverflow.com/questions/23055651/ , skip extension1590 # if self.demo_mode or self.masterqa_mode:1591 # disable_csp = True1592 test_id = self.__get_test_id()1593 if cap_file is None:1594 cap_file = self.cap_file1595 if cap_string is None:1596 cap_string = self.cap_string1597 if is_mobile is None:1598 is_mobile = False1599 if d_width is None:1600 d_width = self.__device_width1601 if d_height is None:1602 d_height = self.__device_height1603 if d_p_r is None:1604 d_p_r = self.__device_pixel_ratio1605 valid_browsers = constants.ValidBrowsers.valid_browsers1606 if browser_name not in valid_browsers:1607 raise Exception("Browser: {%s} is not a valid browser option. "1608 "Valid options = {%s}" % (browser, valid_browsers))1609 # Launch a web browser1610 from seleniumbase.core import browser_launcher1611 new_driver = browser_launcher.get_driver(browser_name=browser_name,1612 headless=headless,1613 use_grid=use_grid,1614 servername=servername,1615 port=port,1616 proxy_string=proxy_string,1617 user_agent=user_agent,1618 cap_file=cap_file,1619 cap_string=cap_string,1620 disable_csp=disable_csp,1621 enable_sync=enable_sync,1622 use_auto_ext=use_auto_ext,1623 no_sandbox=no_sandbox,1624 disable_gpu=disable_gpu,1625 incognito=incognito,1626 guest_mode=guest_mode,1627 devtools=devtools,1628 user_data_dir=user_data_dir,1629 extension_zip=extension_zip,1630 extension_dir=extension_dir,1631 test_id=test_id,1632 mobile_emulator=is_mobile,1633 device_width=d_width,1634 device_height=d_height,1635 device_pixel_ratio=d_p_r)1636 self._drivers_list.append(new_driver)1637 if switch_to:1638 self.driver = new_driver1639 if self.headless:1640 # Make sure the invisible browser window is big enough1641 width = settings.HEADLESS_START_WIDTH1642 height = settings.HEADLESS_START_HEIGHT1643 try:1644 self.driver.set_window_size(width, height)1645 self.wait_for_ready_state_complete()1646 except Exception:1647 # This shouldn't fail, but in case it does,1648 # get safely through setUp() so that1649 # WebDrivers can get closed during tearDown().1650 pass1651 else:1652 if self.browser == 'chrome' or self.browser == 'edge':1653 width = settings.CHROME_START_WIDTH1654 height = settings.CHROME_START_HEIGHT1655 try:1656 if self.maximize_option:1657 self.driver.maximize_window()1658 else:1659 self.driver.set_window_size(width, height)1660 self.wait_for_ready_state_complete()1661 except Exception:1662 pass # Keep existing browser resolution1663 elif self.browser == 'firefox':1664 pass # No changes1665 elif self.browser == 'safari':1666 if self.maximize_option:1667 try:1668 self.driver.maximize_window()1669 self.wait_for_ready_state_complete()1670 except Exception:1671 pass # Keep existing browser resolution1672 else:1673 try:1674 self.driver.set_window_rect(10, 30, 945, 630)1675 except Exception:1676 pass1677 if self.start_page and len(self.start_page) >= 4:1678 if page_utils.is_valid_url(self.start_page):1679 self.open(self.start_page)1680 else:1681 new_start_page = "http://" + self.start_page1682 if page_utils.is_valid_url(new_start_page):1683 self.open(new_start_page)1684 return new_driver1685 def switch_to_driver(self, driver):1686 """ Sets self.driver to the specified driver.1687 You may need this if using self.get_new_driver() in your code. """1688 self.driver = driver1689 def switch_to_default_driver(self):1690 """ Sets self.driver to the default/original driver. """1691 self.driver = self._default_driver1692 def save_screenshot(self, name, folder=None):1693 """ The screenshot will be in PNG format. """1694 return page_actions.save_screenshot(self.driver, name, folder)1695 def save_page_source(self, name, folder=None):1696 """ Saves the page HTML to the current directory (or given subfolder).1697 If the folder specified doesn't exist, it will get created.1698 @Params1699 name - The file name to save the current page's HTML to.1700 folder - The folder to save the file to. (Default = current folder)1701 """1702 return page_actions.save_page_source(self.driver, name, folder)1703 def save_cookies(self, name="cookies.txt"):1704 """ Saves the page cookies to the "saved_cookies" folder. """1705 cookies = self.driver.get_cookies()1706 json_cookies = json.dumps(cookies)1707 if name.endswith('/'):1708 raise Exception("Invalid filename for Cookies!")1709 if '/' in name:1710 name = name.split('/')[-1]1711 if len(name) < 1:1712 raise Exception("Filename for Cookies is too short!")1713 if not name.endswith(".txt"):1714 name = name + ".txt"1715 folder = constants.SavedCookies.STORAGE_FOLDER1716 abs_path = os.path.abspath('.')1717 file_path = abs_path + "/%s" % folder1718 if not os.path.exists(file_path):1719 os.makedirs(file_path)1720 cookies_file_path = "%s/%s" % (file_path, name)1721 cookies_file = codecs.open(cookies_file_path, "w+")1722 cookies_file.writelines(json_cookies)1723 cookies_file.close()1724 def load_cookies(self, name="cookies.txt"):1725 """ Loads the page cookies from the "saved_cookies" folder. """1726 if name.endswith('/'):1727 raise Exception("Invalid filename for Cookies!")1728 if '/' in name:1729 name = name.split('/')[-1]1730 if len(name) < 1:1731 raise Exception("Filename for Cookies is too short!")1732 if not name.endswith(".txt"):1733 name = name + ".txt"1734 folder = constants.SavedCookies.STORAGE_FOLDER1735 abs_path = os.path.abspath('.')1736 file_path = abs_path + "/%s" % folder1737 cookies_file_path = "%s/%s" % (file_path, name)1738 json_cookies = None1739 with open(cookies_file_path, 'r') as f:1740 json_cookies = f.read().strip()1741 cookies = json.loads(json_cookies)1742 for cookie in cookies:1743 if 'expiry' in cookie:1744 del cookie['expiry']1745 self.driver.add_cookie(cookie)1746 def delete_all_cookies(self):1747 """ Deletes all cookies in the web browser.1748 Does NOT delete the saved cookies file. """1749 self.driver.delete_all_cookies()1750 def delete_saved_cookies(self, name="cookies.txt"):1751 """ Deletes the cookies file from the "saved_cookies" folder.1752 Does NOT delete the cookies from the web browser. """1753 if name.endswith('/'):1754 raise Exception("Invalid filename for Cookies!")1755 if '/' in name:1756 name = name.split('/')[-1]1757 if len(name) < 1:1758 raise Exception("Filename for Cookies is too short!")1759 if not name.endswith(".txt"):1760 name = name + ".txt"1761 folder = constants.SavedCookies.STORAGE_FOLDER1762 abs_path = os.path.abspath('.')1763 file_path = abs_path + "/%s" % folder1764 cookies_file_path = "%s/%s" % (file_path, name)1765 if os.path.exists(cookies_file_path):1766 if cookies_file_path.endswith('.txt'):1767 os.remove(cookies_file_path)1768 def wait_for_ready_state_complete(self, timeout=None):1769 try:1770 # If there's an alert, skip1771 self.driver.switch_to.alert1772 return1773 except Exception:1774 # If there's no alert, continue1775 pass1776 if not timeout:1777 timeout = settings.EXTREME_TIMEOUT1778 if self.timeout_multiplier and timeout == settings.EXTREME_TIMEOUT:1779 timeout = self.__get_new_timeout(timeout)1780 is_ready = js_utils.wait_for_ready_state_complete(self.driver, timeout)1781 self.wait_for_angularjs(timeout=settings.MINI_TIMEOUT)1782 if self.js_checking_on:1783 self.assert_no_js_errors()1784 if self.ad_block_on:1785 # If the ad_block feature is enabled, then block ads for new URLs1786 current_url = self.get_current_url()1787 if not current_url == self.__last_page_load_url:1788 time.sleep(0.02)1789 self.ad_block()1790 time.sleep(0.01)1791 if self.is_element_present("iframe"):1792 time.sleep(0.07) # iframe ads take slightly longer to load1793 self.ad_block() # Do ad_block on slower-loading iframes1794 self.__last_page_load_url = current_url1795 return is_ready1796 def wait_for_angularjs(self, timeout=None, **kwargs):1797 if not timeout:1798 timeout = settings.LARGE_TIMEOUT1799 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:1800 timeout = self.__get_new_timeout(timeout)1801 js_utils.wait_for_angularjs(self.driver, timeout, **kwargs)1802 def sleep(self, seconds):1803 if not sb_config.time_limit:1804 time.sleep(seconds)1805 elif seconds <= 0.3:1806 shared_utils.check_if_time_limit_exceeded()1807 time.sleep(seconds)1808 shared_utils.check_if_time_limit_exceeded()1809 else:1810 start_ms = time.time() * 1000.01811 stop_ms = start_ms + (seconds * 1000.0)1812 for x in range(int(seconds * 5)):1813 shared_utils.check_if_time_limit_exceeded()1814 now_ms = time.time() * 1000.01815 if now_ms >= stop_ms:1816 break1817 time.sleep(0.2)1818 def activate_jquery(self):1819 """ If "jQuery is not defined", use this method to activate it for use.1820 This happens because jQuery is not always defined on web sites. """1821 js_utils.activate_jquery(self.driver)1822 self.wait_for_ready_state_complete()1823 def __are_quotes_escaped(self, string):1824 return js_utils.are_quotes_escaped(string)1825 def __escape_quotes_if_needed(self, string):1826 return js_utils.escape_quotes_if_needed(string)1827 def bring_to_front(self, selector, by=By.CSS_SELECTOR):1828 """ Updates the Z-index of a page element to bring it into view.1829 Useful when getting a WebDriverException, such as the one below:1830 { Element is not clickable at point (#, #).1831 Other element would receive the click: ... } """1832 selector, by = self.__recalculate_selector(selector, by)1833 self.wait_for_element_visible(1834 selector, by=by, timeout=settings.SMALL_TIMEOUT)1835 try:1836 selector = self.convert_to_css_selector(selector, by=by)1837 except Exception:1838 # Don't run action if can't convert to CSS_Selector for JavaScript1839 return1840 selector = re.escape(selector)1841 selector = self.__escape_quotes_if_needed(selector)1842 script = ("""document.querySelector('%s').style.zIndex = '999999';"""1843 % selector)1844 self.execute_script(script)1845 def highlight_click(self, selector, by=By.CSS_SELECTOR,1846 loops=3, scroll=True):1847 if not self.demo_mode:1848 self.highlight(selector, by=by, loops=loops, scroll=scroll)1849 self.click(selector, by=by)1850 def highlight_update_text(self, selector, text, by=By.CSS_SELECTOR,1851 loops=3, scroll=True):1852 if not self.demo_mode:1853 self.highlight(selector, by=by, loops=loops, scroll=scroll)1854 self.update_text(selector, text, by=by)1855 def highlight(self, selector, by=By.CSS_SELECTOR,1856 loops=None, scroll=True):1857 """ This method uses fancy JavaScript to highlight an element.1858 Used during demo_mode.1859 @Params1860 selector - the selector of the element to find1861 by - the type of selector to search by (Default: CSS)1862 loops - # of times to repeat the highlight animation1863 (Default: 4. Each loop lasts for about 0.18s)1864 scroll - the option to scroll to the element first (Default: True)1865 """1866 selector, by = self.__recalculate_selector(selector, by)1867 element = self.wait_for_element_visible(1868 selector, by=by, timeout=settings.SMALL_TIMEOUT)1869 if not loops:1870 loops = settings.HIGHLIGHTS1871 if scroll:1872 try:1873 self.__slow_scroll_to_element(element)1874 except (StaleElementReferenceException, ENI_Exception):1875 self.wait_for_ready_state_complete()1876 time.sleep(0.05)1877 element = self.wait_for_element_visible(1878 selector, by=by, timeout=settings.SMALL_TIMEOUT)1879 self.__slow_scroll_to_element(element)1880 try:1881 selector = self.convert_to_css_selector(selector, by=by)1882 except Exception:1883 # Don't highlight if can't convert to CSS_SELECTOR1884 return1885 if self.highlights:1886 loops = self.highlights1887 if self.browser == 'ie':1888 loops = 1 # Override previous setting because IE is slow1889 loops = int(loops)1890 o_bs = '' # original_box_shadow1891 try:1892 style = element.get_attribute('style')1893 except (StaleElementReferenceException, ENI_Exception):1894 self.wait_for_ready_state_complete()1895 time.sleep(0.05)1896 element = self.wait_for_element_visible(1897 selector, by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT)1898 style = element.get_attribute('style')1899 if style:1900 if 'box-shadow: ' in style:1901 box_start = style.find('box-shadow: ')1902 box_end = style.find(';', box_start) + 11903 original_box_shadow = style[box_start:box_end]1904 o_bs = original_box_shadow1905 if ":contains" not in selector and ":first" not in selector:1906 selector = re.escape(selector)1907 selector = self.__escape_quotes_if_needed(selector)1908 self.__highlight_with_js(selector, loops, o_bs)1909 else:1910 selector = self.__make_css_match_first_element_only(selector)1911 selector = re.escape(selector)1912 selector = self.__escape_quotes_if_needed(selector)1913 try:1914 self.__highlight_with_jquery(selector, loops, o_bs)1915 except Exception:1916 pass # JQuery probably couldn't load. Skip highlighting.1917 time.sleep(0.065)1918 def __highlight_with_js(self, selector, loops, o_bs):1919 js_utils.highlight_with_js(self.driver, selector, loops, o_bs)1920 def __highlight_with_jquery(self, selector, loops, o_bs):1921 js_utils.highlight_with_jquery(self.driver, selector, loops, o_bs)1922 def press_up_arrow(self, selector="html", times=1, by=By.CSS_SELECTOR):1923 """ Simulates pressing the UP Arrow on the keyboard.1924 By default, "html" will be used as the CSS Selector target.1925 You can specify how many times in-a-row the action happens. """1926 if times < 1:1927 return1928 element = self.wait_for_element_present(selector)1929 self.__demo_mode_highlight_if_active(selector, by)1930 if not self.demo_mode:1931 self.__scroll_to_element(element, selector, by)1932 for i in range(int(times)):1933 try:1934 element.send_keys(Keys.ARROW_UP)1935 except Exception:1936 self.wait_for_ready_state_complete()1937 element = self.wait_for_element_visible(selector)1938 element.send_keys(Keys.ARROW_UP)1939 time.sleep(0.01)1940 if self.slow_mode:1941 time.sleep(0.1)1942 def press_down_arrow(self, selector="html", times=1, by=By.CSS_SELECTOR):1943 """ Simulates pressing the DOWN Arrow on the keyboard.1944 By default, "html" will be used as the CSS Selector target.1945 You can specify how many times in-a-row the action happens. """1946 if times < 1:1947 return1948 element = self.wait_for_element_present(selector)1949 self.__demo_mode_highlight_if_active(selector, by)1950 if not self.demo_mode:1951 self.__scroll_to_element(element, selector, by)1952 for i in range(int(times)):1953 try:1954 element.send_keys(Keys.ARROW_DOWN)1955 except Exception:1956 self.wait_for_ready_state_complete()1957 element = self.wait_for_element_visible(selector)1958 element.send_keys(Keys.ARROW_DOWN)1959 time.sleep(0.01)1960 if self.slow_mode:1961 time.sleep(0.1)1962 def press_left_arrow(self, selector="html", times=1, by=By.CSS_SELECTOR):1963 """ Simulates pressing the LEFT Arrow on the keyboard.1964 By default, "html" will be used as the CSS Selector target.1965 You can specify how many times in-a-row the action happens. """1966 if times < 1:1967 return1968 element = self.wait_for_element_present(selector)1969 self.__demo_mode_highlight_if_active(selector, by)1970 if not self.demo_mode:1971 self.__scroll_to_element(element, selector, by)1972 for i in range(int(times)):1973 try:1974 element.send_keys(Keys.ARROW_LEFT)1975 except Exception:1976 self.wait_for_ready_state_complete()1977 element = self.wait_for_element_visible(selector)1978 element.send_keys(Keys.ARROW_LEFT)1979 time.sleep(0.01)1980 if self.slow_mode:1981 time.sleep(0.1)1982 def press_right_arrow(self, selector="html", times=1, by=By.CSS_SELECTOR):1983 """ Simulates pressing the RIGHT Arrow on the keyboard.1984 By default, "html" will be used as the CSS Selector target.1985 You can specify how many times in-a-row the action happens. """1986 if times < 1:1987 return1988 element = self.wait_for_element_present(selector)1989 self.__demo_mode_highlight_if_active(selector, by)1990 if not self.demo_mode:1991 self.__scroll_to_element(element, selector, by)1992 for i in range(int(times)):1993 try:1994 element.send_keys(Keys.ARROW_RIGHT)1995 except Exception:1996 self.wait_for_ready_state_complete()1997 element = self.wait_for_element_visible(selector)1998 element.send_keys(Keys.ARROW_RIGHT)1999 time.sleep(0.01)2000 if self.slow_mode:2001 time.sleep(0.1)2002 def scroll_to(self, selector, by=By.CSS_SELECTOR, timeout=None):2003 ''' Fast scroll to destination '''2004 if not timeout:2005 timeout = settings.SMALL_TIMEOUT2006 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:2007 timeout = self.__get_new_timeout(timeout)2008 if self.demo_mode or self.slow_mode:2009 self.slow_scroll_to(selector, by=by, timeout=timeout)2010 return2011 element = self.wait_for_element_visible(2012 selector, by=by, timeout=timeout)2013 try:2014 self.__scroll_to_element(element, selector, by)2015 except (StaleElementReferenceException, ENI_Exception):2016 self.wait_for_ready_state_complete()2017 time.sleep(0.05)2018 element = self.wait_for_element_visible(2019 selector, by=by, timeout=timeout)2020 self.__scroll_to_element(element, selector, by)2021 def slow_scroll_to(self, selector, by=By.CSS_SELECTOR, timeout=None):2022 ''' Slow motion scroll to destination '''2023 if not timeout:2024 timeout = settings.SMALL_TIMEOUT2025 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:2026 timeout = self.__get_new_timeout(timeout)2027 selector, by = self.__recalculate_selector(selector, by)2028 element = self.wait_for_element_visible(2029 selector, by=by, timeout=timeout)2030 try:2031 self.__slow_scroll_to_element(element)2032 except (StaleElementReferenceException, ENI_Exception):2033 self.wait_for_ready_state_complete()2034 time.sleep(0.05)2035 element = self.wait_for_element_visible(2036 selector, by=by, timeout=timeout)2037 self.__slow_scroll_to_element(element)2038 def scroll_to_top(self):2039 """ Scroll to the top of the page. """2040 scroll_script = "window.scrollTo(0, 0);"2041 try:2042 self.execute_script(scroll_script)2043 time.sleep(0.012)2044 return True2045 except Exception:2046 return False2047 def scroll_to_bottom(self):2048 """ Scroll to the bottom of the page. """2049 scroll_script = "window.scrollTo(0, 10000);"2050 try:2051 self.execute_script(scroll_script)2052 time.sleep(0.012)2053 return True2054 except Exception:2055 return False2056 def click_xpath(self, xpath):2057 # Technically self.click() will automatically detect an xpath selector,2058 # so self.click_xpath() is just a longer name for the same action.2059 self.click(xpath, by=By.XPATH)2060 def js_click(self, selector, by=By.CSS_SELECTOR, all_matches=False):2061 """ Clicks an element using pure JS. Does not use jQuery.2062 If "all_matches" is False, only the first match is clicked. """2063 selector, by = self.__recalculate_selector(selector, by)2064 if by == By.LINK_TEXT:2065 message = (2066 "Pure JavaScript doesn't support clicking by Link Text. "2067 "You may want to use self.jquery_click() instead, which "2068 "allows this with :contains(), assuming jQuery isn't blocked. "2069 "For now, self.js_click() will use a regular WebDriver click.")2070 logging.debug(message)2071 self.click(selector, by=by)2072 return2073 element = self.wait_for_element_present(2074 selector, by=by, timeout=settings.SMALL_TIMEOUT)2075 if self.is_element_visible(selector, by=by):2076 self.__demo_mode_highlight_if_active(selector, by)2077 if not self.demo_mode:2078 self.__scroll_to_element(element, selector, by)2079 css_selector = self.convert_to_css_selector(selector, by=by)2080 css_selector = re.escape(css_selector)2081 css_selector = self.__escape_quotes_if_needed(css_selector)2082 if not all_matches:2083 self.__js_click(selector, by=by) # The real "magic" happens2084 else:2085 self.__js_click_all(selector, by=by) # The real "magic" happens2086 self.wait_for_ready_state_complete()2087 self.__demo_mode_pause_if_active()2088 def js_click_all(self, selector, by=By.CSS_SELECTOR):2089 """ Clicks all matching elements using pure JS. (No jQuery) """2090 self.js_click(selector, by=By.CSS_SELECTOR, all_matches=True)2091 def jquery_click(self, selector, by=By.CSS_SELECTOR):2092 """ Clicks an element using jQuery. Different from using pure JS. """2093 selector, by = self.__recalculate_selector(selector, by)2094 self.wait_for_element_present(2095 selector, by=by, timeout=settings.SMALL_TIMEOUT)2096 if self.is_element_visible(selector, by=by):2097 self.__demo_mode_highlight_if_active(selector, by)2098 selector = self.convert_to_css_selector(selector, by=by)2099 selector = self.__make_css_match_first_element_only(selector)2100 click_script = """jQuery('%s')[0].click()""" % selector2101 self.safe_execute_script(click_script)2102 self.__demo_mode_pause_if_active()2103 def jquery_click_all(self, selector, by=By.CSS_SELECTOR):2104 """ Clicks all matching elements using jQuery. """2105 selector, by = self.__recalculate_selector(selector, by)2106 self.wait_for_element_present(2107 selector, by=by, timeout=settings.SMALL_TIMEOUT)2108 if self.is_element_visible(selector, by=by):2109 self.__demo_mode_highlight_if_active(selector, by)2110 selector = self.convert_to_css_selector(selector, by=by)2111 click_script = """jQuery('%s').click()""" % selector2112 self.safe_execute_script(click_script)2113 self.__demo_mode_pause_if_active()2114 def hide_element(self, selector, by=By.CSS_SELECTOR):2115 """ Hide the first element on the page that matches the selector. """2116 selector, by = self.__recalculate_selector(selector, by)2117 selector = self.convert_to_css_selector(selector, by=by)2118 selector = self.__make_css_match_first_element_only(selector)2119 hide_script = """jQuery('%s').hide()""" % selector2120 self.safe_execute_script(hide_script)2121 def hide_elements(self, selector, by=By.CSS_SELECTOR):2122 """ Hide all elements on the page that match the selector. """2123 selector, by = self.__recalculate_selector(selector, by)2124 selector = self.convert_to_css_selector(selector, by=by)2125 hide_script = """jQuery('%s').hide()""" % selector2126 self.safe_execute_script(hide_script)2127 def show_element(self, selector, by=By.CSS_SELECTOR):2128 """ Show the first element on the page that matches the selector. """2129 selector, by = self.__recalculate_selector(selector, by)2130 selector = self.convert_to_css_selector(selector, by=by)2131 selector = self.__make_css_match_first_element_only(selector)2132 show_script = """jQuery('%s').show(0)""" % selector2133 self.safe_execute_script(show_script)2134 def show_elements(self, selector, by=By.CSS_SELECTOR):2135 """ Show all elements on the page that match the selector. """2136 selector, by = self.__recalculate_selector(selector, by)2137 selector = self.convert_to_css_selector(selector, by=by)2138 show_script = """jQuery('%s').show(0)""" % selector2139 self.safe_execute_script(show_script)2140 def remove_element(self, selector, by=By.CSS_SELECTOR):2141 """ Remove the first element on the page that matches the selector. """2142 selector, by = self.__recalculate_selector(selector, by)2143 selector = self.convert_to_css_selector(selector, by=by)2144 selector = self.__make_css_match_first_element_only(selector)2145 remove_script = """jQuery('%s').remove()""" % selector2146 self.safe_execute_script(remove_script)2147 def remove_elements(self, selector, by=By.CSS_SELECTOR):2148 """ Remove all elements on the page that match the selector. """2149 selector, by = self.__recalculate_selector(selector, by)2150 selector = self.convert_to_css_selector(selector, by=by)2151 remove_script = """jQuery('%s').remove()""" % selector2152 self.safe_execute_script(remove_script)2153 def ad_block(self):2154 """ Block ads that appear on the current web page. """2155 self.wait_for_ready_state_complete()2156 from seleniumbase.config import ad_block_list2157 for css_selector in ad_block_list.AD_BLOCK_LIST:2158 css_selector = re.escape(css_selector)2159 css_selector = self.__escape_quotes_if_needed(css_selector)2160 script = ("""var $elements = document.querySelectorAll('%s');2161 var index = 0, length = $elements.length;2162 for(; index < length; index++){2163 $elements[index].remove();}"""2164 % css_selector)2165 try:2166 self.execute_script(script)2167 except Exception:2168 pass # Don't fail test if ad_blocking fails2169 def get_domain_url(self, url):2170 return page_utils.get_domain_url(url)2171 def get_beautiful_soup(self, source=None):2172 """ BeautifulSoup is a toolkit for dissecting an HTML document2173 and extracting what you need. It's great for screen-scraping! """2174 from bs4 import BeautifulSoup2175 if not source:2176 self.wait_for_ready_state_complete()2177 source = self.get_page_source()2178 soup = BeautifulSoup(source, "html.parser")2179 return soup2180 def get_unique_links(self):2181 """ Get all unique links in the html of the page source.2182 Page links include those obtained from:2183 "a"->"href", "img"->"src", "link"->"href", and "script"->"src". """2184 page_url = self.get_current_url()2185 soup = self.get_beautiful_soup(self.get_page_source())2186 links = page_utils._get_unique_links(page_url, soup)2187 return links2188 def get_link_status_code(self, link, allow_redirects=False, timeout=5):2189 """ Get the status code of a link.2190 If the timeout is exceeded, will return a 404.2191 For a list of available status codes, see:2192 https://en.wikipedia.org/wiki/List_of_HTTP_status_codes """2193 status_code = page_utils._get_link_status_code(2194 link, allow_redirects=allow_redirects, timeout=timeout)2195 return status_code2196 def assert_link_status_code_is_not_404(self, link):2197 status_code = str(self.get_link_status_code(link))2198 bad_link_str = 'Error: "%s" returned a 404!' % link2199 self.assertNotEqual(status_code, "404", bad_link_str)2200 def assert_no_404_errors(self, multithreaded=True):2201 """ Assert no 404 errors from page links obtained from:2202 "a"->"href", "img"->"src", "link"->"href", and "script"->"src". """2203 all_links = self.get_unique_links()2204 links = []2205 for link in all_links:2206 if "javascript:" not in link and "mailto:" not in link:2207 links.append(link)2208 if multithreaded:2209 from multiprocessing.dummy import Pool as ThreadPool2210 pool = ThreadPool(10)2211 pool.map(self.assert_link_status_code_is_not_404, links)2212 pool.close()2213 pool.join()2214 else:2215 for link in links:2216 self.assert_link_status_code_is_not_404(link)2217 if self.demo_mode:2218 a_t = "ASSERT NO 404 ERRORS"2219 if self._language != "English":2220 from seleniumbase.fixtures.words import SD2221 a_t = SD.translate_assert_no_404_errors(self._language)2222 messenger_post = ("%s" % a_t)2223 self.__highlight_with_assert_success(messenger_post, "html")2224 def print_unique_links_with_status_codes(self):2225 """ Finds all unique links in the html of the page source2226 and then prints out those links with their status codes.2227 Format: ["link" -> "status_code"] (per line)2228 Page links include those obtained from:2229 "a"->"href", "img"->"src", "link"->"href", and "script"->"src". """2230 page_url = self.get_current_url()2231 soup = self.get_beautiful_soup(self.get_page_source())2232 page_utils._print_unique_links_with_status_codes(page_url, soup)2233 def __fix_unicode_conversion(self, text):2234 """ Fixing Chinese characters when converting from PDF to HTML. """2235 if sys.version_info[0] < 3:2236 # Update encoding for Python 2 users2237 reload(sys) # noqa2238 sys.setdefaultencoding('utf8')2239 text = text.replace(u'\u2f8f', u'\u884c')2240 text = text.replace(u'\u2f45', u'\u65b9')2241 text = text.replace(u'\u2f08', u'\u4eba')2242 text = text.replace(u'\u2f70', u'\u793a')2243 return text2244 def get_pdf_text(self, pdf, page=None, maxpages=None,2245 password=None, codec='utf-8', wrap=False, nav=False,2246 override=False):2247 """ Gets text from a PDF file.2248 PDF can be either a URL or a file path on the local file system.2249 @Params2250 pdf - The URL or file path of the PDF file.2251 page - The page number (or a list of page numbers) of the PDF.2252 If a page number is provided, looks only at that page.2253 (1 is the first page, 2 is the second page, etc.)2254 If no page number is provided, returns all PDF text.2255 maxpages - Instead of providing a page number, you can provide2256 the number of pages to use from the beginning.2257 password - If the PDF is password-protected, enter it here.2258 codec - The compression format for character encoding.2259 (The default codec used by this method is 'utf-8'.)2260 wrap - Replaces ' \n' with ' ' so that individual sentences2261 from a PDF don't get broken up into seperate lines when2262 getting converted into text format.2263 nav - If PDF is a URL, navigates to the URL in the browser first.2264 (Not needed because the PDF will be downloaded anyway.)2265 override - If the PDF file to be downloaded already exists in the2266 downloaded_files/ folder, that PDF will be used2267 instead of downloading it again. """2268 import warnings2269 with warnings.catch_warnings():2270 warnings.simplefilter("ignore", category=UserWarning)2271 from pdfminer.high_level import extract_text2272 if not password:2273 password = ''2274 if not maxpages:2275 maxpages = 02276 if not pdf.lower().endswith('.pdf'):2277 raise Exception("%s is not a PDF file! (Expecting a .pdf)" % pdf)2278 file_path = None2279 if page_utils.is_valid_url(pdf):2280 if nav:2281 if self.get_current_url() != pdf:2282 self.open(pdf)2283 file_name = pdf.split('/')[-1]2284 file_path = self.get_downloads_folder() + '/' + file_name2285 if not os.path.exists(file_path):2286 self.download_file(pdf)2287 elif override:2288 self.download_file(pdf)2289 else:2290 if not os.path.exists(pdf):2291 raise Exception("%s is not a valid URL or file path!" % pdf)2292 file_path = os.path.abspath(pdf)2293 page_search = None # (Pages are delimited by '\x0c')2294 if type(page) is list:2295 pages = page2296 page_search = []2297 for page in pages:2298 page_search.append(page - 1)2299 elif type(page) is int:2300 page = page - 12301 if page < 0:2302 page = 02303 page_search = [page]2304 else:2305 page_search = None2306 pdf_text = extract_text(2307 file_path, password='', page_numbers=page_search,2308 maxpages=maxpages, caching=False, codec=codec)2309 pdf_text = self.__fix_unicode_conversion(pdf_text)2310 if wrap:2311 pdf_text = pdf_text.replace(' \n', ' ')2312 pdf_text = pdf_text.strip() # Remove leading and trailing whitespace2313 return pdf_text2314 def assert_pdf_text(self, pdf, text, page=None, maxpages=None,2315 password=None, codec='utf-8', wrap=True, nav=False,2316 override=False):2317 """ Asserts text in a PDF file.2318 PDF can be either a URL or a file path on the local file system.2319 @Params2320 pdf - The URL or file path of the PDF file.2321 text - The expected text to verify in the PDF.2322 page - The page number of the PDF to use (optional).2323 If a page number is provided, looks only at that page.2324 (1 is the first page, 2 is the second page, etc.)2325 If no page number is provided, looks at all the pages.2326 maxpages - Instead of providing a page number, you can provide2327 the number of pages to use from the beginning.2328 password - If the PDF is password-protected, enter it here.2329 codec - The compression format for character encoding.2330 (The default codec used by this method is 'utf-8'.)2331 wrap - Replaces ' \n' with ' ' so that individual sentences2332 from a PDF don't get broken up into seperate lines when2333 getting converted into text format.2334 nav - If PDF is a URL, navigates to the URL in the browser first.2335 (Not needed because the PDF will be downloaded anyway.)2336 override - If the PDF file to be downloaded already exists in the2337 downloaded_files/ folder, that PDF will be used2338 instead of downloading it again. """2339 text = self.__fix_unicode_conversion(text)2340 if not codec:2341 codec = 'utf-8'2342 pdf_text = self.get_pdf_text(2343 pdf, page=page, maxpages=maxpages, password=password, codec=codec,2344 wrap=wrap, nav=nav, override=override)2345 if type(page) is int:2346 if text not in pdf_text:2347 raise Exception("PDF [%s] is missing expected text [%s] on "2348 "page [%s]!" % (pdf, text, page))2349 else:2350 if text not in pdf_text:2351 raise Exception("PDF [%s] is missing expected text [%s]!"2352 "" % (pdf, text))2353 return True2354 def create_folder(self, folder):2355 """ Creates a folder of the given name if it doesn't already exist. """2356 if folder.endswith("/"):2357 folder = folder[:-1]2358 if len(folder) < 1:2359 raise Exception("Minimum folder name length = 1.")2360 if not os.path.exists(folder):2361 try:2362 os.makedirs(folder)2363 except Exception:2364 pass2365 def choose_file(self, selector, file_path, by=By.CSS_SELECTOR,2366 timeout=None):2367 """ This method is used to choose a file to upload to a website.2368 It works by populating a file-chooser "input" field of type="file".2369 A relative file_path will get converted into an absolute file_path.2370 Example usage:2371 self.choose_file('input[type="file"]', "my_dir/my_file.txt")2372 """2373 if not timeout:2374 timeout = settings.LARGE_TIMEOUT2375 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2376 timeout = self.__get_new_timeout(timeout)2377 selector, by = self.__recalculate_selector(selector, by)2378 abs_path = os.path.abspath(file_path)2379 self.add_text(selector, abs_path, by=by, timeout=timeout)2380 def save_element_as_image_file(self, selector, file_name, folder=None):2381 """ Take a screenshot of an element and save it as an image file.2382 If no folder is specified, will save it to the current folder. """2383 element = self.wait_for_element_visible(selector)2384 element_png = element.screenshot_as_png2385 if len(file_name.split('.')[0]) < 1:2386 raise Exception("Error: file_name length must be > 0.")2387 if not file_name.endswith(".png"):2388 file_name = file_name + ".png"2389 image_file_path = None2390 if folder:2391 if folder.endswith("/"):2392 folder = folder[:-1]2393 if len(folder) > 0:2394 self.create_folder(folder)2395 image_file_path = "%s/%s" % (folder, file_name)2396 if not image_file_path:2397 image_file_path = file_name2398 with open(image_file_path, "wb") as file:2399 file.write(element_png)2400 def download_file(self, file_url, destination_folder=None):2401 """ Downloads the file from the url to the destination folder.2402 If no destination folder is specified, the default one is used.2403 (The default downloads folder = "./downloaded_files") """2404 if not destination_folder:2405 destination_folder = constants.Files.DOWNLOADS_FOLDER2406 if not os.path.exists(destination_folder):2407 os.makedirs(destination_folder)2408 page_utils._download_file_to(file_url, destination_folder)2409 def save_file_as(self, file_url, new_file_name, destination_folder=None):2410 """ Similar to self.download_file(), except that you get to rename the2411 file being downloaded to whatever you want. """2412 if not destination_folder:2413 destination_folder = constants.Files.DOWNLOADS_FOLDER2414 page_utils._download_file_to(2415 file_url, destination_folder, new_file_name)2416 def save_data_as(self, data, file_name, destination_folder=None):2417 """ Saves the data specified to a file of the name specified.2418 If no destination folder is specified, the default one is used.2419 (The default downloads folder = "./downloaded_files") """2420 if not destination_folder:2421 destination_folder = constants.Files.DOWNLOADS_FOLDER2422 page_utils._save_data_as(data, destination_folder, file_name)2423 def get_downloads_folder(self):2424 """ Returns the OS path of the Downloads Folder.2425 (Works with Chrome and Firefox only, for now.) """2426 from seleniumbase.core import download_helper2427 return download_helper.get_downloads_folder()2428 def get_path_of_downloaded_file(self, file):2429 """ Returns the OS path of the downloaded file. """2430 return os.path.join(self.get_downloads_folder(), file)2431 def is_downloaded_file_present(self, file):2432 """ Checks if the file exists in the Downloads Folder. """2433 return os.path.exists(self.get_path_of_downloaded_file(file))2434 def assert_downloaded_file(self, file, timeout=None):2435 """ Asserts that the file exists in the Downloads Folder. """2436 if not timeout:2437 timeout = settings.SMALL_TIMEOUT2438 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:2439 timeout = self.__get_new_timeout(timeout)2440 start_ms = time.time() * 1000.02441 stop_ms = start_ms + (timeout * 1000.0)2442 for x in range(int(timeout)):2443 shared_utils.check_if_time_limit_exceeded()2444 try:2445 self.assertTrue(2446 os.path.exists(self.get_path_of_downloaded_file(file)),2447 "File [%s] was not found in the downloads folder [%s]!"2448 "" % (file, self.get_downloads_folder()))2449 if self.demo_mode:2450 messenger_post = ("ASSERT DOWNLOADED FILE: [%s]" % file)2451 js_utils.post_messenger_success_message(2452 self.driver, messenger_post, self.message_duration)2453 return2454 except Exception:2455 now_ms = time.time() * 1000.02456 if now_ms >= stop_ms:2457 break2458 time.sleep(1)2459 if not os.path.exists(self.get_path_of_downloaded_file(file)):2460 message = (2461 "File {%s} was not found in the downloads folder {%s} "2462 "after %s seconds! (Or the download didn't complete!)"2463 "" % (file, self.get_downloads_folder(), timeout))2464 page_actions.timeout_exception("NoSuchFileException", message)2465 if self.demo_mode:2466 messenger_post = ("ASSERT DOWNLOADED FILE: [%s]" % file)2467 js_utils.post_messenger_success_message(2468 self.driver, messenger_post, self.message_duration)2469 def assert_true(self, expr, msg=None):2470 """ Asserts that the expression is True.2471 Will raise an exception if the statement if False. """2472 self.assertTrue(expr, msg=msg)2473 def assert_false(self, expr, msg=None):2474 """ Asserts that the expression is False.2475 Will raise an exception if the statement if True. """2476 self.assertFalse(expr, msg=msg)2477 def assert_equal(self, first, second, msg=None):2478 """ Asserts that the two values are equal.2479 Will raise an exception if the values are not equal. """2480 self.assertEqual(first, second, msg=msg)2481 def assert_not_equal(self, first, second, msg=None):2482 """ Asserts that the two values are not equal.2483 Will raise an exception if the values are equal. """2484 self.assertNotEqual(first, second, msg=msg)2485 def assert_raises(self, *args, **kwargs):2486 """ Asserts that the following block of code raises an exception.2487 Will raise an exception if the block of code has no exception.2488 Usage Example =>2489 # Verify that the expected exception is raised.2490 with self.assert_raises(Exception):2491 raise Exception("Expected Exception!")2492 """2493 self.assertRaises(*args, **kwargs)2494 def assert_title(self, title):2495 """ Asserts that the web page title matches the expected title. """2496 expected = title2497 actual = self.get_page_title()2498 self.assertEqual(expected, actual, "Expected page title [%s] "2499 "does not match the actual page title [%s]!"2500 "" % (expected, actual))2501 if self.demo_mode:2502 a_t = "ASSERT TITLE"2503 if self._language != "English":2504 from seleniumbase.fixtures.words import SD2505 a_t = SD.translate_assert_title(self._language)2506 messenger_post = ("%s: {%s}" % (a_t, title))2507 self.__highlight_with_assert_success(messenger_post, "html")2508 def assert_no_js_errors(self):2509 """ Asserts that there are no JavaScript "SEVERE"-level page errors.2510 Works ONLY for Chrome (non-headless) and Chrome-based browsers.2511 Does NOT work on Firefox, Edge, IE, and some other browsers:2512 * See https://github.com/SeleniumHQ/selenium/issues/11612513 Based on the following Stack Overflow solution:2514 * https://stackoverflow.com/a/41150512/7058266 """2515 self.wait_for_ready_state_complete()2516 time.sleep(0.1) # May take a moment for errors to appear after loads.2517 try:2518 browser_logs = self.driver.get_log('browser')2519 except (ValueError, WebDriverException):2520 # If unable to get browser logs, skip the assert and return.2521 return2522 messenger_library = "//cdnjs.cloudflare.com/ajax/libs/messenger"2523 errors = []2524 for entry in browser_logs:2525 if entry['level'] == 'SEVERE':2526 if messenger_library not in entry['message']:2527 # Add errors if not caused by SeleniumBase dependencies2528 errors.append(entry)2529 if len(errors) > 0:2530 current_url = self.get_current_url()2531 raise Exception(2532 "JavaScript errors found on %s => %s" % (current_url, errors))2533 if self.demo_mode:2534 if (self.browser == 'chrome' or self.browser == 'edge'):2535 a_t = "ASSERT NO JS ERRORS"2536 if self._language != "English":2537 from seleniumbase.fixtures.words import SD2538 a_t = SD.translate_assert_no_js_errors(self._language)2539 messenger_post = ("%s" % a_t)2540 self.__highlight_with_assert_success(messenger_post, "html")2541 def __activate_html_inspector(self):2542 self.wait_for_ready_state_complete()2543 time.sleep(0.05)2544 js_utils.activate_html_inspector(self.driver)2545 def inspect_html(self):2546 """ Inspects the Page HTML with HTML-Inspector.2547 (https://github.com/philipwalton/html-inspector)2548 (https://cdnjs.com/libraries/html-inspector)2549 Prints the results and also returns them. """2550 self.__activate_html_inspector()2551 script = ("""HTMLInspector.inspect();""")2552 self.execute_script(script)2553 time.sleep(0.1)2554 browser_logs = []2555 try:2556 browser_logs = self.driver.get_log('browser')2557 except (ValueError, WebDriverException):2558 # If unable to get browser logs, skip the assert and return.2559 return("(Unable to Inspect HTML! -> Only works on Chrome!)")2560 messenger_library = "//cdnjs.cloudflare.com/ajax/libs/messenger"2561 url = self.get_current_url()2562 header = '\n* HTML Inspection Results: %s' % url2563 results = [header]2564 row_count = 02565 for entry in browser_logs:2566 message = entry['message']2567 if "0:6053 " in message:2568 message = message.split("0:6053")[1]2569 message = message.replace("\\u003C", "<")2570 if message.startswith(' "') and message.count('"') == 2:2571 message = message.split('"')[1]2572 message = "X - " + message2573 if messenger_library not in message:2574 if message not in results:2575 results.append(message)2576 row_count += 12577 if row_count > 0:2578 results.append('* (See the Console output for details!)')2579 else:2580 results.append('* (No issues detected!)')2581 results = '\n'.join(results)2582 print(results)2583 return(results)2584 def get_google_auth_password(self, totp_key=None):2585 """ Returns a time-based one-time password based on the2586 Google Authenticator password algorithm. Works with Authy.2587 If "totp_key" is not specified, defaults to using the one2588 provided in seleniumbase/config/settings.py2589 Google Auth passwords expire and change at 30-second intervals.2590 If the fetched password expires in the next 1.5 seconds, waits2591 for a new one before returning it (may take up to 1.5 seconds).2592 See https://pyotp.readthedocs.io/en/latest/ for details. """2593 import pyotp2594 if not totp_key:2595 totp_key = settings.TOTP_KEY2596 epoch_interval = time.time() / 30.02597 cycle_lifespan = float(epoch_interval) - int(epoch_interval)2598 if float(cycle_lifespan) > 0.95:2599 # Password expires in the next 1.5 seconds. Wait for a new one.2600 for i in range(30):2601 time.sleep(0.05)2602 epoch_interval = time.time() / 30.02603 cycle_lifespan = float(epoch_interval) - int(epoch_interval)2604 if not float(cycle_lifespan) > 0.95:2605 # The new password cycle has begun2606 break2607 totp = pyotp.TOTP(totp_key)2608 return str(totp.now())2609 def convert_xpath_to_css(self, xpath):2610 return xpath_to_css.convert_xpath_to_css(xpath)2611 def convert_to_css_selector(self, selector, by):2612 """ This method converts a selector to a CSS_SELECTOR.2613 jQuery commands require a CSS_SELECTOR for finding elements.2614 This method should only be used for jQuery/JavaScript actions.2615 Pure JavaScript doesn't support using a:contains("LINK_TEXT"). """2616 if by == By.CSS_SELECTOR:2617 return selector2618 elif by == By.ID:2619 return '#%s' % selector2620 elif by == By.CLASS_NAME:2621 return '.%s' % selector2622 elif by == By.NAME:2623 return '[name="%s"]' % selector2624 elif by == By.TAG_NAME:2625 return selector2626 elif by == By.XPATH:2627 return self.convert_xpath_to_css(selector)2628 elif by == By.LINK_TEXT:2629 return 'a:contains("%s")' % selector2630 elif by == By.PARTIAL_LINK_TEXT:2631 return 'a:contains("%s")' % selector2632 else:2633 raise Exception(2634 "Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!" % (2635 selector, by))2636 def set_value(self, selector, text, by=By.CSS_SELECTOR, timeout=None):2637 """ This method uses JavaScript to update a text field. """2638 if not timeout:2639 timeout = settings.LARGE_TIMEOUT2640 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2641 timeout = self.__get_new_timeout(timeout)2642 selector, by = self.__recalculate_selector(selector, by)2643 orginal_selector = selector2644 css_selector = self.convert_to_css_selector(selector, by=by)2645 self.__demo_mode_highlight_if_active(orginal_selector, by)2646 if not self.demo_mode:2647 self.scroll_to(orginal_selector, by=by, timeout=timeout)2648 if type(text) is int or type(text) is float:2649 text = str(text)2650 value = re.escape(text)2651 value = self.__escape_quotes_if_needed(value)2652 css_selector = re.escape(css_selector)2653 css_selector = self.__escape_quotes_if_needed(css_selector)2654 script = ("""document.querySelector('%s').value='%s';"""2655 % (css_selector, value))2656 self.execute_script(script)2657 if text.endswith('\n'):2658 element = self.wait_for_element_present(2659 orginal_selector, by=by, timeout=timeout)2660 element.send_keys(Keys.RETURN)2661 if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:2662 self.wait_for_ready_state_complete()2663 self.__demo_mode_pause_if_active()2664 def js_update_text(self, selector, text, by=By.CSS_SELECTOR,2665 timeout=None):2666 """ JavaScript + send_keys are used to update a text field.2667 Performs self.set_value() and triggers event listeners.2668 If text ends in "\n", set_value() presses RETURN after.2669 Works faster than send_keys() alone due to the JS call.2670 """2671 if not timeout:2672 timeout = settings.LARGE_TIMEOUT2673 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2674 timeout = self.__get_new_timeout(timeout)2675 selector, by = self.__recalculate_selector(selector, by)2676 if type(text) is int or type(text) is float:2677 text = str(text)2678 self.set_value(2679 selector, text, by=by, timeout=timeout)2680 if not text.endswith('\n'):2681 try:2682 element = page_actions.wait_for_element_present(2683 self.driver, selector, by, timeout=0.2)2684 element.send_keys(" \b")2685 except Exception:2686 pass2687 def js_type(self, selector, text, by=By.CSS_SELECTOR,2688 timeout=None):2689 """ Same as self.js_update_text()2690 JavaScript + send_keys are used to update a text field.2691 Performs self.set_value() and triggers event listeners.2692 If text ends in "\n", set_value() presses RETURN after.2693 Works faster than send_keys() alone due to the JS call.2694 """2695 if not timeout:2696 timeout = settings.LARGE_TIMEOUT2697 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2698 timeout = self.__get_new_timeout(timeout)2699 selector, by = self.__recalculate_selector(selector, by)2700 if type(text) is int or type(text) is float:2701 text = str(text)2702 self.set_value(2703 selector, text, by=by, timeout=timeout)2704 if not text.endswith('\n'):2705 try:2706 element = page_actions.wait_for_element_present(2707 self.driver, selector, by, timeout=0.2)2708 element.send_keys(" \b")2709 except Exception:2710 pass2711 def jquery_update_text(self, selector, text, by=By.CSS_SELECTOR,2712 timeout=None):2713 """ This method uses jQuery to update a text field.2714 If the text string ends with the newline character,2715 Selenium finishes the call, which simulates pressing2716 {Enter/Return} after the text is entered. """2717 if not timeout:2718 timeout = settings.LARGE_TIMEOUT2719 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2720 timeout = self.__get_new_timeout(timeout)2721 selector, by = self.__recalculate_selector(selector, by)2722 element = self.wait_for_element_visible(2723 selector, by=by, timeout=timeout)2724 self.__demo_mode_highlight_if_active(selector, by)2725 self.scroll_to(selector, by=by)2726 selector = self.convert_to_css_selector(selector, by=by)2727 selector = self.__make_css_match_first_element_only(selector)2728 selector = self.__escape_quotes_if_needed(selector)2729 text = re.escape(text)2730 text = self.__escape_quotes_if_needed(text)2731 update_text_script = """jQuery('%s').val('%s')""" % (2732 selector, text)2733 self.safe_execute_script(update_text_script)2734 if text.endswith('\n'):2735 element.send_keys('\n')2736 self.__demo_mode_pause_if_active()2737 def set_time_limit(self, time_limit):2738 if time_limit:2739 try:2740 sb_config.time_limit = float(time_limit)2741 except Exception:2742 sb_config.time_limit = None2743 else:2744 sb_config.time_limit = None2745 if sb_config.time_limit and sb_config.time_limit > 0:2746 sb_config.time_limit_ms = int(sb_config.time_limit * 1000.0)2747 self.time_limit = sb_config.time_limit2748 else:2749 self.time_limit = None2750 sb_config.time_limit = None2751 sb_config.time_limit_ms = None2752 def skip(self, reason=""):2753 """ Mark the test as Skipped. """2754 self.skipTest(reason)2755 ############2756 # Application "Local Storage" controls2757 def set_local_storage_item(self, key, value):2758 self.execute_script(2759 "window.localStorage.setItem('{}', '{}');".format(key, value))2760 def get_local_storage_item(self, key):2761 return self.execute_script(2762 "return window.localStorage.getItem('{}');".format(key))2763 def remove_local_storage_item(self, key):2764 self.execute_script(2765 "window.localStorage.removeItem('{}');".format(key))2766 def clear_local_storage(self):2767 self.execute_script("window.localStorage.clear();")2768 def get_local_storage_keys(self):2769 return self.execute_script(2770 "var ls = window.localStorage, keys = []; "2771 "for (var i = 0; i < ls.length; ++i) "2772 " keys[i] = ls.key(i); "2773 "return keys;")2774 def get_local_storage_items(self):2775 return self.execute_script(2776 r"var ls = window.localStorage, items = {}; "2777 "for (var i = 0, k; i < ls.length; ++i) "2778 " items[k = ls.key(i)] = ls.getItem(k); "2779 "return items;")2780 # Application "Session Storage" controls2781 def set_session_storage_item(self, key, value):2782 self.execute_script(2783 "window.sessionStorage.setItem('{}', '{}');".format(key, value))2784 def get_session_storage_item(self, key):2785 return self.execute_script(2786 "return window.sessionStorage.getItem('{}');".format(key))2787 def remove_session_storage_item(self, key):2788 self.execute_script(2789 "window.sessionStorage.removeItem('{}');".format(key))2790 def clear_session_storage(self):2791 self.execute_script("window.sessionStorage.clear();")2792 def get_session_storage_keys(self):2793 return self.execute_script(2794 "var ls = window.sessionStorage, keys = []; "2795 "for (var i = 0; i < ls.length; ++i) "2796 " keys[i] = ls.key(i); "2797 "return keys;")2798 def get_session_storage_items(self):2799 return self.execute_script(2800 r"var ls = window.sessionStorage, items = {}; "2801 "for (var i = 0, k; i < ls.length; ++i) "2802 " items[k = ls.key(i)] = ls.getItem(k); "2803 "return items;")2804 ############2805 # Duplicates (Avoids name confusion when migrating from other frameworks.)2806 def open_url(self, url):2807 """ Same as self.open() """2808 self.open(url)2809 def visit(self, url):2810 """ Same as self.open() """2811 self.open(url)2812 def visit_url(self, url):2813 """ Same as self.open() """2814 self.open(url)2815 def goto(self, url):2816 """ Same as self.open() """2817 self.open(url)2818 def go_to(self, url):2819 """ Same as self.open() """2820 self.open(url)2821 def reload(self):2822 """ Same as self.refresh_page() """2823 self.refresh_page()2824 def reload_page(self):2825 """ Same as self.refresh_page() """2826 self.refresh_page()2827 def input(self, selector, text, by=By.CSS_SELECTOR,2828 timeout=None, retry=False):2829 """ Same as self.update_text() """2830 if not timeout:2831 timeout = settings.LARGE_TIMEOUT2832 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2833 timeout = self.__get_new_timeout(timeout)2834 selector, by = self.__recalculate_selector(selector, by)2835 self.update_text(selector, text, by=by, timeout=timeout, retry=retry)2836 def write(self, selector, text, by=By.CSS_SELECTOR,2837 timeout=None, retry=False):2838 """ Same as self.update_text() """2839 if not timeout:2840 timeout = settings.LARGE_TIMEOUT2841 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2842 timeout = self.__get_new_timeout(timeout)2843 selector, by = self.__recalculate_selector(selector, by)2844 self.update_text(selector, text, by=by, timeout=timeout, retry=retry)2845 def send_keys(self, selector, text, by=By.CSS_SELECTOR, timeout=None):2846 """ Same as self.add_text() """2847 if not timeout:2848 timeout = settings.LARGE_TIMEOUT2849 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2850 timeout = self.__get_new_timeout(timeout)2851 selector, by = self.__recalculate_selector(selector, by)2852 self.add_text(selector, text, by=by, timeout=timeout)2853 def click_link(self, link_text, timeout=None):2854 """ Same as self.click_link_text() """2855 if not timeout:2856 timeout = settings.SMALL_TIMEOUT2857 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:2858 timeout = self.__get_new_timeout(timeout)2859 self.click_link_text(link_text, timeout=timeout)2860 def wait_for_element_visible(self, selector, by=By.CSS_SELECTOR,2861 timeout=None):2862 """ Same as self.wait_for_element() """2863 if not timeout:2864 timeout = settings.LARGE_TIMEOUT2865 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2866 timeout = self.__get_new_timeout(timeout)2867 selector, by = self.__recalculate_selector(selector, by)2868 return page_actions.wait_for_element_visible(2869 self.driver, selector, by, timeout)2870 def wait_for_element_not_present(self, selector, by=By.CSS_SELECTOR,2871 timeout=None):2872 """ Same as self.wait_for_element_absent()2873 Waits for an element to no longer appear in the HTML of a page.2874 A hidden element still counts as appearing in the page HTML.2875 If an element with "hidden" status is acceptable,2876 use wait_for_element_not_visible() instead. """2877 if not timeout:2878 timeout = settings.LARGE_TIMEOUT2879 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:2880 timeout = self.__get_new_timeout(timeout)2881 selector, by = self.__recalculate_selector(selector, by)2882 return page_actions.wait_for_element_absent(2883 self.driver, selector, by, timeout)2884 def assert_element_not_present(self, selector, by=By.CSS_SELECTOR,2885 timeout=None):2886 """ Same as self.assert_element_absent()2887 Will raise an exception if the element stays present.2888 Returns True if successful. Default timeout = SMALL_TIMEOUT. """2889 if not timeout:2890 timeout = settings.SMALL_TIMEOUT2891 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:2892 timeout = self.__get_new_timeout(timeout)2893 self.wait_for_element_absent(selector, by=by, timeout=timeout)2894 return True2895 def assert_no_broken_links(self, multithreaded=True):2896 """ Same as self.assert_no_404_errors() """2897 self.assert_no_404_errors(multithreaded=multithreaded)2898 def wait(self, seconds):2899 """ Same as self.sleep() - Some JS frameworks use this method name. """2900 self.sleep(seconds)2901 def block_ads(self):2902 """ Same as self.ad_block() """2903 self.ad_block()2904 def _print(self, msg):2905 """ Same as Python's print() """2906 print(msg)2907 def start_tour(self, name=None, interval=0):2908 self.play_tour(name=name, interval=interval)2909 ############2910 def add_css_link(self, css_link):2911 js_utils.add_css_link(self.driver, css_link)2912 def add_js_link(self, js_link):2913 js_utils.add_js_link(self.driver, js_link)2914 def add_css_style(self, css_style):2915 js_utils.add_css_style(self.driver, css_style)2916 def add_js_code_from_link(self, js_link):2917 js_utils.add_js_code_from_link(self.driver, js_link)2918 def add_js_code(self, js_code):2919 js_utils.add_js_code(self.driver, js_code)2920 def add_meta_tag(self, http_equiv=None, content=None):2921 js_utils.add_meta_tag(2922 self.driver, http_equiv=http_equiv, content=content)2923 ############2924 def create_presentation(self, name=None, theme="default"):2925 """ Creates a Reveal-JS presentation that you can add slides to.2926 @Params2927 name - If creating multiple presentations at the same time,2928 use this to specify the name of the current presentation.2929 theme - Set a theme with a unique style for the presentation.2930 Valid themes: "serif" (default), "sky", "white", "black",2931 "simple", "league", "moon", "night",2932 "beige", "blood", and "solarized".2933 """2934 if not name:2935 name = "default"2936 if not theme or theme == "default":2937 theme = "serif"2938 valid_themes = (["serif", "white", "black", "beige", "simple", "sky",2939 "league", "moon", "night", "blood", "solarized"])2940 theme = theme.lower()2941 if theme not in valid_themes:2942 raise Exception(2943 "Theme {%s} not found! Valid themes: %s"2944 "" % (theme, valid_themes))2945 reveal_theme_css = None2946 if theme == "serif":2947 reveal_theme_css = constants.Reveal.SERIF_MIN_CSS2948 elif theme == "sky":2949 reveal_theme_css = constants.Reveal.SKY_MIN_CSS2950 elif theme == "white":2951 reveal_theme_css = constants.Reveal.WHITE_MIN_CSS2952 elif theme == "black":2953 reveal_theme_css = constants.Reveal.BLACK_MIN_CSS2954 elif theme == "simple":2955 reveal_theme_css = constants.Reveal.SIMPLE_MIN_CSS2956 elif theme == "league":2957 reveal_theme_css = constants.Reveal.LEAGUE_MIN_CSS2958 elif theme == "moon":2959 reveal_theme_css = constants.Reveal.MOON_MIN_CSS2960 elif theme == "night":2961 reveal_theme_css = constants.Reveal.NIGHT_MIN_CSS2962 elif theme == "beige":2963 reveal_theme_css = constants.Reveal.BEIGE_MIN_CSS2964 elif theme == "blood":2965 reveal_theme_css = constants.Reveal.BLOOD_MIN_CSS2966 elif theme == "solarized":2967 reveal_theme_css = constants.Reveal.SOLARIZED_MIN_CSS2968 else:2969 # Use the default if unable to determine the theme2970 reveal_theme_css = constants.Reveal.SERIF_MIN_CSS2971 new_presentation = (2972 '<html>\n'2973 '<head>\n'2974 '<link rel="stylesheet" href="%s">\n'2975 '<link rel="stylesheet" href="%s">\n'2976 '<style>\n'2977 'pre{background-color:#fbe8d4;border-radius:8px;}\n'2978 'div[flex_div]{height:75vh;margin:0;align-items:center;'2979 'justify-content:center;}\n'2980 'img[rounded]{border-radius:16px;max-width:82%%;}\n'2981 '</style>\n'2982 '</head>\n\n'2983 '<body>\n'2984 '<div class="reveal">\n'2985 '<div class="slides">\n'2986 '' % (constants.Reveal.MIN_CSS, reveal_theme_css))2987 self._presentation_slides[name] = []2988 self._presentation_slides[name].append(new_presentation)2989 def add_slide(self, content=None, image=None, code=None, iframe=None,2990 content2=None, notes=None, name=None):2991 """ Allows the user to add slides to a presentation.2992 @Params2993 content - The HTML content to display on the presentation slide.2994 image - Attach an image (from a URL link) to the slide.2995 code - Attach code of any programming language to the slide.2996 Language-detection will be used to add syntax formatting.2997 iframe - Attach an iFrame (from a URL link) to the slide.2998 content2 - HTML content to display after adding an image or code.2999 notes - Additional notes to include with the slide.3000 ONLY SEEN if show_notes is set for the presentation.3001 name - If creating multiple presentations at the same time,3002 use this to select the presentation to add slides to.3003 """3004 if not name:3005 name = "default"3006 if name not in self._presentation_slides:3007 # Create a presentation if it doesn't already exist3008 self.create_presentation(name=name)3009 if not content:3010 content = ""3011 if not content2:3012 content2 = ""3013 if not notes:3014 notes = ""3015 add_line = ""3016 if content.startswith("<"):3017 add_line = "\n"3018 html = ('\n<section data-transition="none">%s%s' % (add_line, content))3019 if image:3020 html += '\n<div flex_div><img rounded src="%s"></div>' % image3021 if code:3022 html += '\n<div></div>'3023 html += '\n<pre class="prettyprint">\n%s</pre>' % code3024 if iframe:3025 html += ('\n<div></div>'3026 '\n<iframe src="%s" style="width:92%%;height:550;'3027 'title="iframe content"></iframe>' % iframe)3028 add_line = ""3029 if content2.startswith("<"):3030 add_line = "\n"3031 if content2:3032 html += '%s%s' % (add_line, content2)3033 html += '\n<aside class="notes">%s</aside>' % notes3034 html += '\n</section>\n'3035 self._presentation_slides[name].append(html)3036 def save_presentation(3037 self, name=None, filename=None, show_notes=True, interval=0):3038 """ Saves a Reveal-JS Presentation to a file for later use.3039 @Params3040 name - If creating multiple presentations at the same time,3041 use this to select the one you wish to add slides to.3042 filename - The name of the HTML file that you wish to3043 save the presentation to. (filename must end in ".html")3044 show_notes - When set to True, the Notes feature becomes enabled,3045 which allows presenters to see notes next to slides.3046 interval - The delay time between autoplaying slides. (in seconds)3047 If set to 0 (default), autoplay is disabled.3048 """3049 if not name:3050 name = "default"3051 if not filename:3052 filename = "my_presentation.html"3053 if name not in self._presentation_slides:3054 raise Exception("Presentation {%s} does not exist!" % name)3055 if not filename.endswith('.html'):3056 raise Exception('Presentation file must end in ".html"!')3057 if not interval:3058 interval = 03059 if not type(interval) is int and not type(interval) is float:3060 raise Exception('Expecting a numeric value for "interval"!')3061 if interval < 0:3062 raise Exception('The "interval" cannot be a negative number!')3063 interval_ms = float(interval) * 1000.03064 show_notes_str = "false"3065 if show_notes:3066 show_notes_str = "true"3067 the_html = ""3068 for slide in self._presentation_slides[name]:3069 the_html += slide3070 the_html += (3071 '\n</div>\n'3072 '</div>\n'3073 '<script src="%s"></script>\n'3074 '<script src="%s"></script>\n'3075 '<script>Reveal.initialize('3076 '{showNotes: %s, slideNumber: true, '3077 'autoSlide: %s,});'3078 '</script>\n'3079 '</body>\n'3080 '</html>\n'3081 '' % (constants.Reveal.MIN_JS,3082 constants.PrettifyJS.RUN_PRETTIFY_JS,3083 show_notes_str,3084 interval_ms))3085 saved_presentations_folder = constants.Presentations.SAVED_FOLDER3086 if saved_presentations_folder.endswith("/"):3087 saved_presentations_folder = saved_presentations_folder[:-1]3088 if not os.path.exists(saved_presentations_folder):3089 try:3090 os.makedirs(saved_presentations_folder)3091 except Exception:3092 pass3093 file_path = saved_presentations_folder + "/" + filename3094 out_file = codecs.open(file_path, "w+")3095 out_file.writelines(the_html)3096 out_file.close()3097 print('\n>>> [%s] was saved!\n' % file_path)3098 return file_path3099 def begin_presentation(3100 self, name=None, filename=None, show_notes=True, interval=0):3101 """ Begin a Reveal-JS Presentation in the web browser.3102 @Params3103 name - If creating multiple presentations at the same time,3104 use this to select the one you wish to add slides to.3105 filename - The name of the HTML file that you wish to3106 save the presentation to. (filename must end in ".html")3107 show_notes - When set to True, the Notes feature becomes enabled,3108 which allows presenters to see notes next to slides.3109 interval - The delay time between autoplaying slides. (in seconds)3110 If set to 0 (default), autoplay is disabled.3111 """3112 if self.headless:3113 return # Presentations should not run in headless mode.3114 if not name:3115 name = "default"3116 if not filename:3117 filename = "my_presentation.html"3118 if name not in self._presentation_slides:3119 raise Exception("Presentation {%s} does not exist!" % name)3120 if not filename.endswith('.html'):3121 raise Exception('Presentation file must end in ".html"!')3122 if not interval:3123 interval = 03124 if not type(interval) is int and not type(interval) is float:3125 raise Exception('Expecting a numeric value for "interval"!')3126 if interval < 0:3127 raise Exception('The "interval" cannot be a negative number!')3128 end_slide = (3129 '\n<section data-transition="none">\n'3130 '<p class="End_Presentation_Now"> </p>\n</section>\n')3131 self._presentation_slides[name].append(end_slide)3132 file_path = self.save_presentation(3133 name=name, filename=filename,3134 show_notes=show_notes, interval=interval)3135 self._presentation_slides[name].pop()3136 self.open_html_file(file_path)3137 presentation_folder = constants.Presentations.SAVED_FOLDER3138 try:3139 while (len(self.driver.window_handles) > 0 and (3140 presentation_folder in self.get_current_url())):3141 time.sleep(0.05)3142 if self.is_element_visible(3143 "section.present p.End_Presentation_Now"):3144 break3145 time.sleep(0.05)3146 except Exception:3147 pass3148 ############3149 def create_tour(self, name=None, theme=None):3150 """ Creates a tour for a website. By default, the Shepherd JavaScript3151 Library is used with the Shepherd "Light" / "Arrows" theme.3152 @Params3153 name - If creating multiple tours at the same time,3154 use this to select the tour you wish to add steps to.3155 theme - Sets the default theme for the tour.3156 Choose from "light"/"arrows", "dark", "default", "square",3157 and "square-dark". ("arrows" is used if None is selected.)3158 Alternatively, you may use a different JavaScript Library3159 as the theme. Those include "IntroJS", "DriverJS",3160 "Hopscotch", and "Bootstrap".3161 """3162 if not name:3163 name = "default"3164 if theme:3165 if theme.lower() == "bootstrap":3166 self.create_bootstrap_tour(name)3167 return3168 elif theme.lower() == "hopscotch":3169 self.create_hopscotch_tour(name)3170 return3171 elif theme.lower() == "intro":3172 self.create_introjs_tour(name)3173 return3174 elif theme.lower() == "introjs":3175 self.create_introjs_tour(name)3176 return3177 elif theme.lower() == "driver":3178 self.create_driverjs_tour(name)3179 return3180 elif theme.lower() == "driverjs":3181 self.create_driverjs_tour(name)3182 return3183 elif theme.lower() == "shepherd":3184 self.create_shepherd_tour(name, theme="light")3185 return3186 else:3187 self.create_shepherd_tour(name, theme)3188 else:3189 self.create_shepherd_tour(name, theme="light")3190 def create_shepherd_tour(self, name=None, theme=None):3191 """ Creates a Shepherd JS website tour.3192 @Params3193 name - If creating multiple tours at the same time,3194 use this to select the tour you wish to add steps to.3195 theme - Sets the default theme for the tour.3196 Choose from "light"/"arrows", "dark", "default", "square",3197 and "square-dark". ("light" is used if None is selected.)3198 """3199 shepherd_theme = "shepherd-theme-arrows"3200 if theme:3201 if theme.lower() == "default":3202 shepherd_theme = "shepherd-theme-default"3203 elif theme.lower() == "dark":3204 shepherd_theme = "shepherd-theme-dark"3205 elif theme.lower() == "light":3206 shepherd_theme = "shepherd-theme-arrows"3207 elif theme.lower() == "arrows":3208 shepherd_theme = "shepherd-theme-arrows"3209 elif theme.lower() == "square":3210 shepherd_theme = "shepherd-theme-square"3211 elif theme.lower() == "square-dark":3212 shepherd_theme = "shepherd-theme-square-dark"3213 if not name:3214 name = "default"3215 new_tour = (3216 """3217 // Shepherd Tour3218 var tour = new Shepherd.Tour({3219 defaults: {3220 classes: '%s',3221 scrollTo: true3222 }3223 });3224 var allButtons = {3225 skip: {3226 text: "Skip",3227 action: tour.cancel,3228 classes: 'shepherd-button-secondary tour-button-left'3229 },3230 back: {3231 text: "Back",3232 action: tour.back,3233 classes: 'shepherd-button-secondary'3234 },3235 next: {3236 text: "Next",3237 action: tour.next,3238 classes: 'shepherd-button-primary tour-button-right'3239 },3240 };3241 var firstStepButtons = [allButtons.skip, allButtons.next];3242 var midTourButtons = [allButtons.back, allButtons.next];3243 """ % shepherd_theme)3244 self._tour_steps[name] = []3245 self._tour_steps[name].append(new_tour)3246 def create_bootstrap_tour(self, name=None):3247 """ Creates a Bootstrap tour for a website.3248 @Params3249 name - If creating multiple tours at the same time,3250 use this to select the tour you wish to add steps to.3251 """3252 if not name:3253 name = "default"3254 new_tour = (3255 """3256 // Bootstrap Tour3257 var tour = new Tour({3258 });3259 tour.addSteps([3260 """)3261 self._tour_steps[name] = []3262 self._tour_steps[name].append(new_tour)3263 def create_driverjs_tour(self, name=None):3264 """ Creates a DriverJS tour for a website.3265 @Params3266 name - If creating multiple tours at the same time,3267 use this to select the tour you wish to add steps to.3268 """3269 if not name:3270 name = "default"3271 new_tour = (3272 """3273 // DriverJS Tour3274 var tour = new Driver({3275 opacity: 0.24, // Background opacity (0: no popover / overlay)3276 padding: 6, // Distance of element from around the edges3277 allowClose: false, // Whether clicking on overlay should close3278 overlayClickNext: false, // Move to next step on overlay click3279 doneBtnText: 'Done', // Text that appears on the Done button3280 closeBtnText: 'Close', // Text appearing on the Close button3281 nextBtnText: 'Next', // Text that appears on the Next button3282 prevBtnText: 'Previous', // Text appearing on Previous button3283 showButtons: true, // This shows control buttons in the footer3284 keyboardControl: true, // (escape to close, arrow keys to move)3285 animate: true, // Animate while changing highlighted element3286 });3287 tour.defineSteps([3288 """)3289 self._tour_steps[name] = []3290 self._tour_steps[name].append(new_tour)3291 def create_hopscotch_tour(self, name=None):3292 """ Creates a Hopscotch tour for a website.3293 @Params3294 name - If creating multiple tours at the same time,3295 use this to select the tour you wish to add steps to.3296 """3297 if not name:3298 name = "default"3299 new_tour = (3300 """3301 // Hopscotch Tour3302 var tour = {3303 id: "hopscotch_tour",3304 steps: [3305 """)3306 self._tour_steps[name] = []3307 self._tour_steps[name].append(new_tour)3308 def create_introjs_tour(self, name=None):3309 """ Creates an IntroJS tour for a website.3310 @Params3311 name - If creating multiple tours at the same time,3312 use this to select the tour you wish to add steps to.3313 """3314 if not name:3315 name = "default"3316 new_tour = (3317 """3318 // IntroJS Tour3319 function startIntro(){3320 var intro = introJs();3321 intro.setOptions({3322 steps: [3323 """)3324 self._tour_steps[name] = []3325 self._tour_steps[name].append(new_tour)3326 def add_tour_step(self, message, selector=None, name=None,3327 title=None, theme=None, alignment=None, duration=None):3328 """ Allows the user to add tour steps for a website.3329 @Params3330 message - The message to display.3331 selector - The CSS Selector of the Element to attach to.3332 name - If creating multiple tours at the same time,3333 use this to select the tour you wish to add steps to.3334 title - Additional header text that appears above the message.3335 theme - (NON-Bootstrap Tours ONLY) The styling of the tour step.3336 Choose from "light"/"arrows", "dark", "default", "square",3337 and "square-dark". ("arrows" is used if None is selected.)3338 alignment - Choose from "top", "bottom", "left", and "right".3339 ("top" is default, except for Hopscotch and DriverJS).3340 duration - (Bootstrap Tours ONLY) The amount of time, in seconds,3341 before automatically advancing to the next tour step.3342 """3343 if not selector:3344 selector = "html"3345 if page_utils.is_name_selector(selector):3346 name = page_utils.get_name_from_selector(selector)3347 selector = '[name="%s"]' % name3348 if page_utils.is_xpath_selector(selector):3349 selector = self.convert_to_css_selector(selector, By.XPATH)3350 selector = self.__escape_quotes_if_needed(selector)3351 if not name:3352 name = "default"3353 if name not in self._tour_steps:3354 # By default, will create an IntroJS tour if no tours exist3355 self.create_tour(name=name, theme="introjs")3356 if not title:3357 title = ""3358 title = self.__escape_quotes_if_needed(title)3359 if message:3360 message = self.__escape_quotes_if_needed(message)3361 else:3362 message = ""3363 if not alignment or (3364 alignment not in ["top", "bottom", "left", "right"]):3365 t_name = self._tour_steps[name][0]3366 if "Hopscotch" not in t_name and "DriverJS" not in t_name:3367 alignment = "top"3368 else:3369 alignment = "bottom"3370 if "Bootstrap" in self._tour_steps[name][0]:3371 self.__add_bootstrap_tour_step(3372 message, selector=selector, name=name, title=title,3373 alignment=alignment, duration=duration)3374 elif "DriverJS" in self._tour_steps[name][0]:3375 self.__add_driverjs_tour_step(3376 message, selector=selector, name=name, title=title,3377 alignment=alignment)3378 elif "Hopscotch" in self._tour_steps[name][0]:3379 self.__add_hopscotch_tour_step(3380 message, selector=selector, name=name, title=title,3381 alignment=alignment)3382 elif "IntroJS" in self._tour_steps[name][0]:3383 self.__add_introjs_tour_step(3384 message, selector=selector, name=name, title=title,3385 alignment=alignment)3386 else:3387 self.__add_shepherd_tour_step(3388 message, selector=selector, name=name, title=title,3389 theme=theme, alignment=alignment)3390 def __add_shepherd_tour_step(self, message, selector=None, name=None,3391 title=None, theme=None, alignment=None):3392 """ Allows the user to add tour steps for a website.3393 @Params3394 message - The message to display.3395 selector - The CSS Selector of the Element to attach to.3396 name - If creating multiple tours at the same time,3397 use this to select the tour you wish to add steps to.3398 title - Additional header text that appears above the message.3399 theme - (NON-Bootstrap Tours ONLY) The styling of the tour step.3400 Choose from "light"/"arrows", "dark", "default", "square",3401 and "square-dark". ("arrows" is used if None is selected.)3402 alignment - Choose from "top", "bottom", "left", and "right".3403 ("top" is the default alignment).3404 """3405 if theme == "default":3406 shepherd_theme = "shepherd-theme-default"3407 elif theme == "dark":3408 shepherd_theme = "shepherd-theme-dark"3409 elif theme == "light":3410 shepherd_theme = "shepherd-theme-arrows"3411 elif theme == "arrows":3412 shepherd_theme = "shepherd-theme-arrows"3413 elif theme == "square":3414 shepherd_theme = "shepherd-theme-square"3415 elif theme == "square-dark":3416 shepherd_theme = "shepherd-theme-square-dark"3417 else:3418 shepherd_base_theme = re.search(3419 r"[\S\s]+classes: '([\S\s]+)',[\S\s]+",3420 self._tour_steps[name][0]).group(1)3421 shepherd_theme = shepherd_base_theme3422 shepherd_classes = shepherd_theme3423 if selector == "html":3424 shepherd_classes += " shepherd-orphan"3425 buttons = "firstStepButtons"3426 if len(self._tour_steps[name]) > 1:3427 buttons = "midTourButtons"3428 step = ("""3429 tour.addStep('%s', {3430 title: '%s',3431 classes: '%s',3432 text: '%s',3433 attachTo: {element: '%s', on: '%s'},3434 buttons: %s,3435 advanceOn: '.docs-link click'3436 });""" % (3437 name, title, shepherd_classes, message, selector, alignment,3438 buttons))3439 self._tour_steps[name].append(step)3440 def __add_bootstrap_tour_step(self, message, selector=None, name=None,3441 title=None, alignment=None, duration=None):3442 """ Allows the user to add tour steps for a website.3443 @Params3444 message - The message to display.3445 selector - The CSS Selector of the Element to attach to.3446 name - If creating multiple tours at the same time,3447 use this to select the tour you wish to add steps to.3448 title - Additional header text that appears above the message.3449 alignment - Choose from "top", "bottom", "left", and "right".3450 ("top" is the default alignment).3451 duration - (Bootstrap Tours ONLY) The amount of time, in seconds,3452 before automatically advancing to the next tour step.3453 """3454 if selector != "html":3455 selector = self.__make_css_match_first_element_only(selector)3456 element_row = "element: '%s'," % selector3457 else:3458 element_row = ""3459 if not duration:3460 duration = "0"3461 else:3462 duration = str(float(duration) * 1000.0)3463 step = ("""{3464 %s3465 title: '%s',3466 content: '%s',3467 orphan: true,3468 placement: 'auto %s',3469 smartPlacement: true,3470 duration: %s,3471 },""" % (element_row, title, message, alignment, duration))3472 self._tour_steps[name].append(step)3473 def __add_driverjs_tour_step(self, message, selector=None, name=None,3474 title=None, alignment=None):3475 """ Allows the user to add tour steps for a website.3476 @Params3477 message - The message to display.3478 selector - The CSS Selector of the Element to attach to.3479 name - If creating multiple tours at the same time,3480 use this to select the tour you wish to add steps to.3481 title - Additional header text that appears above the message.3482 alignment - Choose from "top", "bottom", "left", and "right".3483 ("top" is the default alignment).3484 """3485 message = (3486 '<font size=\"3\" color=\"#33477B\"><b>' + message + '</b></font>')3487 title_row = ""3488 if not title:3489 title_row = "title: '%s'," % message3490 message = ""3491 else:3492 title_row = "title: '%s'," % title3493 align_row = "position: '%s'," % alignment3494 ani_row = "animate: true,"3495 if not selector or selector == "html" or selector == "body":3496 selector = "body"3497 ani_row = "animate: false,"3498 align_row = "position: '%s'," % "mid-center"3499 element_row = "element: '%s'," % selector3500 desc_row = "description: '%s'," % message3501 step = ("""{3502 %s3503 %s3504 popover: {3505 className: 'popover-class',3506 %s3507 %s3508 %s3509 }3510 },""" % (element_row, ani_row, title_row, desc_row, align_row))3511 self._tour_steps[name].append(step)3512 def __add_hopscotch_tour_step(self, message, selector=None, name=None,3513 title=None, alignment=None):3514 """ Allows the user to add tour steps for a website.3515 @Params3516 message - The message to display.3517 selector - The CSS Selector of the Element to attach to.3518 name - If creating multiple tours at the same time,3519 use this to select the tour you wish to add steps to.3520 title - Additional header text that appears above the message.3521 alignment - Choose from "top", "bottom", "left", and "right".3522 ("bottom" is the default alignment).3523 """3524 arrow_offset_row = None3525 if not selector or selector == "html":3526 selector = "head"3527 alignment = "bottom"3528 arrow_offset_row = "arrowOffset: '200',"3529 else:3530 arrow_offset_row = ""3531 step = ("""{3532 target: '%s',3533 title: '%s',3534 content: '%s',3535 %s3536 showPrevButton: 'true',3537 scrollDuration: '550',3538 placement: '%s'},3539 """ % (selector, title, message, arrow_offset_row, alignment))3540 self._tour_steps[name].append(step)3541 def __add_introjs_tour_step(self, message, selector=None, name=None,3542 title=None, alignment=None):3543 """ Allows the user to add tour steps for a website.3544 @Params3545 message - The message to display.3546 selector - The CSS Selector of the Element to attach to.3547 name - If creating multiple tours at the same time,3548 use this to select the tour you wish to add steps to.3549 title - Additional header text that appears above the message.3550 alignment - Choose from "top", "bottom", "left", and "right".3551 ("top" is the default alignment).3552 """3553 if selector != "html":3554 element_row = "element: '%s'," % selector3555 else:3556 element_row = ""3557 if title:3558 message = "<center><b>" + title + "</b></center><hr>" + message3559 message = '<font size=\"3\" color=\"#33477B\">' + message + '</font>'3560 step = ("""{%s3561 intro: '%s',3562 position: '%s'},3563 """ % (element_row, message, alignment))3564 self._tour_steps[name].append(step)3565 def play_tour(self, name=None, interval=0):3566 """ Plays a tour on the current website.3567 @Params3568 name - If creating multiple tours at the same time,3569 use this to select the tour you wish to add steps to.3570 interval - The delay time between autoplaying tour steps. (Seconds)3571 If set to 0 (default), the tour is fully manual control.3572 """3573 if self.headless:3574 return # Tours should not run in headless mode.3575 if not name:3576 name = "default"3577 if name not in self._tour_steps:3578 raise Exception("Tour {%s} does not exist!" % name)3579 if "Bootstrap" in self._tour_steps[name][0]:3580 tour_helper.play_bootstrap_tour(3581 self.driver, self._tour_steps, self.browser,3582 self.message_duration, name=name, interval=interval)3583 elif "DriverJS" in self._tour_steps[name][0]:3584 tour_helper.play_driverjs_tour(3585 self.driver, self._tour_steps, self.browser,3586 self.message_duration, name=name, interval=interval)3587 elif "Hopscotch" in self._tour_steps[name][0]:3588 tour_helper.play_hopscotch_tour(3589 self.driver, self._tour_steps, self.browser,3590 self.message_duration, name=name, interval=interval)3591 elif "IntroJS" in self._tour_steps[name][0]:3592 tour_helper.play_introjs_tour(3593 self.driver, self._tour_steps, self.browser,3594 self.message_duration, name=name, interval=interval)3595 else:3596 # "Shepherd"3597 tour_helper.play_shepherd_tour(3598 self.driver, self._tour_steps,3599 self.message_duration, name=name, interval=interval)3600 def export_tour(self, name=None, filename="my_tour.js", url=None):3601 """ Exports a tour as a JS file.3602 You can call self.export_tour() anywhere where you would3603 normally use self.play_tour() to play a website tour.3604 It will include necessary resources as well, such as jQuery.3605 You'll be able to copy the tour directly into the Console of3606 any web browser to play the tour outside of SeleniumBase runs.3607 @Params3608 name - If creating multiple tours at the same time,3609 use this to select the tour you wish to add steps to.3610 filename - The name of the JavaScript file that you wish to3611 save the tour to.3612 url - The URL where the tour starts. If not specified, the URL3613 of the current page will be used. """3614 if not url:3615 url = self.get_current_url()3616 tour_helper.export_tour(3617 self._tour_steps, name=name, filename=filename, url=url)3618 def activate_jquery_confirm(self):3619 """ See https://craftpip.github.io/jquery-confirm/ for usage. """3620 js_utils.activate_jquery_confirm(self.driver)3621 self.wait_for_ready_state_complete()3622 def activate_messenger(self):3623 js_utils.activate_messenger(self.driver)3624 self.wait_for_ready_state_complete()3625 def set_messenger_theme(self, theme="default", location="default",3626 max_messages="default"):3627 """ Sets a theme for posting messages.3628 Themes: ["flat", "future", "block", "air", "ice"]3629 Locations: ["top_left", "top_center", "top_right",3630 "bottom_left", "bottom_center", "bottom_right"]3631 max_messages is the limit of concurrent messages to display. """3632 if not theme:3633 theme = "default" # "future"3634 if not location:3635 location = "default" # "bottom_right"3636 if not max_messages:3637 max_messages = "default" # "8"3638 else:3639 max_messages = str(max_messages) # Value must be in string format3640 js_utils.set_messenger_theme(3641 self.driver, theme=theme,3642 location=location, max_messages=max_messages)3643 def post_message(self, message, duration=None, pause=True, style="info"):3644 """ Post a message on the screen with Messenger.3645 Arguments:3646 message: The message to display.3647 duration: The time until the message vanishes. (Default: 2.55s)3648 pause: If True, the program waits until the message completes.3649 style: "info", "success", or "error".3650 You can also post messages by using =>3651 self.execute_script('Messenger().post("My Message")')3652 """3653 if not duration:3654 if not self.message_duration:3655 duration = settings.DEFAULT_MESSAGE_DURATION3656 else:3657 duration = self.message_duration3658 js_utils.post_message(3659 self.driver, message, duration, style=style)3660 if pause:3661 duration = float(duration) + 0.153662 time.sleep(float(duration))3663 def post_success_message(self, message, duration=None, pause=True):3664 """ Post a success message on the screen with Messenger.3665 Arguments:3666 message: The success message to display.3667 duration: The time until the message vanishes. (Default: 2.55s)3668 pause: If True, the program waits until the message completes.3669 """3670 if not duration:3671 if not self.message_duration:3672 duration = settings.DEFAULT_MESSAGE_DURATION3673 else:3674 duration = self.message_duration3675 js_utils.post_message(3676 self.driver, message, duration, style="success")3677 if pause:3678 duration = float(duration) + 0.153679 time.sleep(float(duration))3680 def post_error_message(self, message, duration=None, pause=True):3681 """ Post an error message on the screen with Messenger.3682 Arguments:3683 message: The error message to display.3684 duration: The time until the message vanishes. (Default: 2.55s)3685 pause: If True, the program waits until the message completes.3686 """3687 if not duration:3688 if not self.message_duration:3689 duration = settings.DEFAULT_MESSAGE_DURATION3690 else:3691 duration = self.message_duration3692 js_utils.post_message(3693 self.driver, message, duration, style="error")3694 if pause:3695 duration = float(duration) + 0.153696 time.sleep(float(duration))3697 ############3698 def generate_referral(self, start_page, destination_page):3699 """ This method opens the start_page, creates a referral link there,3700 and clicks on that link, which goes to the destination_page.3701 (This generates real traffic for testing analytics software.) """3702 if not page_utils.is_valid_url(destination_page):3703 raise Exception(3704 "Exception: destination_page {%s} is not a valid URL!"3705 % destination_page)3706 if start_page:3707 if not page_utils.is_valid_url(start_page):3708 raise Exception(3709 "Exception: start_page {%s} is not a valid URL! "3710 "(Use an empty string or None to start from current page.)"3711 % start_page)3712 self.open(start_page)3713 time.sleep(0.08)3714 self.wait_for_ready_state_complete()3715 referral_link = ('''<body>'''3716 '''<a class='analytics referral test' href='%s' '''3717 '''style='font-family: Arial,sans-serif; '''3718 '''font-size: 30px; color: #18a2cd'>'''3719 '''Magic Link Button</a></body>''' % destination_page)3720 self.execute_script(3721 '''document.body.outerHTML = \"%s\"''' % referral_link)3722 self.click(3723 "a.analytics.referral.test", timeout=2) # Clicks generated button3724 time.sleep(0.15)3725 try:3726 self.click("html")3727 time.sleep(0.08)3728 except Exception:3729 pass3730 def generate_traffic(self, start_page, destination_page, loops=1):3731 """ Similar to generate_referral(), but can do multiple loops. """3732 for loop in range(loops):3733 self.generate_referral(start_page, destination_page)3734 time.sleep(0.05)3735 def generate_referral_chain(self, pages):3736 """ Use this method to chain the action of creating button links on3737 one website page that will take you to the next page.3738 (When you want to create a referral to a website for traffic3739 generation without increasing the bounce rate, you'll want to visit3740 at least one additional page on that site with a button click.) """3741 if not type(pages) is tuple and not type(pages) is list:3742 raise Exception(3743 "Exception: Expecting a list of website pages for chaining!")3744 if len(pages) < 2:3745 raise Exception(3746 "Exception: At least two website pages required for chaining!")3747 for page in pages:3748 # Find out if any of the web pages are invalid before continuing3749 if not page_utils.is_valid_url(page):3750 raise Exception(3751 "Exception: Website page {%s} is not a valid URL!" % page)3752 for page in pages:3753 self.generate_referral(None, page)3754 def generate_traffic_chain(self, pages, loops=1):3755 """ Similar to generate_referral_chain(), but for multiple loops. """3756 for loop in range(loops):3757 self.generate_referral_chain(pages)3758 time.sleep(0.05)3759 ############3760 def wait_for_element_present(self, selector, by=By.CSS_SELECTOR,3761 timeout=None):3762 """ Waits for an element to appear in the HTML of a page.3763 The element does not need be visible (it may be hidden). """3764 if not timeout:3765 timeout = settings.LARGE_TIMEOUT3766 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3767 timeout = self.__get_new_timeout(timeout)3768 selector, by = self.__recalculate_selector(selector, by)3769 return page_actions.wait_for_element_present(3770 self.driver, selector, by, timeout)3771 def wait_for_element(self, selector, by=By.CSS_SELECTOR, timeout=None):3772 """ Waits for an element to appear in the HTML of a page.3773 The element must be visible (it cannot be hidden). """3774 if not timeout:3775 timeout = settings.LARGE_TIMEOUT3776 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3777 timeout = self.__get_new_timeout(timeout)3778 selector, by = self.__recalculate_selector(selector, by)3779 return page_actions.wait_for_element_visible(3780 self.driver, selector, by, timeout)3781 def get_element(self, selector, by=By.CSS_SELECTOR, timeout=None):3782 """ Same as wait_for_element_present() - returns the element.3783 The element does not need be visible (it may be hidden). """3784 if not timeout:3785 timeout = settings.SMALL_TIMEOUT3786 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:3787 timeout = self.__get_new_timeout(timeout)3788 selector, by = self.__recalculate_selector(selector, by)3789 return self.wait_for_element_present(selector, by=by, timeout=timeout)3790 def assert_element_present(self, selector, by=By.CSS_SELECTOR,3791 timeout=None):3792 """ Similar to wait_for_element_present(), but returns nothing.3793 Waits for an element to appear in the HTML of a page.3794 The element does not need be visible (it may be hidden).3795 Returns True if successful. Default timeout = SMALL_TIMEOUT. """3796 if not timeout:3797 timeout = settings.SMALL_TIMEOUT3798 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:3799 timeout = self.__get_new_timeout(timeout)3800 self.wait_for_element_present(selector, by=by, timeout=timeout)3801 return True3802 def find_element(self, selector, by=By.CSS_SELECTOR, timeout=None):3803 """ Same as wait_for_element_visible() - returns the element """3804 if not timeout:3805 timeout = settings.LARGE_TIMEOUT3806 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3807 timeout = self.__get_new_timeout(timeout)3808 return self.wait_for_element_visible(selector, by=by, timeout=timeout)3809 def assert_element(self, selector, by=By.CSS_SELECTOR, timeout=None):3810 """ Similar to wait_for_element_visible(), but returns nothing.3811 As above, will raise an exception if nothing can be found.3812 Returns True if successful. Default timeout = SMALL_TIMEOUT. """3813 if not timeout:3814 timeout = settings.SMALL_TIMEOUT3815 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:3816 timeout = self.__get_new_timeout(timeout)3817 self.wait_for_element_visible(selector, by=by, timeout=timeout)3818 if self.demo_mode:3819 selector, by = self.__recalculate_selector(selector, by)3820 a_t = "ASSERT"3821 if self._language != "English":3822 from seleniumbase.fixtures.words import SD3823 a_t = SD.translate_assert(self._language)3824 messenger_post = "%s %s: %s" % (a_t, by.upper(), selector)3825 self.__highlight_with_assert_success(messenger_post, selector, by)3826 return True3827 def assert_element_visible(self, selector, by=By.CSS_SELECTOR,3828 timeout=None):3829 """ Same as self.assert_element()3830 As above, will raise an exception if nothing can be found. """3831 if not timeout:3832 timeout = settings.SMALL_TIMEOUT3833 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:3834 timeout = self.__get_new_timeout(timeout)3835 self.assert_element(selector, by=by, timeout=timeout)3836 return True3837 ############3838 def wait_for_text_visible(self, text, selector="html", by=By.CSS_SELECTOR,3839 timeout=None):3840 if not timeout:3841 timeout = settings.LARGE_TIMEOUT3842 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3843 timeout = self.__get_new_timeout(timeout)3844 selector, by = self.__recalculate_selector(selector, by)3845 return page_actions.wait_for_text_visible(3846 self.driver, text, selector, by, timeout)3847 def wait_for_exact_text_visible(self, text, selector="html",3848 by=By.CSS_SELECTOR,3849 timeout=None):3850 if not timeout:3851 timeout = settings.LARGE_TIMEOUT3852 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3853 timeout = self.__get_new_timeout(timeout)3854 selector, by = self.__recalculate_selector(selector, by)3855 return page_actions.wait_for_exact_text_visible(3856 self.driver, text, selector, by, timeout)3857 def wait_for_text(self, text, selector="html", by=By.CSS_SELECTOR,3858 timeout=None):3859 """ The shorter version of wait_for_text_visible() """3860 if not timeout:3861 timeout = settings.LARGE_TIMEOUT3862 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3863 timeout = self.__get_new_timeout(timeout)3864 return self.wait_for_text_visible(3865 text, selector, by=by, timeout=timeout)3866 def find_text(self, text, selector="html", by=By.CSS_SELECTOR,3867 timeout=None):3868 """ Same as wait_for_text_visible() - returns the element """3869 if not timeout:3870 timeout = settings.LARGE_TIMEOUT3871 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3872 timeout = self.__get_new_timeout(timeout)3873 return self.wait_for_text_visible(3874 text, selector, by=by, timeout=timeout)3875 def assert_text_visible(self, text, selector="html", by=By.CSS_SELECTOR,3876 timeout=None):3877 """ Same as assert_text() """3878 if not timeout:3879 timeout = settings.SMALL_TIMEOUT3880 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:3881 timeout = self.__get_new_timeout(timeout)3882 return self.assert_text(text, selector, by=by, timeout=timeout)3883 def assert_text(self, text, selector="html", by=By.CSS_SELECTOR,3884 timeout=None):3885 """ Similar to wait_for_text_visible()3886 Raises an exception if the element or the text is not found.3887 Returns True if successful. Default timeout = SMALL_TIMEOUT. """3888 if not timeout:3889 timeout = settings.SMALL_TIMEOUT3890 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:3891 timeout = self.__get_new_timeout(timeout)3892 self.wait_for_text_visible(text, selector, by=by, timeout=timeout)3893 if self.demo_mode:3894 selector, by = self.__recalculate_selector(selector, by)3895 a_t = "ASSERT TEXT"3896 i_n = "in"3897 if self._language != "English":3898 from seleniumbase.fixtures.words import SD3899 a_t = SD.translate_assert_text(self._language)3900 i_n = SD.translate_in(self._language)3901 messenger_post = ("%s: {%s} %s %s: %s"3902 % (a_t, text, i_n, by.upper(), selector))3903 self.__highlight_with_assert_success(messenger_post, selector, by)3904 return True3905 def assert_exact_text(self, text, selector="html", by=By.CSS_SELECTOR,3906 timeout=None):3907 """ Similar to assert_text(), but the text must be exact, rather than3908 exist as a subset of the full text.3909 (Extra whitespace at the beginning or the end doesn't count.)3910 Raises an exception if the element or the text is not found.3911 Returns True if successful. Default timeout = SMALL_TIMEOUT. """3912 if not timeout:3913 timeout = settings.SMALL_TIMEOUT3914 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:3915 timeout = self.__get_new_timeout(timeout)3916 self.wait_for_exact_text_visible(3917 text, selector, by=by, timeout=timeout)3918 if self.demo_mode:3919 selector, by = self.__recalculate_selector(selector, by)3920 a_t = "ASSERT EXACT TEXT"3921 i_n = "in"3922 if self._language != "English":3923 from seleniumbase.fixtures.words import SD3924 a_t = SD.translate_assert_exact_text(self._language)3925 i_n = SD.translate_in(self._language)3926 messenger_post = ("%s: {%s} %s %s: %s"3927 % (a_t, text, i_n, by.upper(), selector))3928 self.__highlight_with_assert_success(messenger_post, selector, by)3929 return True3930 ############3931 def wait_for_link_text_present(self, link_text, timeout=None):3932 if not timeout:3933 timeout = settings.SMALL_TIMEOUT3934 start_ms = time.time() * 1000.03935 stop_ms = start_ms + (timeout * 1000.0)3936 for x in range(int(timeout * 5)):3937 shared_utils.check_if_time_limit_exceeded()3938 try:3939 if not self.is_link_text_present(link_text):3940 raise Exception(3941 "Link text {%s} was not found!" % link_text)3942 return3943 except Exception:3944 now_ms = time.time() * 1000.03945 if now_ms >= stop_ms:3946 break3947 time.sleep(0.2)3948 message = (3949 "Link text {%s} was not present after %s seconds!"3950 "" % (link_text, timeout))3951 page_actions.timeout_exception("NoSuchElementException", message)3952 def wait_for_partial_link_text_present(self, link_text, timeout=None):3953 if not timeout:3954 timeout = settings.SMALL_TIMEOUT3955 start_ms = time.time() * 1000.03956 stop_ms = start_ms + (timeout * 1000.0)3957 for x in range(int(timeout * 5)):3958 shared_utils.check_if_time_limit_exceeded()3959 try:3960 if not self.is_partial_link_text_present(link_text):3961 raise Exception(3962 "Partial Link text {%s} was not found!" % link_text)3963 return3964 except Exception:3965 now_ms = time.time() * 1000.03966 if now_ms >= stop_ms:3967 break3968 time.sleep(0.2)3969 message = (3970 "Partial Link text {%s} was not present after %s seconds!"3971 "" % (link_text, timeout))3972 page_actions.timeout_exception("NoSuchElementException", message)3973 def wait_for_link_text_visible(self, link_text, timeout=None):3974 if not timeout:3975 timeout = settings.LARGE_TIMEOUT3976 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3977 timeout = self.__get_new_timeout(timeout)3978 return self.wait_for_element_visible(3979 link_text, by=By.LINK_TEXT, timeout=timeout)3980 def wait_for_link_text(self, link_text, timeout=None):3981 """ The shorter version of wait_for_link_text_visible() """3982 if not timeout:3983 timeout = settings.LARGE_TIMEOUT3984 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3985 timeout = self.__get_new_timeout(timeout)3986 return self.wait_for_link_text_visible(link_text, timeout=timeout)3987 def find_link_text(self, link_text, timeout=None):3988 """ Same as wait_for_link_text_visible() - returns the element """3989 if not timeout:3990 timeout = settings.LARGE_TIMEOUT3991 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:3992 timeout = self.__get_new_timeout(timeout)3993 return self.wait_for_link_text_visible(link_text, timeout=timeout)3994 def assert_link_text(self, link_text, timeout=None):3995 """ Similar to wait_for_link_text_visible(), but returns nothing.3996 As above, will raise an exception if nothing can be found.3997 Returns True if successful. Default timeout = SMALL_TIMEOUT. """3998 if not timeout:3999 timeout = settings.SMALL_TIMEOUT4000 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:4001 timeout = self.__get_new_timeout(timeout)4002 self.wait_for_link_text_visible(link_text, timeout=timeout)4003 if self.demo_mode:4004 a_t = "ASSERT LINK TEXT"4005 if self._language != "English":4006 from seleniumbase.fixtures.words import SD4007 a_t = SD.translate_assert_link_text(self._language)4008 messenger_post = ("%s: {%s}" % (a_t, link_text))4009 self.__highlight_with_assert_success(4010 messenger_post, link_text, by=By.LINK_TEXT)4011 return True4012 def wait_for_partial_link_text(self, partial_link_text, timeout=None):4013 if not timeout:4014 timeout = settings.LARGE_TIMEOUT4015 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:4016 timeout = self.__get_new_timeout(timeout)4017 return self.wait_for_element_visible(4018 partial_link_text, by=By.PARTIAL_LINK_TEXT, timeout=timeout)4019 def find_partial_link_text(self, partial_link_text, timeout=None):4020 """ Same as wait_for_partial_link_text() - returns the element """4021 if not timeout:4022 timeout = settings.LARGE_TIMEOUT4023 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:4024 timeout = self.__get_new_timeout(timeout)4025 return self.wait_for_partial_link_text(4026 partial_link_text, timeout=timeout)4027 def assert_partial_link_text(self, partial_link_text, timeout=None):4028 """ Similar to wait_for_partial_link_text(), but returns nothing.4029 As above, will raise an exception if nothing can be found.4030 Returns True if successful. Default timeout = SMALL_TIMEOUT. """4031 if not timeout:4032 timeout = settings.SMALL_TIMEOUT4033 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:4034 timeout = self.__get_new_timeout(timeout)4035 self.wait_for_partial_link_text(partial_link_text, timeout=timeout)4036 if self.demo_mode:4037 a_t = "ASSERT PARTIAL LINK TEXT"4038 if self._language != "English":4039 from seleniumbase.fixtures.words import SD4040 a_t = SD.translate_assert_link_text(self._language)4041 messenger_post = ("%s: {%s}" % (a_t, partial_link_text))4042 self.__highlight_with_assert_success(4043 messenger_post, partial_link_text, by=By.PARTIAL_LINK_TEXT)4044 return True4045 ############4046 def wait_for_element_absent(self, selector, by=By.CSS_SELECTOR,4047 timeout=None):4048 """ Waits for an element to no longer appear in the HTML of a page.4049 A hidden element still counts as appearing in the page HTML.4050 If an element with "hidden" status is acceptable,4051 use wait_for_element_not_visible() instead. """4052 if not timeout:4053 timeout = settings.LARGE_TIMEOUT4054 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:4055 timeout = self.__get_new_timeout(timeout)4056 selector, by = self.__recalculate_selector(selector, by)4057 return page_actions.wait_for_element_absent(4058 self.driver, selector, by, timeout)4059 def assert_element_absent(self, selector, by=By.CSS_SELECTOR,4060 timeout=None):4061 """ Similar to wait_for_element_absent() - returns nothing.4062 As above, will raise an exception if the element stays present.4063 Returns True if successful. Default timeout = SMALL_TIMEOUT. """4064 if not timeout:4065 timeout = settings.SMALL_TIMEOUT4066 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:4067 timeout = self.__get_new_timeout(timeout)4068 self.wait_for_element_absent(selector, by=by, timeout=timeout)4069 return True4070 ############4071 def wait_for_element_not_visible(self, selector, by=By.CSS_SELECTOR,4072 timeout=None):4073 """ Waits for an element to no longer be visible on a page.4074 The element can be non-existant in the HTML or hidden on the page4075 to qualify as not visible. """4076 if not timeout:4077 timeout = settings.LARGE_TIMEOUT4078 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:4079 timeout = self.__get_new_timeout(timeout)4080 selector, by = self.__recalculate_selector(selector, by)4081 return page_actions.wait_for_element_not_visible(4082 self.driver, selector, by, timeout)4083 def assert_element_not_visible(self, selector, by=By.CSS_SELECTOR,4084 timeout=None):4085 """ Similar to wait_for_element_not_visible() - returns nothing.4086 As above, will raise an exception if the element stays visible.4087 Returns True if successful. Default timeout = SMALL_TIMEOUT. """4088 if not timeout:4089 timeout = settings.SMALL_TIMEOUT4090 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:4091 timeout = self.__get_new_timeout(timeout)4092 self.wait_for_element_not_visible(selector, by=by, timeout=timeout)4093 return True4094 ############4095 def wait_for_text_not_visible(self, text, selector="html",4096 by=By.CSS_SELECTOR,4097 timeout=None):4098 if not timeout:4099 timeout = settings.LARGE_TIMEOUT4100 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:4101 timeout = self.__get_new_timeout(timeout)4102 selector, by = self.__recalculate_selector(selector, by)4103 return page_actions.wait_for_text_not_visible(4104 self.driver, text, selector, by, timeout)4105 def assert_text_not_visible(self, text, selector="html",4106 by=By.CSS_SELECTOR,4107 timeout=None):4108 """ Similar to wait_for_text_not_visible()4109 Raises an exception if the element or the text is not found.4110 Returns True if successful. Default timeout = SMALL_TIMEOUT. """4111 if not timeout:4112 timeout = settings.SMALL_TIMEOUT4113 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:4114 timeout = self.__get_new_timeout(timeout)4115 self.wait_for_text_not_visible(text, selector, by=by, timeout=timeout)4116 ############4117 def wait_for_and_accept_alert(self, timeout=None):4118 if not timeout:4119 timeout = settings.LARGE_TIMEOUT4120 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:4121 timeout = self.__get_new_timeout(timeout)4122 return page_actions.wait_for_and_accept_alert(self.driver, timeout)4123 def wait_for_and_dismiss_alert(self, timeout=None):4124 if not timeout:4125 timeout = settings.LARGE_TIMEOUT4126 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:4127 timeout = self.__get_new_timeout(timeout)4128 return page_actions.wait_for_and_dismiss_alert(self.driver, timeout)4129 def wait_for_and_switch_to_alert(self, timeout=None):4130 if not timeout:4131 timeout = settings.LARGE_TIMEOUT4132 if self.timeout_multiplier and timeout == settings.LARGE_TIMEOUT:4133 timeout = self.__get_new_timeout(timeout)4134 return page_actions.wait_for_and_switch_to_alert(self.driver, timeout)4135 ############4136 def accept_alert(self, timeout=None):4137 """ Same as wait_for_and_accept_alert(), but smaller default T_O """4138 if not timeout:4139 timeout = settings.SMALL_TIMEOUT4140 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:4141 timeout = self.__get_new_timeout(timeout)4142 return page_actions.wait_for_and_accept_alert(self.driver, timeout)4143 def dismiss_alert(self, timeout=None):4144 """ Same as wait_for_and_dismiss_alert(), but smaller default T_O """4145 if not timeout:4146 timeout = settings.SMALL_TIMEOUT4147 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:4148 timeout = self.__get_new_timeout(timeout)4149 return page_actions.wait_for_and_dismiss_alert(self.driver, timeout)4150 def switch_to_alert(self, timeout=None):4151 """ Same as wait_for_and_switch_to_alert(), but smaller default T_O """4152 if not timeout:4153 timeout = settings.SMALL_TIMEOUT4154 if self.timeout_multiplier and timeout == settings.SMALL_TIMEOUT:4155 timeout = self.__get_new_timeout(timeout)4156 return page_actions.wait_for_and_switch_to_alert(self.driver, timeout)4157 ############4158 def __assert_eq(self, *args, **kwargs):4159 """ Minified assert_equal() using only the list diff. """4160 minified_exception = None4161 try:4162 self.assertEqual(*args, **kwargs)4163 except Exception as e:4164 str_e = str(e)4165 minified_exception = "\nAssertionError:\n"4166 lines = str_e.split('\n')4167 countdown = 34168 countdown_on = False4169 for line in lines:4170 if countdown_on:4171 minified_exception += line + '\n'4172 countdown = countdown - 14173 if countdown == 0:4174 countdown_on = False4175 elif line.startswith('F'):4176 countdown_on = True4177 countdown = 34178 minified_exception += line + '\n'4179 elif line.startswith('+') or line.startswith('-'):4180 minified_exception += line + '\n'4181 elif line.startswith('?'):4182 minified_exception += line + '\n'4183 elif line.strip().startswith('*'):4184 minified_exception += line + '\n'4185 if minified_exception:4186 raise Exception(minified_exception)4187 def check_window(self, name="default", level=0, baseline=False):4188 """ *** Automated Visual Testing with SeleniumBase ***4189 The first time a test calls self.check_window() for a unique "name"4190 parameter provided, it will set a visual baseline, meaning that it4191 creates a folder, saves the URL to a file, saves the current window4192 screenshot to a file, and creates the following three files4193 with the listed data saved:4194 tags_level1.txt -> HTML tags from the window4195 tags_level2.txt -> HTML tags + attributes from the window4196 tags_level3.txt -> HTML tags + attributes/values from the window4197 Baseline folders are named based on the test name and the name4198 parameter passed to self.check_window(). The same test can store4199 multiple baseline folders.4200 If the baseline is being set/reset, the "level" doesn't matter.4201 After the first run of self.check_window(), it will compare the4202 HTML tags of the latest window to the one from the initial run.4203 Here's how the level system works:4204 * level=0 ->4205 DRY RUN ONLY - Will perform a comparison to the baseline, and4206 print out any differences that are found, but4207 won't fail the test even if differences exist.4208 * level=1 ->4209 HTML tags are compared to tags_level1.txt4210 * level=2 ->4211 HTML tags are compared to tags_level1.txt and4212 HTML tags/attributes are compared to tags_level2.txt4213 * level=3 ->4214 HTML tags are compared to tags_level1.txt and4215 HTML tags + attributes are compared to tags_level2.txt and4216 HTML tags + attributes/values are compared to tags_level3.txt4217 As shown, Level-3 is the most strict, Level-1 is the least strict.4218 If the comparisons from the latest window to the existing baseline4219 don't match, the current test will fail, except for Level-0 tests.4220 You can reset the visual baseline on the command line by using:4221 --visual_baseline4222 As long as "--visual_baseline" is used on the command line while4223 running tests, the self.check_window() method cannot fail because4224 it will rebuild the visual baseline rather than comparing the html4225 tags of the latest run to the existing baseline. If there are any4226 expected layout changes to a website that you're testing, you'll4227 need to reset the baseline to prevent unnecessary failures.4228 self.check_window() will fail with "Page Domain Mismatch Failure"4229 if the page domain doesn't match the domain of the baseline.4230 If you want to use self.check_window() to compare a web page to4231 a later version of itself from within the same test run, you can4232 add the parameter "baseline=True" to the first time you call4233 self.check_window() in a test to use that as the baseline. This4234 only makes sense if you're calling self.check_window() more than4235 once with the same name parameter in the same test.4236 Automated Visual Testing with self.check_window() is not very4237 effective for websites that have dynamic content that changes4238 the layout and structure of web pages. For those, you're much4239 better off using regular SeleniumBase functional testing.4240 Example usage:4241 self.check_window(name="testing", level=0)4242 self.check_window(name="xkcd_home", level=1)4243 self.check_window(name="github_page", level=2)4244 self.check_window(name="wikipedia_page", level=3)4245 """4246 if level == "0":4247 level = 04248 if level == "1":4249 level = 14250 if level == "2":4251 level = 24252 if level == "3":4253 level = 34254 if level != 0 and level != 1 and level != 2 and level != 3:4255 raise Exception('Parameter "level" must be set to 0, 1, 2, or 3!')4256 if self.demo_mode:4257 raise Exception(4258 "WARNING: Using Demo Mode will break layout tests "4259 "that use the check_window() method due to custom "4260 "HTML edits being made on the page!\n"4261 "Please rerun without using Demo Mode!")4262 module = self.__class__.__module__4263 if '.' in module and len(module.split('.')[-1]) > 1:4264 module = module.split('.')[-1]4265 test_id = "%s.%s" % (module, self._testMethodName)4266 if not name or len(name) < 1:4267 name = "default"4268 name = str(name)4269 from seleniumbase.core import visual_helper4270 visual_helper.visual_baseline_folder_setup()4271 baseline_dir = constants.VisualBaseline.STORAGE_FOLDER4272 visual_baseline_path = baseline_dir + "/" + test_id + "/" + name4273 page_url_file = visual_baseline_path + "/page_url.txt"4274 screenshot_file = visual_baseline_path + "/screenshot.png"4275 level_1_file = visual_baseline_path + "/tags_level_1.txt"4276 level_2_file = visual_baseline_path + "/tags_level_2.txt"4277 level_3_file = visual_baseline_path + "/tags_level_3.txt"4278 set_baseline = False4279 if baseline or self.visual_baseline:4280 set_baseline = True4281 if not os.path.exists(visual_baseline_path):4282 set_baseline = True4283 try:4284 os.makedirs(visual_baseline_path)4285 except Exception:4286 pass # Only reachable during multi-threaded test runs4287 if not os.path.exists(page_url_file):4288 set_baseline = True4289 if not os.path.exists(screenshot_file):4290 set_baseline = True4291 if not os.path.exists(level_1_file):4292 set_baseline = True4293 if not os.path.exists(level_2_file):4294 set_baseline = True4295 if not os.path.exists(level_3_file):4296 set_baseline = True4297 page_url = self.get_current_url()4298 soup = self.get_beautiful_soup()4299 html_tags = soup.body.find_all()4300 level_1 = [[tag.name] for tag in html_tags]4301 level_1 = json.loads(json.dumps(level_1)) # Tuples become lists4302 level_2 = [[tag.name, sorted(tag.attrs.keys())] for tag in html_tags]4303 level_2 = json.loads(json.dumps(level_2)) # Tuples become lists4304 level_3 = [[tag.name, sorted(tag.attrs.items())] for tag in html_tags]4305 level_3 = json.loads(json.dumps(level_3)) # Tuples become lists4306 if set_baseline:4307 self.save_screenshot("screenshot.png", visual_baseline_path)4308 out_file = codecs.open(page_url_file, "w+")4309 out_file.writelines(page_url)4310 out_file.close()4311 out_file = codecs.open(level_1_file, "w+")4312 out_file.writelines(json.dumps(level_1))4313 out_file.close()4314 out_file = codecs.open(level_2_file, "w+")4315 out_file.writelines(json.dumps(level_2))4316 out_file.close()4317 out_file = codecs.open(level_3_file, "w+")4318 out_file.writelines(json.dumps(level_3))4319 out_file.close()4320 if not set_baseline:4321 f = open(page_url_file, 'r')4322 page_url_data = f.read().strip()4323 f.close()4324 f = open(level_1_file, 'r')4325 level_1_data = json.loads(f.read())4326 f.close()4327 f = open(level_2_file, 'r')4328 level_2_data = json.loads(f.read())4329 f.close()4330 f = open(level_3_file, 'r')4331 level_3_data = json.loads(f.read())4332 f.close()4333 domain_fail = (4334 "\nPage Domain Mismatch Failure: "4335 "Current Page Domain doesn't match the Page Domain of the "4336 "Baseline! Can't compare two completely different sites! "4337 "Run with --visual_baseline to reset the baseline!")4338 level_1_failure = (4339 "\n*\n*** Exception: <Level 1> Visual Diff Failure:\n"4340 "* HTML tags don't match the baseline!")4341 level_2_failure = (4342 "\n*\n*** Exception: <Level 2> Visual Diff Failure:\n"4343 "* HTML tag attribute names don't match the baseline!")4344 level_3_failure = (4345 "\n*\n*** Exception: <Level 3> Visual Diff Failure:\n"4346 "* HTML tag attribute values don't match the baseline!")4347 page_domain = self.get_domain_url(page_url)4348 page_data_domain = self.get_domain_url(page_url_data)4349 unittest.TestCase.maxDiff = 10004350 if level != 0:4351 self.assertEqual(page_data_domain, page_domain, domain_fail)4352 unittest.TestCase.maxDiff = None4353 if level == 3:4354 self.__assert_eq(level_3_data, level_3, level_3_failure)4355 if level == 2:4356 self.__assert_eq(level_2_data, level_2, level_2_failure)4357 unittest.TestCase.maxDiff = 10004358 if level == 1:4359 self.__assert_eq(level_1_data, level_1, level_1_failure)4360 unittest.TestCase.maxDiff = None4361 if level == 0:4362 try:4363 unittest.TestCase.maxDiff = 10004364 self.assertEqual(4365 page_domain, page_data_domain, domain_fail)4366 unittest.TestCase.maxDiff = None4367 self.__assert_eq(level_3_data, level_3, level_3_failure)4368 except Exception as e:4369 print(e) # Level-0 Dry Run (Only print the differences)4370 ############4371 def __get_new_timeout(self, timeout):4372 """ When using --timeout_multiplier=#.# """4373 try:4374 timeout_multiplier = float(self.timeout_multiplier)4375 if timeout_multiplier <= 0.5:4376 timeout_multiplier = 0.54377 timeout = int(math.ceil(timeout_multiplier * timeout))4378 return timeout4379 except Exception:4380 # Wrong data type for timeout_multiplier (expecting int or float)4381 return timeout4382 ############4383 def __get_exception_message(self):4384 """ This method extracts the message from an exception if there4385 was an exception that occurred during the test, assuming4386 that the exception was in a try/except block and not thrown. """4387 exception_info = sys.exc_info()[1]4388 if hasattr(exception_info, 'msg'):4389 exc_message = exception_info.msg4390 elif hasattr(exception_info, 'message'):4391 exc_message = exception_info.message4392 else:4393 exc_message = sys.exc_info()4394 return exc_message4395 def __get_improved_exception_message(self):4396 """4397 If Chromedriver is out-of-date, make it clear!4398 Given the high popularity of the following StackOverflow article:4399 https://stackoverflow.com/questions/49162667/unknown-error-4400 call-function-result-missing-value-for-selenium-send-keys-even4401 ... the original error message was not helpful. Tell people directly.4402 (Only expected when using driver.send_keys() with an old Chromedriver.)4403 """4404 exc_message = self.__get_exception_message()4405 maybe_using_old_chromedriver = False4406 if "unknown error: call function result missing" in exc_message:4407 maybe_using_old_chromedriver = True4408 if self.browser == 'chrome' and maybe_using_old_chromedriver:4409 update = ("Your version of ChromeDriver may be out-of-date! "4410 "Please go to "4411 "https://sites.google.com/a/chromium.org/chromedriver/ "4412 "and download the latest version to your system PATH! "4413 "Or use: ``seleniumbase install chromedriver`` . "4414 "Original Exception Message: %s" % exc_message)4415 exc_message = update4416 return exc_message4417 def __add_deferred_assert_failure(self):4418 """ Add a deferred_assert failure to a list for future processing. """4419 current_url = self.driver.current_url4420 message = self.__get_exception_message()4421 self.__deferred_assert_failures.append(4422 "CHECK #%s: (%s)\n %s" % (4423 self.__deferred_assert_count, current_url, message))4424 ############4425 def deferred_assert_element(self, selector, by=By.CSS_SELECTOR,4426 timeout=None):4427 """ A non-terminating assertion for an element on a page.4428 Failures will be saved until the process_deferred_asserts()4429 method is called from inside a test, likely at the end of it. """4430 if not timeout:4431 timeout = settings.MINI_TIMEOUT4432 if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:4433 timeout = self.__get_new_timeout(timeout)4434 self.__deferred_assert_count += 14435 try:4436 url = self.get_current_url()4437 if url == self.__last_url_of_deferred_assert:4438 timeout = 14439 else:4440 self.__last_url_of_deferred_assert = url4441 except Exception:4442 pass4443 try:4444 self.wait_for_element_visible(selector, by=by, timeout=timeout)4445 return True4446 except Exception:4447 self.__add_deferred_assert_failure()4448 return False4449 def deferred_assert_text(self, text, selector="html", by=By.CSS_SELECTOR,4450 timeout=None):4451 """ A non-terminating assertion for text from an element on a page.4452 Failures will be saved until the process_deferred_asserts()4453 method is called from inside a test, likely at the end of it. """4454 if not timeout:4455 timeout = settings.MINI_TIMEOUT4456 if self.timeout_multiplier and timeout == settings.MINI_TIMEOUT:4457 timeout = self.__get_new_timeout(timeout)4458 self.__deferred_assert_count += 14459 try:4460 url = self.get_current_url()4461 if url == self.__last_url_of_deferred_assert:4462 timeout = 14463 else:4464 self.__last_url_of_deferred_assert = url4465 except Exception:4466 pass4467 try:4468 self.wait_for_text_visible(text, selector, by=by, timeout=timeout)4469 return True4470 except Exception:4471 self.__add_deferred_assert_failure()4472 return False4473 def process_deferred_asserts(self, print_only=False):4474 """ To be used with any test that uses deferred_asserts, which are4475 non-terminating verifications that only raise exceptions4476 after this method is called.4477 This is useful for pages with multiple elements to be checked when4478 you want to find as many bugs as possible in a single test run4479 before having all the exceptions get raised simultaneously.4480 Might be more useful if this method is called after processing all4481 the deferred asserts on a single html page so that the failure4482 screenshot matches the location of the deferred asserts.4483 If "print_only" is set to True, the exception won't get raised. """4484 if self.__deferred_assert_failures:4485 exception_output = ''4486 exception_output += "\n*** DEFERRED ASSERTION FAILURES FROM: "4487 exception_output += "%s\n" % self.id()4488 all_failing_checks = self.__deferred_assert_failures4489 self.__deferred_assert_failures = []4490 for tb in all_failing_checks:4491 exception_output += "%s\n" % tb4492 if print_only:4493 print(exception_output)4494 else:4495 raise Exception(exception_output)4496 ############4497 # Alternate naming scheme for the "deferred_assert" methods.4498 def delayed_assert_element(self, selector, by=By.CSS_SELECTOR,4499 timeout=None):4500 """ Same as self.deferred_assert_element() """4501 return self.deferred_assert_element(4502 selector=selector, by=by, timeout=timeout)4503 def delayed_assert_text(self, text, selector="html", by=By.CSS_SELECTOR,4504 timeout=None):4505 """ Same as self.deferred_assert_text() """4506 return self.deferred_assert_text(4507 text=text, selector=selector, by=by, timeout=timeout)4508 def process_delayed_asserts(self, print_only=False):4509 """ Same as self.process_deferred_asserts() """4510 self.process_deferred_asserts(print_only=print_only)4511 ############4512 def __js_click(self, selector, by=By.CSS_SELECTOR):4513 """ Clicks an element using pure JS. Does not use jQuery. """4514 selector, by = self.__recalculate_selector(selector, by)4515 css_selector = self.convert_to_css_selector(selector, by=by)4516 css_selector = re.escape(css_selector)4517 css_selector = self.__escape_quotes_if_needed(css_selector)4518 script = ("""var simulateClick = function (elem) {4519 var evt = new MouseEvent('click', {4520 bubbles: true,4521 cancelable: true,4522 view: window4523 });4524 var canceled = !elem.dispatchEvent(evt);4525 };4526 var someLink = document.querySelector('%s');4527 simulateClick(someLink);"""4528 % css_selector)4529 self.execute_script(script)4530 def __js_click_all(self, selector, by=By.CSS_SELECTOR):4531 """ Clicks all matching elements using pure JS. (No jQuery) """4532 selector, by = self.__recalculate_selector(selector, by)4533 css_selector = self.convert_to_css_selector(selector, by=by)4534 css_selector = re.escape(css_selector)4535 css_selector = self.__escape_quotes_if_needed(css_selector)4536 script = ("""var simulateClick = function (elem) {4537 var evt = new MouseEvent('click', {4538 bubbles: true,4539 cancelable: true,4540 view: window4541 });4542 var canceled = !elem.dispatchEvent(evt);4543 };4544 var $elements = document.querySelectorAll('%s');4545 var index = 0, length = $elements.length;4546 for(; index < length; index++){4547 simulateClick($elements[index]);}"""4548 % css_selector)4549 self.execute_script(script)4550 def __jquery_click(self, selector, by=By.CSS_SELECTOR):4551 """ Clicks an element using jQuery. Different from using pure JS. """4552 selector, by = self.__recalculate_selector(selector, by)4553 self.wait_for_element_present(4554 selector, by=by, timeout=settings.SMALL_TIMEOUT)4555 selector = self.convert_to_css_selector(selector, by=by)4556 selector = self.__make_css_match_first_element_only(selector)4557 click_script = """jQuery('%s')[0].click()""" % selector4558 self.safe_execute_script(click_script)4559 def __get_href_from_link_text(self, link_text, hard_fail=True):4560 href = self.get_link_attribute(link_text, "href", hard_fail)4561 if not href:4562 return None4563 if href.startswith('//'):4564 link = "http:" + href4565 elif href.startswith('/'):4566 url = self.driver.current_url4567 domain_url = self.get_domain_url(url)4568 link = domain_url + href4569 else:4570 link = href4571 return link4572 def __click_dropdown_link_text(self, link_text, link_css):4573 """ When a link may be hidden under a dropdown menu, use this. """4574 soup = self.get_beautiful_soup()4575 drop_down_list = []4576 for item in soup.select('li[class]'):4577 drop_down_list.append(item)4578 csstype = link_css.split('[')[1].split('=')[0]4579 for item in drop_down_list:4580 item_text_list = item.text.split('\n')4581 if link_text in item_text_list and csstype in item.decode():4582 dropdown_css = ""4583 try:4584 for css_class in item['class']:4585 dropdown_css += '.'4586 dropdown_css += css_class4587 except Exception:4588 continue4589 dropdown_css = item.name + dropdown_css4590 matching_dropdowns = self.find_visible_elements(dropdown_css)4591 for dropdown in matching_dropdowns:4592 # The same class names might be used for multiple dropdowns4593 if dropdown.is_displayed():4594 try:4595 try:4596 page_actions.hover_element(4597 self.driver, dropdown)4598 except Exception:4599 # If hovering fails, driver is likely outdated4600 # Time to go directly to the hidden link text4601 self.open(self.__get_href_from_link_text(4602 link_text))4603 return True4604 page_actions.hover_element_and_click(4605 self.driver, dropdown, link_text,4606 click_by=By.LINK_TEXT, timeout=0.12)4607 return True4608 except Exception:4609 pass4610 return False4611 def __get_href_from_partial_link_text(self, link_text, hard_fail=True):4612 href = self.get_partial_link_text_attribute(4613 link_text, "href", hard_fail)4614 if not href:4615 return None4616 if href.startswith('//'):4617 link = "http:" + href4618 elif href.startswith('/'):4619 url = self.driver.current_url4620 domain_url = self.get_domain_url(url)4621 link = domain_url + href4622 else:4623 link = href4624 return link4625 def __click_dropdown_partial_link_text(self, link_text, link_css):4626 """ When a partial link may be hidden under a dropdown, use this. """4627 soup = self.get_beautiful_soup()4628 drop_down_list = []4629 for item in soup.select('li[class]'):4630 drop_down_list.append(item)4631 csstype = link_css.split('[')[1].split('=')[0]4632 for item in drop_down_list:4633 item_text_list = item.text.split('\n')4634 if link_text in item_text_list and csstype in item.decode():4635 dropdown_css = ""4636 try:4637 for css_class in item['class']:4638 dropdown_css += '.'4639 dropdown_css += css_class4640 except Exception:4641 continue4642 dropdown_css = item.name + dropdown_css4643 matching_dropdowns = self.find_visible_elements(dropdown_css)4644 for dropdown in matching_dropdowns:4645 # The same class names might be used for multiple dropdowns4646 if dropdown.is_displayed():4647 try:4648 try:4649 page_actions.hover_element(4650 self.driver, dropdown)4651 except Exception:4652 # If hovering fails, driver is likely outdated4653 # Time to go directly to the hidden link text4654 self.open(4655 self.__get_href_from_partial_link_text(4656 link_text))4657 return True4658 page_actions.hover_element_and_click(4659 self.driver, dropdown, link_text,4660 click_by=By.LINK_TEXT, timeout=0.12)4661 return True4662 except Exception:4663 pass4664 return False4665 def __recalculate_selector(self, selector, by):4666 # Try to determine the type of selector automatically4667 if page_utils.is_xpath_selector(selector):4668 by = By.XPATH4669 if page_utils.is_link_text_selector(selector):4670 selector = page_utils.get_link_text_from_selector(selector)4671 by = By.LINK_TEXT4672 if page_utils.is_partial_link_text_selector(selector):4673 selector = page_utils.get_partial_link_text_from_selector(selector)4674 by = By.PARTIAL_LINK_TEXT4675 if page_utils.is_name_selector(selector):4676 name = page_utils.get_name_from_selector(selector)4677 selector = '[name="%s"]' % name4678 by = By.CSS_SELECTOR4679 return (selector, by)4680 def __looks_like_a_page_url(self, url):4681 """ Returns True if the url parameter looks like a URL. This method4682 is slightly more lenient than page_utils.is_valid_url(url) due to4683 possible typos when calling self.get(url), which will try to4684 navigate to the page if a URL is detected, but will instead call4685 self.get_element(URL_AS_A_SELECTOR) if the input in not a URL. """4686 if (url.startswith("http:") or url.startswith("https:") or (4687 url.startswith("://") or url.startswith("data:") or (4688 url.startswith("about:") or url.startswith("chrome:") or (4689 url.startswith("file:"))))):4690 return True4691 else:4692 return False4693 def __make_css_match_first_element_only(self, selector):4694 # Only get the first match4695 return page_utils.make_css_match_first_element_only(selector)4696 def __demo_mode_pause_if_active(self, tiny=False):4697 if self.demo_mode:4698 wait_time = settings.DEFAULT_DEMO_MODE_TIMEOUT4699 if self.demo_sleep:4700 wait_time = float(self.demo_sleep)4701 if not tiny:4702 time.sleep(wait_time)4703 else:4704 time.sleep(wait_time / 3.4)4705 elif self.slow_mode:4706 self.__slow_mode_pause_if_active()4707 def __slow_mode_pause_if_active(self):4708 if self.slow_mode:4709 wait_time = settings.DEFAULT_DEMO_MODE_TIMEOUT4710 if self.demo_sleep:4711 wait_time = float(self.demo_sleep)4712 time.sleep(wait_time)4713 def __demo_mode_scroll_if_active(self, selector, by):4714 if self.demo_mode:4715 self.slow_scroll_to(selector, by=by)4716 def __demo_mode_highlight_if_active(self, selector, by):4717 if self.demo_mode:4718 # Includes self.slow_scroll_to(selector, by=by) by default4719 self.highlight(selector, by=by)4720 elif self.slow_mode:4721 # Just do the slow scroll part of the highlight() method4722 selector, by = self.__recalculate_selector(selector, by)4723 element = self.wait_for_element_visible(4724 selector, by=by, timeout=settings.SMALL_TIMEOUT)4725 try:4726 self.__slow_scroll_to_element(element)4727 except (StaleElementReferenceException, ENI_Exception):4728 self.wait_for_ready_state_complete()4729 time.sleep(0.05)4730 element = self.wait_for_element_visible(4731 selector, by=by, timeout=settings.SMALL_TIMEOUT)4732 self.__slow_scroll_to_element(element)4733 def __scroll_to_element(self, element, selector=None, by=By.CSS_SELECTOR):4734 success = js_utils.scroll_to_element(self.driver, element)4735 if not success and selector:4736 self.wait_for_ready_state_complete()4737 element = page_actions.wait_for_element_visible(4738 self.driver, selector, by, timeout=settings.SMALL_TIMEOUT)4739 self.__demo_mode_pause_if_active(tiny=True)4740 def __slow_scroll_to_element(self, element):4741 js_utils.slow_scroll_to_element(self.driver, element, self.browser)4742 def __highlight_with_assert_success(4743 self, message, selector, by=By.CSS_SELECTOR):4744 selector, by = self.__recalculate_selector(selector, by)4745 element = self.wait_for_element_visible(4746 selector, by=by, timeout=settings.SMALL_TIMEOUT)4747 try:4748 selector = self.convert_to_css_selector(selector, by=by)4749 except Exception:4750 # Don't highlight if can't convert to CSS_SELECTOR4751 return4752 try:4753 self.__slow_scroll_to_element(element)4754 except (StaleElementReferenceException, ENI_Exception):4755 self.wait_for_ready_state_complete()4756 time.sleep(0.05)4757 element = self.wait_for_element_visible(4758 selector, by=by, timeout=settings.SMALL_TIMEOUT)4759 self.__slow_scroll_to_element(element)4760 o_bs = '' # original_box_shadow4761 try:4762 style = element.get_attribute('style')...

Full Screen

Full Screen

web.py

Source:web.py Github

copy

Full Screen

...54 seleniumwire_options=seleniumwire_options,55 **kwargs56 )57 @staticmethod58 def convert_to_css_selector(by, value: str):59 if by == By.ID:60 return '[id="%s"]' % value61 elif by == By.TAG_NAME:62 return value63 elif by == By.CLASS_NAME:64 return ".%s" % value65 elif by == By.NAME:66 return '[name="%s"]' % value67 else:68 return value69 def _get_element(70 self, element: PageElement) -> webdriver.Firefox._web_element_cls:71 return super().find_element('css selector', element.css_selector)72 def click(self, webelement: PageElement) -> True:73 self._get_element(webelement).click()74 return True75 def enter_input(self, webelement: PageElement, value: str) -> True:76 webelement = self._get_element(webelement)77 webelement.click()78 webelement.send_keys(Keys.HOME)79 webelement.send_keys(Keys.SHIFT, Keys.END)80 webelement.send_keys(Keys.BACKSPACE)81 webelement.send_keys(value)82 return True83 def find_element(self, by=By.ID, value=None):84 element = super().find_element(by, value)85 element = bs(86 element.get_attribute('outerHTML'), 'html.parser'87 ).select_one('*')88 element.css_selector = self.convert_to_css_selector(by, value)89 return element90 def find_elements(self, by=By.ID, value=None):91 elements = super().find_elements(by, value)92 css_selector = self.convert_to_css_selector(by, value)93 elements = [94 bs(95 element.get_attribute('outerHTML'), 'html.parser'96 ).select_one('*')97 for element in elements98 ]99 for element in elements:100 element.css_selector = css_selector101 return elements102 @property103 def content(self):104 return bs(self.page_source, 'html.parser')105 @property106 def url(self):...

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run SeleniumBase automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful