How to use __check_browser method in SeleniumBase

Best Python code snippet using SeleniumBase

webdriver_test.py

Source:webdriver_test.py Github

copy

Full Screen

...2110 self.__page_sources = []2111 def open_new_window(self, switch_to=True):2112 """ Opens a new browser tab/window and switches to it by default. """2113 self.__check_scope__()2114 self.__check_browser() # Current window must exist to open a new one2115 self.driver.execute_script("window.open('');")2116 time.sleep(0.01)2117 if switch_to:2118 self.switch_to_newest_window()2119 time.sleep(0.01)2120 if self.browser == "safari":2121 self.wait_for_ready_state_complete()2122 def switch_to_window(self, window, timeout=None):2123 """ Switches control of the browser to the specified window.2124 The window can be an integer: 0 -> 1st tab, 1 -> 2nd tab, etc...2125 Or it can be a list item from self.driver.window_handles """2126 self.__check_scope__()2127 timeout = self.get_timeout(timeout, constants.SMALL_TIMEOUT)2128 page_actions.switch_to_window(self.driver, window, timeout)2129 def switch_to_default_window(self):2130 self.switch_to_window(0)2131 def __switch_to_newest_window_if_not_blank(self):2132 current_window = self.driver.current_window_handle2133 try:2134 self.switch_to_window(len(self.driver.window_handles) - 1)2135 if self.get_current_url() == "about:blank":2136 self.switch_to_window(current_window)2137 except Exception:2138 self.switch_to_window(current_window)2139 def switch_to_newest_window(self):2140 self.switch_to_window(len(self.driver.window_handles) - 1)2141 def get_new_driver(2142 self,2143 browser=None,2144 headless=None,2145 locale_code=None,2146 protocol=None,2147 servername=None,2148 port=None,2149 proxy=None,2150 proxy_bypass_list=None,2151 agent=None,2152 switch_to=True,2153 cap_file=None,2154 cap_string=None,2155 recorder_ext=None,2156 disable_csp=None,2157 enable_ws=None,2158 enable_sync=None,2159 use_auto_ext=None,2160 no_sandbox=None,2161 disable_gpu=None,2162 incognito=None,2163 guest_mode=None,2164 devtools=None,2165 remote_debug=None,2166 swiftshader=None,2167 ad_block_on=None,2168 block_images=None,2169 chromium_arg=None,2170 firefox_arg=None,2171 firefox_pref=None,2172 user_data_dir=None,2173 extension_zip=None,2174 extension_dir=None,2175 external_pdf=None,2176 is_mobile=None,2177 d_width=None,2178 d_height=None,2179 d_p_r=None,2180 ):2181 """This method spins up an extra browser for tests that require2182 more than one. The first browser is already provided by tests2183 that import base_case.BaseCase from seleniumbase. If parameters2184 aren't specified, the method uses the same as the default driver.2185 @Params2186 browser - the browser to use. (Ex: "chrome", "firefox")2187 headless - the option to run webdriver in headless mode2188 locale_code - the Language Locale Code for the web browser2189 protocol - if using a Selenium Grid, set the host protocol here2190 servername - if using a Selenium Grid, set the host address here2191 port - if using a Selenium Grid, set the host port here2192 proxy - if using a proxy server, specify the "host:port" combo here2193 proxy_bypass_list - ";"-separated hosts to bypass (Eg. "*.foo.com")2194 switch_to - the option to switch to the new driver (default = True)2195 cap_file - the file containing desired capabilities for the browser2196 cap_string - the string with desired capabilities for the browser2197 recorder_ext - the option to enable the SBase Recorder extension2198 disable_csp - an option to disable Chrome's Content Security Policy2199 enable_ws - the option to enable the Web Security feature (Chrome)2200 enable_sync - the option to enable the Chrome Sync feature (Chrome)2201 use_auto_ext - the option to enable Chrome's Automation Extension2202 no_sandbox - the option to enable the "No-Sandbox" feature (Chrome)2203 disable_gpu - the option to enable Chrome's "Disable GPU" feature2204 incognito - the option to enable Chrome's Incognito mode (Chrome)2205 guest - the option to enable Chrome's Guest mode (Chrome)2206 devtools - the option to open Chrome's DevTools on start (Chrome)2207 remote_debug - the option to enable Chrome's Remote Debugger2208 swiftshader - the option to use Chrome's swiftshader (Chrome-only)2209 ad_block_on - the option to block ads from loading (Chromium-only)2210 block_images - the option to block images from loading (Chrome)2211 chromium_arg - the option to add a Chromium arg to Chrome/Edge2212 firefox_arg - the option to add a Firefox arg to Firefox runs2213 firefox_pref - the option to add a Firefox pref:value set (Firefox)2214 user_data_dir - Chrome's User Data Directory to use (Chrome-only)2215 extension_zip - A Chrome Extension ZIP file to use (Chrome-only)2216 extension_dir - A Chrome Extension folder to use (Chrome-only)2217 external_pdf - "plugins.always_open_pdf_externally": True. (Chrome)2218 is_mobile - the option to use the mobile emulator (Chrome-only)2219 d_width - the device width of the mobile emulator (Chrome-only)2220 d_height - the device height of the mobile emulator (Chrome-only)2221 d_p_r - the device pixel ratio of the mobile emulator (Chrome-only)2222 """2223 self.__check_scope__()2224 if self.browser == "remote" and self.servername == "localhost":2225 raise Exception(2226 'Cannot use "remote" browser driver on localhost!'2227 " Did you mean to connect to a remote Grid server"2228 " such as BrowserStack or Sauce Labs? In that"2229 ' case, you must specify the "server" and "port"'2230 " parameters on the command line! "2231 "Example: "2232 "--server=user:key@hub.browserstack.com --port=80"2233 )2234 browserstack_ref = "https://browserstack.com/automate/capabilities"2235 sauce_labs_ref = (2236 "https://wiki.saucelabs.com/display/DOCS/Platform+Configurator#/"2237 )2238 if self.browser == "remote" and not (self.cap_file or self.cap_string):2239 raise Exception(2240 "Need to specify a desired capabilities file when "2241 'using "--browser=remote". Add "--cap_file=FILE". '2242 "File should be in the Python format used by: "2243 "%s OR "2244 "%s "2245 "See SeleniumBase/examples/sample_cap_file_BS.py "2246 "and SeleniumBase/examples/sample_cap_file_SL.py"2247 % (browserstack_ref, sauce_labs_ref)2248 )2249 if browser is None:2250 browser = self.browser2251 browser_name = browser2252 if headless is None:2253 headless = self.headless2254 if locale_code is None:2255 locale_code = self.locale_code2256 if protocol is None:2257 protocol = self.protocol2258 if servername is None:2259 servername = self.servername2260 if port is None:2261 port = self.port2262 use_grid = False2263 if servername != "localhost":2264 # Use Selenium Grid (Use "127.0.0.1" for localhost Grid)2265 use_grid = True2266 proxy_string = proxy2267 if proxy_string is None:2268 proxy_string = self.proxy_string2269 if proxy_bypass_list is None:2270 proxy_bypass_list = self.proxy_bypass_list2271 user_agent = agent2272 if user_agent is None:2273 user_agent = self.user_agent2274 if recorder_ext is None:2275 recorder_ext = self.recorder_ext2276 if disable_csp is None:2277 disable_csp = self.disable_csp2278 if enable_ws is None:2279 enable_ws = self.enable_ws2280 if enable_sync is None:2281 enable_sync = self.enable_sync2282 if use_auto_ext is None:2283 use_auto_ext = self.use_auto_ext2284 if no_sandbox is None:2285 no_sandbox = self.no_sandbox2286 if disable_gpu is None:2287 disable_gpu = self.disable_gpu2288 if incognito is None:2289 incognito = self.incognito2290 if guest_mode is None:2291 guest_mode = self.guest_mode2292 if devtools is None:2293 devtools = self.devtools2294 if remote_debug is None:2295 remote_debug = self.remote_debug2296 if swiftshader is None:2297 swiftshader = self.swiftshader2298 if ad_block_on is None:2299 ad_block_on = self.ad_block_on2300 if block_images is None:2301 block_images = self.block_images2302 if chromium_arg is None:2303 chromium_arg = self.chromium_arg2304 if firefox_arg is None:2305 firefox_arg = self.firefox_arg2306 if firefox_pref is None:2307 firefox_pref = self.firefox_pref2308 if user_data_dir is None:2309 user_data_dir = self.user_data_dir2310 if extension_zip is None:2311 extension_zip = self.extension_zip2312 if extension_dir is None:2313 extension_dir = self.extension_dir2314 if external_pdf is None:2315 external_pdf = self.external_pdf2316 test_id = self.__get_test_id()2317 if cap_file is None:2318 cap_file = self.cap_file2319 if cap_string is None:2320 cap_string = self.cap_string2321 if is_mobile is None:2322 is_mobile = self.mobile_emulator2323 if d_width is None:2324 d_width = self.__device_width2325 if d_height is None:2326 d_height = self.__device_height2327 if d_p_r is None:2328 d_p_r = self.__device_pixel_ratio2329 valid_browsers = constants.ValidBrowsers.valid_browsers2330 if browser_name not in valid_browsers:2331 raise Exception(2332 "Browser: {%s} is not a valid browser option. "2333 "Valid options = {%s}" % (browser, valid_browsers)2334 )2335 # Launch a web browser2336 from seleniumbase.core import browser_launcher2337 new_driver = browser_launcher.get_driver(2338 browser_name=browser_name,2339 headless=headless,2340 locale_code=locale_code,2341 use_grid=use_grid,2342 protocol=protocol,2343 servername=servername,2344 port=port,2345 proxy_string=proxy_string,2346 proxy_bypass_list=proxy_bypass_list,2347 user_agent=user_agent,2348 cap_file=cap_file,2349 cap_string=cap_string,2350 recorder_ext=recorder_ext,2351 disable_csp=disable_csp,2352 enable_ws=enable_ws,2353 enable_sync=enable_sync,2354 use_auto_ext=use_auto_ext,2355 no_sandbox=no_sandbox,2356 disable_gpu=disable_gpu,2357 incognito=incognito,2358 guest_mode=guest_mode,2359 devtools=devtools,2360 remote_debug=remote_debug,2361 swiftshader=swiftshader,2362 ad_block_on=ad_block_on,2363 block_images=block_images,2364 chromium_arg=chromium_arg,2365 firefox_arg=firefox_arg,2366 firefox_pref=firefox_pref,2367 user_data_dir=user_data_dir,2368 extension_zip=extension_zip,2369 extension_dir=extension_dir,2370 external_pdf=external_pdf,2371 test_id=test_id,2372 mobile_emulator=is_mobile,2373 device_width=d_width,2374 device_height=d_height,2375 device_pixel_ratio=d_p_r,2376 )2377 self._drivers_list.append(new_driver)2378 self.__driver_browser_map[new_driver] = browser_name2379 if switch_to:2380 self.driver = new_driver2381 self.browser = browser_name2382 if self.headless or self.xvfb:2383 # Make sure the invisible browser window is big enough2384 width = settings.HEADLESS_START_WIDTH2385 height = settings.HEADLESS_START_HEIGHT2386 try:2387 self.driver.set_window_size(width, height)2388 self.wait_for_ready_state_complete()2389 except Exception:2390 # This shouldn't fail, but in case it does,2391 # get safely through setUp() so that2392 # WebDrivers can get closed during tearDown().2393 pass2394 else:2395 if self.browser == "chrome" or self.browser == "edge":2396 width = settings.CHROME_START_WIDTH2397 height = settings.CHROME_START_HEIGHT2398 try:2399 if self.maximize_option:2400 self.driver.maximize_window()2401 else:2402 self.driver.set_window_size(width, height)2403 self.wait_for_ready_state_complete()2404 except Exception:2405 pass # Keep existing browser resolution2406 elif self.browser == "firefox":2407 width = settings.CHROME_START_WIDTH2408 try:2409 if self.maximize_option:2410 self.driver.maximize_window()2411 else:2412 self.driver.set_window_size(width, 720)2413 self.wait_for_ready_state_complete()2414 except Exception:2415 pass # Keep existing browser resolution2416 elif self.browser == "safari":2417 width = settings.CHROME_START_WIDTH2418 if self.maximize_option:2419 try:2420 self.driver.maximize_window()2421 self.wait_for_ready_state_complete()2422 except Exception:2423 pass # Keep existing browser resolution2424 else:2425 try:2426 self.driver.set_window_rect(10, 30, width, 630)2427 except Exception:2428 pass2429 elif self.browser == "opera":2430 width = settings.CHROME_START_WIDTH2431 if self.maximize_option:2432 try:2433 self.driver.maximize_window()2434 self.wait_for_ready_state_complete()2435 except Exception:2436 pass # Keep existing browser resolution2437 else:2438 try:2439 self.driver.set_window_rect(10, 30, width, 700)2440 except Exception:2441 pass2442 if self.start_page and len(self.start_page) >= 4:2443 if page_utils.is_valid_url(self.start_page):2444 self.open(self.start_page)2445 else:2446 new_start_page = "https://" + self.start_page2447 if page_utils.is_valid_url(new_start_page):2448 self.__dont_record_open = True2449 self.open(new_start_page)2450 self.__dont_record_open = False2451 return new_driver2452 def switch_to_driver(self, driver):2453 """Switches control of the browser to the specified driver.2454 Also sets the self.driver variable to the specified driver.2455 You may need this if using self.get_new_driver() in your code."""2456 self.__check_scope__()2457 self.driver = driver2458 if self.driver in self.__driver_browser_map:2459 self.browser = self.__driver_browser_map[self.driver]2460 self.bring_active_window_to_front()2461 def switch_to_default_driver(self):2462 """ Sets self.driver to the default/original driver. """2463 self.__check_scope__()2464 self.driver = self._default_driver2465 if self.driver in self.__driver_browser_map:2466 self.browser = self.__driver_browser_map[self.driver]2467 self.bring_active_window_to_front()2468 def save_screenshot(2469 self, name, folder=None, selector=None, by=By.CSS_SELECTOR2470 ):2471 """2472 Saves a screenshot of the current page.2473 If no folder is specified, uses the folder where pytest was called.2474 The screenshot will include the entire page unless a selector is given.2475 If a provided selector is not found, then takes a full-page screenshot.2476 If the folder provided doesn't exist, it will get created.2477 The screenshot will be in PNG format: (*.png)2478 """2479 self.wait_for_ready_state_complete()2480 if selector and by:2481 selector, by = self.__recalculate_selector(selector, by)2482 if page_actions.is_element_present(self.driver, selector, by):2483 return page_actions.save_screenshot(2484 self.driver, name, folder, selector, by2485 )2486 return page_actions.save_screenshot(self.driver, name, folder)2487 def save_screenshot_to_logs(2488 self, name=None, selector=None, by=By.CSS_SELECTOR2489 ):2490 """Saves a screenshot of the current page to the "latest_logs" folder.2491 Naming is automatic:2492 If NO NAME provided: "_1_screenshot.png", "_2_screenshot.png", etc.2493 If NAME IS provided, it becomes: "_1_name.png", "_2_name.png", etc.2494 The screenshot will include the entire page unless a selector is given.2495 If a provided selector is not found, then takes a full-page screenshot.2496 (The last_page / failure screenshot is always "screenshot.png")2497 The screenshot will be in PNG format."""2498 self.wait_for_ready_state_complete()2499 test_logpath = os.path.join(self.log_path, self.__get_test_id())2500 self.__create_log_path_as_needed(test_logpath)2501 if name:2502 name = str(name)2503 self.__screenshot_count += 12504 if not name or len(name) == 0:2505 name = "_%s_screenshot.png" % self.__screenshot_count2506 else:2507 pre_name = "_%s_" % self.__screenshot_count2508 if len(name) >= 4 and name[-4:].lower() == ".png":2509 name = name[:-4]2510 if len(name) == 0:2511 name = "screenshot"2512 name = "%s%s.png" % (pre_name, name)2513 if selector and by:2514 selector, by = self.__recalculate_selector(selector, by)2515 if page_actions.is_element_present(self.driver, selector, by):2516 return page_actions.save_screenshot(2517 self.driver, name, test_logpath, selector, by2518 )2519 return page_actions.save_screenshot(self.driver, name, test_logpath)2520 def save_page_source(self, name, folder=None):2521 """Saves the page HTML to the current directory (or given subfolder).2522 If the folder specified doesn't exist, it will get created.2523 @Params2524 name - The file name to save the current page's HTML to.2525 folder - The folder to save the file to. (Default = current folder)2526 """2527 self.wait_for_ready_state_complete()2528 return page_actions.save_page_source(self.driver, name, folder)2529 # def save_cookies(self, name="cookies.txt"):2530 # """ Saves the page cookies to the "saved_cookies" folder. """2531 # self.wait_for_ready_state_complete()2532 # cookies = self.driver.get_cookies()2533 # json_cookies = json.dumps(cookies)2534 # if name.endswith("/"):2535 # raise Exception("Invalid filename for Cookies!")2536 # if "/" in name:2537 # name = name.split("/")[-1]2538 # if len(name) < 1:2539 # raise Exception("Filename for Cookies is too short!")2540 # if not name.endswith(".txt"):2541 # name = name + ".txt"2542 # folder = constants.SavedCookies.STORAGE_FOLDER2543 # abs_path = os.path.abspath(".")2544 # file_path = abs_path + "/%s" % folder2545 # if not os.path.exists(file_path):2546 # os.makedirs(file_path)2547 # cookies_file_path = "%s/%s" % (file_path, name)2548 # cookies_file = codecs.open(cookies_file_path, "w+", encoding="utf-8")2549 # cookies_file.writelines(json_cookies)2550 # cookies_file.close()2551 #2552 # def load_cookies(self, name="cookies.txt"):2553 # """ Loads the page cookies from the "saved_cookies" folder. """2554 # self.wait_for_ready_state_complete()2555 # if name.endswith("/"):2556 # raise Exception("Invalid filename for Cookies!")2557 # if "/" in name:2558 # name = name.split("/")[-1]2559 # if len(name) < 1:2560 # raise Exception("Filename for Cookies is too short!")2561 # if not name.endswith(".txt"):2562 # name = name + ".txt"2563 # folder = constants.SavedCookies.STORAGE_FOLDER2564 # abs_path = os.path.abspath(".")2565 # file_path = abs_path + "/%s" % folder2566 # cookies_file_path = "%s/%s" % (file_path, name)2567 # json_cookies = None2568 # with open(cookies_file_path, "r") as f:2569 # json_cookies = f.read().strip()2570 # cookies = json.loads(json_cookies)2571 # for cookie in cookies:2572 # if "expiry" in cookie:2573 # del cookie["expiry"]2574 # self.driver.add_cookie(cookie)2575 #2576 # def delete_all_cookies(self):2577 # """Deletes all cookies in the web browser.2578 # Does NOT delete the saved cookies file."""2579 # self.wait_for_ready_state_complete()2580 # self.driver.delete_all_cookies()2581 #2582 # def delete_saved_cookies(self, name: str = "cookies.txt"):2583 # """Deletes the cookies file from the "saved_cookies" folder.2584 # Does NOT delete the cookies from the web browser."""2585 # self.wait_for_ready_state_complete()2586 # if name.endswith("/"):2587 # raise Exception("Invalid filename for Cookies!")2588 # if "/" in name:2589 # name = name.split("/")[-1]2590 # if len(name) < 1:2591 # raise Exception("Filename for Cookies is too short!")2592 # if not name.endswith(".txt"):2593 # name = name + ".txt"2594 # folder = constants.SavedCookies.STORAGE_FOLDER2595 # abs_path = os.path.abspath(".")2596 # file_path = abs_path + "/%s" % folder2597 # cookies_file_path = "%s/%s" % (file_path, name)2598 # if os.path.exists(cookies_file_path):2599 # if cookies_file_path.endswith(".txt"):2600 # os.remove(cookies_file_path)2601 def install_addon(self, xpi_file: FilePath):2602 """Installs a Firefox add-on instantly at run-time.2603 @Params2604 xpi_file - A file archive in .xpi format.2605 """2606 self.wait_for_ready_state_complete()2607 if self.driver.capabilities.get("browseName") != "firefox":2608 raise Exception(2609 "install_addon(xpi_file) is for Firefox ONLY!\n"2610 "To load a Chrome extension, use the comamnd-line:\n"2611 "--extension_zip=CRX_FILE OR --extension_dir=DIR"2612 )2613 xpi_path = os.path.abspath(xpi_file)2614 self.driver.install_addon(xpi_path, temporary=True)2615 def activate_demo_mode(self):2616 self.demo_mode = True2617 def deactivate_demo_mode(self):2618 self.demo_mode = False2619 def activate_design_mode(self):2620 # Activate Chrome's Design Mode, which lets you edit a site directly.2621 # See: https://twitter.com/sulco/status/11775591505633443842622 self.wait_for_ready_state_complete()2623 script = """document.designMode = 'on';"""2624 self.execute_script(script)2625 def deactivate_design_mode(self):2626 # Deactivate Chrome's Design Mode.2627 self.wait_for_ready_state_complete()2628 script = """document.designMode = 'off';"""2629 self.execute_script(script)2630 def bring_active_window_to_front(self):2631 """Brings the active browser window to the front.2632 This is useful when multiple drivers are being used."""2633 self.__check_scope__()2634 try:2635 if not js_utils.is_in_frame():2636 # Only bring the window to the front if not in a frame2637 # because the driver resets itself to default content.2638 self.switch_to_window(self.driver.current_window_handle)2639 except Exception:2640 pass2641 def bring_to_front(self, selector, by=By.CSS_SELECTOR):2642 """Updates the Z-index of a page element to bring it into view.2643 Useful when getting a WebDriverException, such as the one below:2644 { Element is not clickable at point (#, #).2645 Other element would receive the click: ... }"""2646 self.__check_scope__()2647 self.wait_for_element_visible(2648 selector, by=by, timeout=settings.SMALL_TIMEOUT2649 )2650 try:2651 selector = self.convert_to_css_selector(selector, by=by)2652 except Exception:2653 # Don't run action if can't convert to CSS_Selector for JavaScript2654 return2655 selector = re.escape(selector)2656 selector = shared.escape_quotes_if_needed(selector)2657 script = (2658 """document.querySelector('%s').style.zIndex = '999999';"""2659 % selector2660 )2661 self.execute_script(script)2662 def highlight_click(2663 self, selector, by=By.CSS_SELECTOR, loops=3, scroll=True2664 ):2665 self.__check_scope__()2666 if not self.demo_mode:2667 self.highlight(selector, by=by, loops=loops, scroll=scroll)2668 self.click(selector, by=by)2669 def highlight_update_text(2670 self, selector, text, by=By.CSS_SELECTOR, loops=3, scroll=True2671 ):2672 """Highlights the element and then types text into the field."""2673 self.__check_scope__()2674 if not self.demo_mode:2675 self.highlight(selector, by=by, loops=loops, scroll=scroll)2676 self.update_text(selector, text, by=by)2677 def highlight_type(2678 self, selector, text, by=By.CSS_SELECTOR, loops=3, scroll=True2679 ):2680 """Same as self.highlight_update_text()2681 As above, highlights the element and then types text into the field."""2682 self.__check_scope__()2683 if not self.demo_mode:2684 self.highlight(selector, by=by, loops=loops, scroll=scroll)2685 self.update_text(selector, text, by=by)2686 def highlight(self, selector, by=By.CSS_SELECTOR, loops=None, scroll=True):2687 """This method uses fancy JavaScript to highlight an element.2688 Used during demo_mode.2689 @Params2690 selector - the selector of the element to find2691 by - the type of selector to search by (Default: CSS)2692 loops - # of times to repeat the highlight animation2693 (Default: 4. Each loop lasts for about 0.18s)2694 scroll - the option to scroll to the element first (Default: True)2695 """2696 self.__check_scope__()2697 selector, by = self.__recalculate_selector(selector, by, xp_ok=False)2698 element = self.wait_for_element_visible(2699 selector, by=by, timeout=settings.SMALL_TIMEOUT2700 )2701 if not loops:2702 loops = settings.HIGHLIGHTS2703 if scroll:2704 try:2705 if self.browser != "safari":2706 scroll_distance = js_utils.get_scroll_distance_to_element(2707 self.driver, element2708 )2709 if abs(scroll_distance) > settings.SSMD:2710 self.__jquery_slow_scroll_to(selector, by)2711 else:2712 self.__slow_scroll_to_element(element)2713 else:2714 self.__jquery_slow_scroll_to(selector, by)2715 except Exception:2716 self.wait_for_ready_state_complete()2717 time.sleep(0.12)2718 element = self.wait_for_element_visible(2719 selector, by=by, timeout=settings.SMALL_TIMEOUT2720 )2721 self.__slow_scroll_to_element(element)2722 try:2723 selector = self.convert_to_css_selector(selector, by=by)2724 except Exception:2725 # Don't highlight if can't convert to CSS_SELECTOR2726 return2727 if self.highlights:2728 loops = self.highlights2729 if self.browser == "ie":2730 loops = 1 # Override previous setting because IE is slow2731 loops = int(loops)2732 o_bs = "" # original_box_shadow2733 try:2734 style = element.get_attribute("style")2735 except Exception:2736 self.wait_for_ready_state_complete()2737 time.sleep(0.12)2738 element = self.wait_for_element_visible(2739 selector, by=By.CSS_SELECTOR, timeout=settings.SMALL_TIMEOUT2740 )2741 style = element.get_attribute("style")2742 if style:2743 if "box-shadow: " in style:2744 box_start = style.find("box-shadow: ")2745 box_end = style.find(";", box_start) + 12746 original_box_shadow = style[box_start:box_end]2747 o_bs = original_box_shadow2748 orig_selector = selector2749 if ":contains" not in selector and ":first" not in selector:2750 selector = re.escape(selector)2751 selector = shared.escape_quotes_if_needed(selector)2752 self.__highlight_with_js(selector, loops, o_bs)2753 else:2754 selector = self.__make_css_match_first_element_only(selector)2755 selector = re.escape(selector)2756 selector = shared.escape_quotes_if_needed(selector)2757 try:2758 self.__highlight_with_jquery(selector, loops, o_bs)2759 except Exception:2760 pass # JQuery probably couldn't load. Skip highlighting.2761 time.sleep(0.065)2762 def __highlight_with_js(self, selector, loops, o_bs):2763 self.wait_for_ready_state_complete()2764 js_utils.highlight_with_js(self.driver, selector, loops, o_bs)2765 def __highlight_with_jquery(self, selector, loops, o_bs):2766 self.wait_for_ready_state_complete()2767 js_utils.highlight_with_jquery(self.driver, selector, loops, o_bs)2768 def press_up_arrow(self, selector="html", times=1, by=By.CSS_SELECTOR):2769 """Simulates pressing the UP Arrow on the keyboard.2770 By default, "html" will be used as the CSS Selector target.2771 You can specify how many times in-a-row the action happens."""2772 self.__check_scope__()2773 if times < 1:2774 return2775 element = self.wait_for_element_present(selector)2776 self.__demo_mode_highlight_if_active(selector, by)2777 if not self.demo_mode and not self.slow_mode:2778 self.__scroll_to_element(element, selector, by)2779 for i in range(int(times)):2780 try:2781 element.send_keys(Keys.ARROW_UP)2782 except Exception:2783 self.wait_for_ready_state_complete()2784 element = self.wait_for_element_visible(selector)2785 element.send_keys(Keys.ARROW_UP)2786 time.sleep(0.01)2787 if self.slow_mode:2788 time.sleep(0.1)2789 def press_down_arrow(self, selector="html", times=1, by=By.CSS_SELECTOR):2790 """Simulates pressing the DOWN Arrow on the keyboard.2791 By default, "html" will be used as the CSS Selector target.2792 You can specify how many times in-a-row the action happens."""2793 self.__check_scope__()2794 if times < 1:2795 return2796 element = self.wait_for_element_present(selector)2797 self.__demo_mode_highlight_if_active(selector, by)2798 if not self.demo_mode and not self.slow_mode:2799 self.__scroll_to_element(element, selector, by)2800 for i in range(int(times)):2801 try:2802 element.send_keys(Keys.ARROW_DOWN)2803 except Exception:2804 self.wait_for_ready_state_complete()2805 element = self.wait_for_element_visible(selector)2806 element.send_keys(Keys.ARROW_DOWN)2807 time.sleep(0.01)2808 if self.slow_mode:2809 time.sleep(0.1)2810 def press_left_arrow(self, selector="html", times=1, by=By.CSS_SELECTOR):2811 """Simulates pressing the LEFT Arrow on the keyboard.2812 By default, "html" will be used as the CSS Selector target.2813 You can specify how many times in-a-row the action happens."""2814 self.__check_scope__()2815 if times < 1:2816 return2817 element = self.wait_for_element_present(selector)2818 self.__demo_mode_highlight_if_active(selector, by)2819 if not self.demo_mode and not self.slow_mode:2820 self.__scroll_to_element(element, selector, by)2821 for i in range(int(times)):2822 try:2823 element.send_keys(Keys.ARROW_LEFT)2824 except Exception:2825 self.wait_for_ready_state_complete()2826 element = self.wait_for_element_visible(selector)2827 element.send_keys(Keys.ARROW_LEFT)2828 time.sleep(0.01)2829 if self.slow_mode:2830 time.sleep(0.1)2831 def press_right_arrow(self, selector="html", times=1, by=By.CSS_SELECTOR):2832 """Simulates pressing the RIGHT Arrow on the keyboard.2833 By default, "html" will be used as the CSS Selector target.2834 You can specify how many times in-a-row the action happens."""2835 self.__check_scope__()2836 if times < 1:2837 return2838 element = self.wait_for_element_present(selector)2839 self.__demo_mode_highlight_if_active(selector, by)2840 if not self.demo_mode and not self.slow_mode:2841 self.__scroll_to_element(element, selector, by)2842 for i in range(int(times)):2843 try:2844 element.send_keys(Keys.ARROW_RIGHT)2845 except Exception:2846 self.wait_for_ready_state_complete()2847 element = self.wait_for_element_visible(selector)2848 element.send_keys(Keys.ARROW_RIGHT)2849 time.sleep(0.01)2850 if self.slow_mode:2851 time.sleep(0.1)2852 def scroll_to(self, selector, by=By.CSS_SELECTOR, timeout=None):2853 """ Fast scroll to destination """2854 self.__check_scope__()2855 timeout = self.get_timeout(timeout, constants.SMALL_TIMEOUT)2856 if self.demo_mode or self.slow_mode:2857 self.slow_scroll_to(selector, by=by, timeout=timeout)2858 return2859 element = self.wait_for_element_visible(2860 selector, by=by, timeout=timeout2861 )2862 try:2863 self.__scroll_to_element(element, selector, by)2864 except (StaleElementReferenceException, ElementNotInteractableException):2865 self.wait_for_ready_state_complete()2866 time.sleep(0.12)2867 element = self.wait_for_element_visible(2868 selector, by=by, timeout=timeout2869 )2870 self.__scroll_to_element(element, selector, by)2871 def scroll_to_element(self, selector, by=By.CSS_SELECTOR, timeout=None):2872 self.scroll_to(selector, by=by, timeout=timeout)2873 def slow_scroll_to(self, selector, by=By.CSS_SELECTOR, timeout=None):2874 """ Slow motion scroll to destination """2875 self.__check_scope__()2876 timeout = self.get_timeout(timeout, constants.SMALL_TIMEOUT)2877 selector, by = self.__recalculate_selector(selector, by)2878 element = self.wait_for_element_visible(2879 selector, by=by, timeout=timeout2880 )2881 try:2882 scroll_distance = js_utils.get_scroll_distance_to_element(2883 self.driver, element2884 )2885 if abs(scroll_distance) > constants.Values.SSMD:2886 self.__jquery_slow_scroll_to(selector, by)2887 else:2888 self.__slow_scroll_to_element(element)2889 except Exception:2890 self.wait_for_ready_state_complete()2891 time.sleep(0.12)2892 element = self.wait_for_element_visible(2893 selector, by=by, timeout=timeout2894 )2895 self.__slow_scroll_to_element(element)2896 def slow_scroll_to_element(2897 self, selector, by=By.CSS_SELECTOR, timeout=None2898 ):2899 self.slow_scroll_to(selector, by=by, timeout=timeout)2900 def scroll_to_top(self):2901 """ Scroll to the top of the page. """2902 self.__check_scope__()2903 scroll_script = "window.scrollTo(0, 0);"2904 try:2905 self.execute_script(scroll_script)2906 time.sleep(0.012)2907 return True2908 except Exception:2909 return False2910 def scroll_to_bottom(self):2911 """ Scroll to the bottom of the page. """2912 self.__check_scope__()2913 scroll_script = "window.scrollTo(0, 10000);"2914 try:2915 self.execute_script(scroll_script)2916 time.sleep(0.012)2917 return True2918 except Exception:2919 return False2920 def click_xpath(self, xpath):2921 # Technically self.click() will automatically detect an xpath selector,2922 # so self.click_xpath() is just a longer name for the same action.2923 self.click(xpath, by=By.XPATH)2924 def js_click(2925 self, selector, by=By.CSS_SELECTOR, all_matches=False, scroll=True2926 ):2927 """Clicks an element using JavaScript.2928 Can be used to click hidden / invisible elements.2929 If "all_matches" is False, only the first match is clicked.2930 If "scroll" is False, won't scroll unless running in Demo Mode."""2931 self.wait_for_ready_state_complete()2932 selector, by = self.__recalculate_selector(selector, by, xp_ok=False)2933 if by == By.LINK_TEXT:2934 message = (2935 "Pure JavaScript doesn't support clicking by Link Text. "2936 "You may want to use self.jquery_click() instead, which "2937 "allows this with :contains(), assuming jQuery isn't blocked. "2938 "For now, self.js_click() will use a regular WebDriver click."2939 )2940 logger.debug(message)2941 self.click(selector, by=by)2942 return2943 element = self.wait_for_element_present(2944 selector, by=by, timeout=settings.SMALL_TIMEOUT2945 )2946 if self.is_element_visible(how, selector):2947 self.__demo_mode_highlight_if_active(selector, by)2948 if scroll and not self.demo_mode and not self.slow_mode:2949 success = js_utils.scroll_to_element(self.driver, element)2950 if not success:2951 self.wait_for_ready_state_complete()2952 timeout = settings.SMALL_TIMEOUT2953 element = page_actions.wait_for_element_present(2954 self.driver, selector, by, timeout=timeout2955 )2956 css_selector = self.convert_to_css_selector(selector, by=by)2957 css_selector = re.escape(css_selector) # Add "\\" to special chars2958 css_selector = shared.escape_quotes_if_needed(css_selector)2959 action = None2960 pre_action_url = self.driver.current_url2961 pre_window_count = len(self.driver.window_handles)2962 if not all_matches:2963 if ":contains\\(" not in css_selector:2964 self.__js_click(selector, by=by)2965 else:2966 click_script = """jQuery('%s')[0].click();""" % css_selector2967 self.safe_execute_script(click_script)2968 else:2969 if ":contains\\(" not in css_selector:2970 self.__js_click_all(selector, by=by)2971 else:2972 click_script = """jQuery('%s').click();""" % css_selector2973 self.safe_execute_script(click_script)2974 latest_window_count = len(self.driver.window_handles)2975 if (2976 latest_window_count > pre_window_count2977 and (2978 self.recorder_mode2979 or (2980 settings.SWITCH_TO_NEW_TABS_ON_CLICK2981 and self.driver.current_url == pre_action_url2982 )2983 )2984 ):2985 self.__switch_to_newest_window_if_not_blank()2986 self.wait_for_ready_state_complete()2987 self._demo_mode_pause_if_active()2988 def js_click_all(self, selector, by=By.CSS_SELECTOR):2989 """ Clicks all matching elements using pure JS. (No jQuery) """2990 self.js_click(selector, by=By.CSS_SELECTOR, all_matches=True)2991 def jquery_click(self, selector, by=By.CSS_SELECTOR):2992 """Clicks an element using jQuery. (Different from using pure JS.)2993 Can be used to click hidden / invisible elements."""2994 self.__check_scope__()2995 self.wait_for_element_present(2996 selector, by=by, timeout=settings.SMALL_TIMEOUT2997 )2998 if self.is_element_visible(selector, by=by):2999 self.__demo_mode_highlight_if_active(selector, by)3000 selector = self.convert_to_css_selector(selector, by=by)3001 selector = self.__make_css_match_first_element_only(selector)3002 click_script = """jQuery('%s')[0].click();""" % selector3003 self.safe_execute_script(click_script)3004 self._demo_mode_pause_if_active()3005 def jquery_click_all(self, selector, by=By.CSS_SELECTOR):3006 """ Clicks all matching elements using jQuery. """3007 self.__check_scope__()3008 self.wait_for_element_present(3009 selector, by=by, timeout=settings.SMALL_TIMEOUT3010 )3011 if self.is_element_visible(selector, by=by):3012 self.__demo_mode_highlight_if_active(selector, by)3013 css_selector = self.convert_to_css_selector(selector, by=by)3014 click_script = """jQuery('%s').click();""" % css_selector3015 self.safe_execute_script(click_script)3016 self._demo_mode_pause_if_active()3017 def hide_element(self, selector, by=By.CSS_SELECTOR):3018 """ Hide the first element on the page that matches the selector. """3019 self.__check_scope__()3020 selector = self.convert_to_css_selector(selector, by=by)3021 selector = self.__make_css_match_first_element_only(selector)3022 hide_script = """jQuery('%s').hide();""" % selector3023 self.safe_execute_script(hide_script)3024 def hide_elements(self, selector, by=By.CSS_SELECTOR):3025 """ Hide all elements on the page that match the selector. """3026 self.__check_scope__()3027 selector = self.convert_to_css_selector(selector, by=by)3028 hide_script = """jQuery('%s').hide();""" % selector3029 self.safe_execute_script(hide_script)3030 def show_element(self, selector, by=By.CSS_SELECTOR):3031 """ Show the first element on the page that matches the selector. """3032 self.__check_scope__()3033 selector = self.convert_to_css_selector(selector, by=by)3034 selector = self.__make_css_match_first_element_only(selector)3035 show_script = """jQuery('%s').show(0);""" % selector3036 self.safe_execute_script(show_script)3037 def show_elements(self, selector, by=By.CSS_SELECTOR):3038 """ Show all elements on the page that match the selector. """3039 self.__check_scope__()3040 selector = self.convert_to_css_selector(selector, by=by)3041 show_script = """jQuery('%s').show(0);""" % selector3042 self.safe_execute_script(show_script)3043 def remove_element(self, selector, by=By.CSS_SELECTOR):3044 """ Remove the first element on the page that matches the selector. """3045 self.__check_scope__()3046 selector = self.convert_to_css_selector(selector, by=by)3047 selector = self.__make_css_match_first_element_only(selector)3048 remove_script = """jQuery('%s').remove();""" % selector3049 self.safe_execute_script(remove_script)3050 def remove_elements(self, selector, by=By.CSS_SELECTOR):3051 """ Remove all elements on the page that match the selector. """3052 self.__check_scope__()3053 selector, by = self.__recalculate_selector(selector, by)3054 selector = self.convert_to_css_selector(selector, by=by)3055 remove_script = """jQuery('%s').remove();""" % selector3056 self.safe_execute_script(remove_script)3057 def show_file_choosers(self):3058 """Display hidden file-chooser input fields on sites if present."""3059 css_selector = 'input[type="file"]'3060 try:3061 self.show_elements(css_selector)3062 except Exception:3063 pass3064 css_selector = re.escape(css_selector) # Add "\\" to special chars3065 css_selector = self.__escape_quotes_if_needed(css_selector)3066 script = (3067 """var $elements = document.querySelectorAll('%s');3068 var index = 0, length = $elements.length;3069 for(; index < length; index++){3070 the_class = $elements[index].getAttribute('class');3071 new_class = the_class.replaceAll('hidden', 'visible');3072 $elements[index].setAttribute('class', new_class);}"""3073 % css_selector3074 )3075 try:3076 self.execute_script(script)3077 except Exception:3078 pass3079 def get_domain_url(self, url):3080 self.__check_scope__()3081 return page_utils.get_domain_url(url)3082 def get_beautiful_soup(self, source=None):3083 """BeautifulSoup is a toolkit for dissecting an HTML document3084 and extracting what you need. It's great for screen-scraping!3085 See: https://www.crummy.com/software/BeautifulSoup/bs4/doc/3086 """3087 from bs4 import BeautifulSoup3088 if not source:3089 source = self.get_page_source()3090 soup = BeautifulSoup(source, "html.parser")3091 return soup3092 def get_unique_links(self):3093 """Get all unique links in the html of the page source.3094 Page links include those obtained from:3095 "a"->"href", "img"->"src", "link"->"href", and "script"->"src".3096 """3097 page_url = self.get_current_url()3098 soup = self.get_beautiful_soup(self.get_page_source())3099 links = page_utils._get_unique_links(page_url, soup)3100 return links3101 def get_link_status_code(3102 self,3103 link,3104 allow_redirects=False,3105 timeout=5,3106 verify=False,3107 ):3108 """Get the status code of a link.3109 If the timeout is set to less than 1, it becomes 1.3110 If the timeout is exceeded by requests.get(), it will return a 404.3111 If "verify" is False, will ignore certificate errors.3112 For a list of available status codes, see:3113 https://en.wikipedia.org/wiki/List_of_HTTP_status_codes3114 """3115 if self.__requests_timeout:3116 timeout = self.__requests_timeout3117 if timeout < 1:3118 timeout = 13119 status_code = page_utils._get_link_status_code(3120 link,3121 allow_redirects=allow_redirects,3122 timeout=timeout,3123 verify=verify,3124 )3125 return status_code3126 def __get_link_if_404_error(self, link):3127 status_code = str(self.get_link_status_code(link))3128 if status_code == "404":3129 # Verify again to be sure. (In case of multi-threading overload.)3130 status_code = str(self.get_link_status_code(link))3131 if status_code == "404":3132 return link3133 else:3134 return None3135 else:3136 return None3137 def print_unique_links_with_status_codes(self):3138 """Finds all unique links in the html of the page source3139 and then prints out those links with their status codes.3140 Format: ["link" -> "status_code"] (per line)3141 Page links include those obtained from:3142 "a"->"href", "img"->"src", "link"->"href", and "script"->"src".3143 """3144 page_url = self.get_current_url()3145 soup = self.get_beautiful_soup(self.get_page_source())3146 page_utils._print_unique_links_with_status_codes(page_url, soup)3147 def __fix_unicode_conversion(self, text):3148 """ Fixing Chinese characters when converting from PDF to HTML. """3149 text = text.replace("\u2f8f", "\u884c")3150 text = text.replace("\u2f45", "\u65b9")3151 text = text.replace("\u2f08", "\u4eba")3152 text = text.replace("\u2f70", "\u793a")3153 text = text.replace("\xe2\xbe\x8f", "\xe8\xa1\x8c")3154 text = text.replace("\xe2\xbd\xb0", "\xe7\xa4\xba")3155 text = text.replace("\xe2\xbe\x8f", "\xe8\xa1\x8c")3156 text = text.replace("\xe2\xbd\x85", "\xe6\x96\xb9")3157 return text3158 def get_pdf_text(3159 self,3160 pdf,3161 page=None,3162 maxpages=None,3163 password=None,3164 codec="utf-8",3165 wrap=False,3166 nav=False,3167 override=False,3168 caching=True,3169 ):3170 import warnings3171 with warnings.catch_warnings():3172 warnings.simplefilter("ignore", category=UserWarning)3173 from pdfminer.high_level import extract_text3174 if not password:3175 password = ""3176 if not maxpages:3177 maxpages = 03178 if not pdf.lower().endswith(".pdf"):3179 raise Exception("%s is not a PDF file! (Expecting a .pdf)" % pdf)3180 file_path = None3181 if page_utils.is_valid_url(pdf):3182 downloads_folder = download_helper.get_downloads_folder()3183 if nav:3184 if self.get_current_url() != pdf:3185 self.open(pdf)3186 file_name = pdf.split("/")[-1]3187 file_path = downloads_folder + "/" + file_name3188 if not os.path.exists(file_path):3189 self.download_file(pdf)3190 elif override:3191 self.download_file(pdf)3192 else:3193 if not os.path.exists(pdf):3194 raise Exception("%s is not a valid URL or file path!" % pdf)3195 file_path = os.path.abspath(pdf)3196 page_search = None # (Pages are delimited by '\x0c')3197 if type(page) is list:3198 pages = page3199 page_search = []3200 for page in pages:3201 page_search.append(page - 1)3202 elif type(page) is int:3203 page = page - 13204 if page < 0:3205 page = 03206 page_search = [page]3207 else:3208 page_search = None3209 pdf_text = extract_text(3210 file_path,3211 password="",3212 page_numbers=page_search,3213 maxpages=maxpages,3214 caching=caching,3215 codec=codec,3216 )3217 pdf_text = self.__fix_unicode_conversion(pdf_text)3218 if wrap:3219 pdf_text = pdf_text.replace(" \n", " ")3220 pdf_text = pdf_text.strip() # Remove leading and trailing whitespace3221 return pdf_text3222 def create_folder(self, folder):3223 """ Creates a folder of the given name if it doesn't already exist. """3224 if folder.endswith("/"):3225 folder = folder[:-1]3226 if len(folder) < 1:3227 raise Exception("Minimum folder name length = 1.")3228 if not os.path.exists(folder):3229 try:3230 os.makedirs(folder)3231 except Exception:3232 pass3233 def choose_file(3234 self, selector, file_path, by=By.CSS_SELECTOR, timeout=None3235 ):3236 """This method is used to choose a file to upload to a website.3237 It works by populating a file-chooser "input" field of type="file".3238 A relative file_path will get converted into an absolute file_path.3239 Example usage:3240 self.choose_file('input[type="file"]', "my_dir/my_file.txt")3241 """3242 self.__check_scope__()3243 timeout = self.get_timeout(timeout, constants.SMALL_TIMEOUT)3244 selector, by = self.__recalculate_selector(selector, by)3245 abs_path = os.path.abspath(file_path)3246 element = self.wait_for_element_present(3247 selector, by=by, timeout=timeout3248 )3249 if self.is_element_visible(selector, by=by):3250 self.__demo_mode_highlight_if_active(selector, by)3251 if not self.demo_mode and not self.slow_mode:3252 self.__scroll_to_element(element, selector, by)3253 else:3254 choose_file_selector = 'input[type="file"]'3255 if self.is_element_present(choose_file_selector):3256 if not self.is_element_visible(choose_file_selector):3257 self.show_file_choosers()3258 if self.is_element_visible(selector, by=by):3259 self.__demo_mode_highlight_if_active(selector, by)3260 if not self.demo_mode and not self.slow_mode:3261 self.__scroll_to_element(element, selector, by)3262 pre_action_url = self.driver.current_url3263 if type(abs_path) is int or type(abs_path) is float:3264 abs_path = str(abs_path)3265 try:3266 if self.browser == "safari":3267 try:3268 element.send_keys(abs_path)3269 except NoSuchElementException:3270 pass # May get this error on Safari even if upload works.3271 else:3272 element.send_keys(abs_path)3273 except (StaleElementReferenceException, ElementNotInteractableException):3274 self.wait_for_ready_state_complete()3275 time.sleep(0.16)3276 element = self.wait_for_element_present(3277 selector, by=by, timeout=timeout3278 )3279 if self.browser == "safari":3280 try:3281 element.send_keys(abs_path)3282 except NoSuchElementException:3283 pass # May get this error on Safari even if upload works.3284 else:3285 element.send_keys(abs_path)3286 if self.demo_mode:3287 if self.driver.current_url != pre_action_url:3288 self._demo_mode_pause_if_active()3289 else:3290 self._demo_mode_pause_if_active(tiny=True)3291 elif self.slow_mode:3292 self._slow_mode_pause_if_active()3293 def save_element_as_image_file(3294 self, selector, file_name, folder=None, overlay_text=""3295 ):3296 """Take a screenshot of an element and save it as an image file.3297 If no folder is specified, will save it to the current folder.3298 If overlay_text is provided, will add that to the saved image."""3299 element = self.wait_for_element_visible(selector)3300 element_png = element.screenshot_as_png3301 if len(file_name.split(".")[0]) < 1:3302 raise Exception("Error: file_name length must be > 0.")3303 if not file_name.endswith(".png"):3304 file_name = file_name + ".png"3305 image_file_path = None3306 if folder:3307 if folder.endswith("/"):3308 folder = folder[:-1]3309 if len(folder) > 0:3310 self.create_folder(folder)3311 image_file_path = "%s/%s" % (folder, file_name)3312 if not image_file_path:3313 image_file_path = file_name3314 with open(image_file_path, "wb") as file:3315 file.write(element_png)3316 # Add a text overlay if given3317 if type(overlay_text) is str and len(overlay_text) > 0:3318 from PIL import Image, ImageDraw3319 text_rows = overlay_text.split("\n")3320 len_text_rows = len(text_rows)3321 max_width = 03322 for text_row in text_rows:3323 if len(text_row) > max_width:3324 max_width = len(text_row)3325 image = Image.open(image_file_path)3326 draw = ImageDraw.Draw(image)3327 draw.rectangle(3328 (0, 0, (max_width * 6) + 6, 16 * len_text_rows),3329 fill=(236, 236, 28),3330 )3331 draw.text(3332 (4, 2), # Coordinates3333 overlay_text, # Text3334 (8, 38, 176), # Color3335 )3336 image.save(image_file_path, "PNG", quality=100, optimize=True)3337 def download_file(self, file_url, destination_folder=None):3338 """Downloads the file from the url to the destination folder.3339 If no destination folder is specified, the default one is used.3340 (The default [Downloads Folder] = "./downloaded_files")"""3341 if not destination_folder:3342 destination_folder = constants.Files.DOWNLOADS_FOLDER3343 if not os.path.exists(destination_folder):3344 os.makedirs(destination_folder)3345 page_utils._download_file_to(file_url, destination_folder)3346 def save_file_as(self, file_url, new_file_name, destination_folder=None):3347 """Similar to self.download_file(), except that you get to rename the3348 file being downloaded to whatever you want."""3349 if not destination_folder:3350 destination_folder = constants.Files.DOWNLOADS_FOLDER3351 page_utils._download_file_to(3352 file_url, destination_folder, new_file_name3353 )3354 def save_data_as(self, data, file_name, destination_folder=None):3355 """Saves the data specified to a file of the name specified.3356 If no destination folder is specified, the default one is used.3357 (The default [Downloads Folder] = "./downloaded_files")"""3358 if not destination_folder:3359 destination_folder = constants.Files.DOWNLOADS_FOLDER3360 page_utils._save_data_as(data, destination_folder, file_name)3361 def get_downloads_folder(self):3362 """Returns the path of the SeleniumBase "downloaded_files/" folder.3363 Calling self.download_file(file_url) will put that file in here.3364 With the exception of Safari, IE, and Chromium Guest Mode,3365 any clicks that download files will also use this folder3366 rather than using the browser's default "downloads/" path."""3367 self.__check_scope__()3368 return download_helper.get_downloads_folder()3369 def get_browser_downloads_folder(self):3370 """Returns the path that is used when a click initiates a download.3371 SeleniumBase overrides the system path to be "downloaded_files/"3372 The path can't be changed on Safari, IE, or Chromium Guest Mode.3373 The same problem occurs when using an out-of-date chromedriver.3374 """3375 self.__check_scope__()3376 if self.is_chromium() and self.guest_mode and not self.headless:3377 # Guest Mode (non-headless) can force the default downloads path3378 return os.path.join(os.path.expanduser("~"), "downloads")3379 elif self.browser == "safari" or self.browser == "ie":3380 # Can't change the system [Downloads Folder] on Safari or IE3381 return os.path.join(os.path.expanduser("~"), "downloads")3382 elif (3383 self.driver.capabilities["browserName"].lower() == "chrome"3384 and int(self.get_chromedriver_version().split(".")[0]) < 733385 and self.headless3386 ):3387 return os.path.join(os.path.expanduser("~"), "downloads")3388 else:3389 return download_helper.get_downloads_folder()3390 return os.path.join(os.path.expanduser("~"), "downloads")3391 def get_path_of_downloaded_file(self, file, browser=False):3392 """ Returns the OS path of the downloaded file. """3393 if browser:3394 return os.path.join(self.get_browser_downloads_folder(), file)3395 else:3396 return os.path.join(self.get_downloads_folder(), file)3397 def is_downloaded_file_present(self, file, browser=False):3398 """Returns True if the file exists in the pre-set [Downloads Folder].3399 For browser click-initiated downloads, SeleniumBase will override3400 the system [Downloads Folder] to be "./downloaded_files/",3401 but that path can't be overridden when using Safari, IE,3402 or Chromium Guest Mode, which keeps the default system path.3403 self.download_file(file_url) will always use "./downloaded_files/".3404 @Params3405 file - The filename of the downloaded file.3406 browser - If True, uses the path set by click-initiated downloads.3407 If False, uses the self.download_file(file_url) path.3408 Those paths are often the same. (browser-dependent)3409 (Default: False).3410 """3411 return os.path.exists(3412 self.get_path_of_downloaded_file(file, browser=browser)3413 )3414 def delete_downloaded_file_if_present(self, file, browser=False):3415 """Deletes the file from the [Downloads Folder] if the file exists.3416 For browser click-initiated downloads, SeleniumBase will override3417 the system [Downloads Folder] to be "./downloaded_files/",3418 but that path can't be overridden when using Safari, IE,3419 or Chromium Guest Mode, which keeps the default system path.3420 self.download_file(file_url) will always use "./downloaded_files/".3421 @Params3422 file - The filename to be deleted from the [Downloads Folder].3423 browser - If True, uses the path set by click-initiated downloads.3424 If False, uses the self.download_file(file_url) path.3425 Those paths are usually the same. (browser-dependent)3426 (Default: False).3427 """3428 if self.is_downloaded_file_present(file, browser=browser):3429 file_path = self.get_path_of_downloaded_file(file, browser=browser)3430 try:3431 os.remove(file_path)3432 except Exception:3433 pass3434 def delete_downloaded_file(self, file, browser=False):3435 """Same as self.delete_downloaded_file_if_present()3436 Deletes the file from the [Downloads Folder] if the file exists.3437 For browser click-initiated downloads, SeleniumBase will override3438 the system [Downloads Folder] to be "./downloaded_files/",3439 but that path can't be overridden when using Safari, IE,3440 or Chromium Guest Mode, which keeps the default system path.3441 self.download_file(file_url) will always use "./downloaded_files/".3442 @Params3443 file - The filename to be deleted from the [Downloads Folder].3444 browser - If True, uses the path set by click-initiated downloads.3445 If False, uses the self.download_file(file_url) path.3446 Those paths are usually the same. (browser-dependent)3447 (Default: False).3448 """3449 if self.is_downloaded_file_present(file, browser=browser):3450 file_path = self.get_path_of_downloaded_file(file, browser=browser)3451 try:3452 os.remove(file_path)3453 except Exception:3454 pass3455 def wait_for_attribute(3456 self, selector, attribute, value=None, by=By.CSS_SELECTOR, timeout=None3457 ):3458 """Raises an exception if the element attribute/value is not found.3459 If the value is not specified, the attribute only needs to exist.3460 Returns the element that contains the attribute if successful.3461 Default timeout = LARGE_TIMEOUT."""3462 self.__check_scope__()3463 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)3464 if self.__is_shadow_selector(selector):3465 return self.__wait_for_shadow_attribute_present(3466 selector, attribute, value=value, timeout=timeout3467 )3468 return page_actions.wait_for_attribute(3469 self.driver,3470 selector,3471 attribute,3472 value=value,3473 by=by,3474 timeout=timeout,3475 )3476 def inspect_html(self):3477 """Inspects the Page HTML with HTML-Inspector.3478 (https://github.com/philipwalton/html-inspector)3479 (https://cdnjs.com/libraries/html-inspector)3480 Prints the results and also returns them."""3481 self._activate_html_inspector()3482 self.wait_for_ready_state_complete()3483 script = """HTMLInspector.inspect();"""3484 try:3485 self.execute_script(script)3486 except Exception:3487 # If unable to load the JavaScript, skip inspection and return.3488 msg = "(Unable to load HTML-Inspector JS! Inspection Skipped!)"3489 print("\n" + msg)3490 return msg3491 time.sleep(0.1)3492 browser_logs = []3493 try:3494 browser_logs = self.driver.get_log("browser")3495 except (ValueError, WebDriverException):3496 # If unable to get browser logs, skip the assert and return.3497 msg = "(Unable to Inspect HTML! -> Only works on Chromium!)"3498 print("\n" + msg)3499 return msg3500 messenger_library = "//cdnjs.cloudflare.com/ajax/libs/messenger"3501 url = self.get_current_url()3502 header = "\n* HTML Inspection Results: %s" % url3503 results = [header]3504 row_count = 03505 for entry in browser_logs:3506 message = entry["message"]3507 if "0:6053 " in message:3508 message = message.split("0:6053")[1]3509 message = message.replace("\\u003C", "<")3510 if message.startswith(' "') and message.count('"') == 2:3511 message = message.split('"')[1]3512 message = "X - " + message3513 if messenger_library not in message:3514 if message not in results:3515 results.append(message)3516 row_count += 13517 if row_count > 0:3518 results.append("* (See the Console output for details!)")3519 else:3520 results.append("* (No issues detected!)")3521 results = "\n".join(results)3522 print(results)3523 return results3524 def is_valid_url(self, url):3525 """ Return True if the url is a valid url. """3526 return page_utils.is_valid_url(url)3527 def get_mfa_code(self, totp_key=None):3528 """Same as get_totp_code() and get_google_auth_password().3529 Returns a time-based one-time password based on the3530 Google Authenticator algorithm for multi-factor authentication.3531 If the "totp_key" is not specified, this method defaults3532 to using the one provided in [seleniumbase/config/settings.py].3533 Google Authenticator codes expire & change at 30-sec intervals.3534 If the fetched password expires in the next 1.5 seconds, waits3535 for a new one before returning it (may take up to 1.5 seconds).3536 See https://pyotp.readthedocs.io/en/latest/ for details."""3537 import pyotp3538 if not totp_key:3539 totp_key = settings.TOTP_KEY3540 epoch_interval = time.time() / 30.03541 cycle_lifespan = float(epoch_interval) - int(epoch_interval)3542 if float(cycle_lifespan) > 0.95:3543 # Password expires in the next 1.5 seconds. Wait for a new one.3544 for i in range(30):3545 time.sleep(0.05)3546 epoch_interval = time.time() / 30.03547 cycle_lifespan = float(epoch_interval) - int(epoch_interval)3548 if not float(cycle_lifespan) > 0.95:3549 # The new password cycle has begun3550 break3551 totp = pyotp.TOTP(totp_key)3552 return str(totp.now())3553 def enter_mfa_code(3554 self, selector, totp_key=None, by=By.CSS_SELECTOR, timeout=None3555 ):3556 """Enters into the field a Multi-Factor Authentication TOTP Code.3557 If the "totp_key" is not specified, this method defaults3558 to using the one provided in [seleniumbase/config/settings.py].3559 The TOTP code is generated by the Google Authenticator Algorithm.3560 This method will automatically press ENTER after typing the code."""3561 self.__check_scope__()3562 if not timeout:3563 timeout = settings.SMALL_TIMEOUT3564 self.wait_for_element_visible(selector, by=by, timeout=timeout)3565 mfa_code = self.get_mfa_code(totp_key)3566 self.update_text(selector, mfa_code + "\n", by=by, timeout=timeout)3567 def convert_css_to_xpath(self, css):3568 return css_to_xpath.convert_css_to_xpath(css)3569 def convert_xpath_to_css(self, xpath):3570 return xpath_to_css.convert_xpath_to_css(xpath)3571 def convert_to_css_selector(self, selector, by):3572 """This method converts a selector to a CSS_SELECTOR.3573 jQuery commands require a CSS_SELECTOR for finding elements.3574 This method should only be used for jQuery/JavaScript actions.3575 Pure JavaScript doesn't support using a:contains("LINK_TEXT")."""3576 if by == By.CSS_SELECTOR:3577 return selector3578 elif by == By.ID:3579 return "#%s" % selector3580 elif by == By.CLASS_NAME:3581 return ".%s" % selector3582 elif by == By.NAME:3583 return '[name="%s"]' % selector3584 elif by == By.TAG_NAME:3585 return selector3586 elif by == By.XPATH:3587 return self.convert_xpath_to_css(selector)3588 elif by == By.LINK_TEXT:3589 return 'a:contains("%s")' % selector3590 elif by == By.PARTIAL_LINK_TEXT:3591 return 'a:contains("%s")' % selector3592 else:3593 raise Exception(3594 "Exception: Could not convert {%s}(by=%s) to CSS_SELECTOR!"3595 % (selector, by)3596 )3597 def set_value(3598 self, selector, text, by=By.CSS_SELECTOR, timeout: =None, scroll=True3599 ):3600 """ This method uses JavaScript to update a text field. """3601 self.__check_scope__()3602 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)3603 self.wait_for_ready_state_complete()3604 self.wait_for_element_present(selector, by=by, timeout=timeout)3605 css_selector = self.convert_to_css_selector(selector, by=by)3606 self.__demo_mode_highlight_if_active(how, selector)3607 if scroll and not self.demo_mode and not self.slow_mode:3608 self.scroll_to(how, selector, timeout)3609 if type(text) is int or type(text) is float:3610 text = str(text)3611 value = re.escape(text)3612 value = shared.escape_quotes_if_needed(value)3613 pre_escape_css_selector = css_selector3614 css_selector = re.escape(css_selector) # Add "\\" to special chars3615 css_selector = shared.escape_quotes_if_needed(css_selector)3616 the_type = None3617 if ":contains\\(" not in css_selector:3618 get_type_script = (3619 """return document.querySelector('%s').getAttribute('type');"""3620 % css_selector3621 )3622 the_type = self.execute_script(get_type_script) # Used later3623 script = """document.querySelector('%s').value='%s';""" % (3624 css_selector,3625 value,3626 )3627 self.execute_script(script)3628 else:3629 script = """jQuery('%s')[0].value='%s';""" % (css_selector, value)3630 self.safe_execute_script(script)3631 if text.endswith("\n"):3632 element = self.wait_for_element_present(3633 orginal_selector, by=by, timeout=timeout3634 )3635 element.send_keys(Keys.RETURN)3636 if settings.WAIT_FOR_RSC_ON_PAGE_LOADS:3637 self.wait_for_ready_state_complete()3638 else:3639 if the_type == "range" and ":contains\\(" not in css_selector:3640 # Some input sliders need a mouse event to trigger listeners.3641 try:3642 mouse_move_script = (3643 """m_elm = document.querySelector('%s');"""3644 """m_evt = new Event('mousemove');"""3645 """m_elm.dispatchEvent(m_evt);"""3646 % css_selector3647 )3648 self.execute_script(mouse_move_script)3649 except Exception:3650 pass3651 self._demo_mode_pause_if_active()3652 def js_update_text(self, selector, text, by=By.CSS_SELECTOR, timeout=None):3653 """JavaScript + send_keys are used to update a text field.3654 Performs self.set_value() and triggers event listeners.3655 If text ends in "\n", set_value() presses RETURN after.3656 Works faster than send_keys() alone due to the JS call.3657 """3658 self.__check_scope__()3659 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)3660 if type(text) is int or type(text) is float:3661 text = str(text)3662 self.set_value(selector, text, by=by, timeout=timeout)3663 if not text.endswith("\n"):3664 try:3665 element = page_actions.wait_for_element_present(3666 self.driver, selector, by, timeout=0.23667 )3668 element.send_keys(" " + Keys.BACK_SPACE)3669 except Exception:3670 pass3671 def js_type(3672 self,3673 text: str | None,3674 how: SeleniumBy,3675 selector: str = Field(..., strict=True, min_length=1),3676 timeout: OptionalInt = None,3677 ):3678 """Same as self.js_update_text()3679 JavaScript + send_keys are used to update a text field.3680 Performs self.set_value() and triggers event listeners.3681 If text ends in "\n", set_value() presses RETURN after.3682 Works faster than send_keys() alone due to the JS call.3683 """3684 self.__check_scope__()3685 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)3686 self.js_update_text(text, selector, how, timeout)3687 def set_text(3688 self,3689 text: str | None,3690 how: SeleniumBy,3691 selector: str = Field(..., strict=True, min_length=1),3692 timeout: OptionalInt = None3693 ):3694 """Same as self.js_update_text()3695 JavaScript + send_keys are used to update a text field.3696 Performs self.set_value() and triggers event listeners.3697 If text ends in "\n", set_value() presses RETURN after.3698 Works faster than send_keys() alone due to the JS call.3699 If not an input or textarea, sets textContent instead."""3700 self.__check_scope__()3701 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)3702 self.wait_for_ready_state_complete()3703 element = element_actions.wait_for_element_present(self.driver, how, selector, timeout)3704 if element.tag_name == "input" or element.tag_name == "textarea":3705 self.js_update_text(text, how, selector, timeout)3706 else:3707 self.set_text_content(text, how, selector, timeout)3708 def set_text_content(3709 self,3710 text: str | None,3711 how: SeleniumBy,3712 selector: str = Field(..., strict=True, min_length=1),3713 timeout: OptionalInt = None,3714 scroll=False3715 ):3716 """This method uses JavaScript to set an element's textContent.3717 If the element is an input or textarea, sets the value instead."""3718 self.__check_scope__()3719 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)3720 self.wait_for_ready_state_complete()3721 element = element_actions.wait_for_element_present(self.driver, how, selector, timeout)3722 if element.tag_name == "input" or element.tag_name == "textarea":3723 self.js_update_text(text, how, selector, timeout=timeout)3724 return3725 css_selector = self.convert_to_css_selector(how, selector)3726 if scroll:3727 self.__demo_mode_highlight_if_active(how, selector)3728 if not self.demo_mode and not self.slow_mode:3729 self.scroll_to(how, selector, timeout=timeout)3730 if type(text) is int or type(text) is float:3731 text = str(text)3732 value = re.escape(text)3733 value = shared.escape_quotes_if_needed(value)3734 css_selector = re.escape(css_selector) # Add "\\" to special chars3735 css_selector = shared.escape_quotes_if_needed(css_selector)3736 if ":contains\\(" not in css_selector:3737 script = """document.querySelector('%s').textContent='%s';""" % (3738 css_selector,3739 value,3740 )3741 self.execute_script(script)3742 else:3743 script = """jQuery('%s')[0].textContent='%s';""" % (3744 css_selector,3745 value,3746 )3747 self.safe_execute_script(script)3748 self._demo_mode_pause_if_active()3749 def jquery_update_text(3750 self,3751 text: str | None,3752 how: SeleniumBy,3753 selector: str = Field(..., strict=True, min_length=1),3754 timeout: OptionalInt = None3755 ):3756 """This method uses jQuery to update a text field.3757 If the text string ends with the newline character,3758 Selenium finishes the call, which simulates pressing3759 {Enter/Return} after the text is entered."""3760 self.__check_scope__()3761 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)3762 element = self.wait_for_element_visible(how, selector, timeout)3763 self.__demo_mode_highlight_if_active(how, selector)3764 self.scroll_to(how, selector)3765 selector = self.convert_to_css_selector(how, selector)3766 selector = self.__make_css_match_first_element_only(selector)3767 selector = shared.escape_quotes_if_needed(selector)3768 text = re.escape(text)3769 text = shared.escape_quotes_if_needed(text)3770 update_text_script = """jQuery('%s').val('%s');""" % (selector, text)3771 self.safe_execute_script(update_text_script)3772 if text.endswith("\n"):3773 element.send_keys("\n")3774 self._demo_mode_pause_if_active()3775 def get_value(3776 self,3777 how: SeleniumBy,3778 selector: str = Field(..., strict=True, min_length=1),3779 timeout: OptionalInt = None3780 ) -> Optional[Any]:3781 """This method uses JavaScript to get the value of an input field.3782 (Works on both input fields and textarea fields.)"""3783 self.__check_scope__()3784 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)3785 self.wait_for_ready_state_complete()3786 self.wait_for_element_present(how, selector, timeout=timeout)3787 orginal_selector = selector3788 css_selector = self.convert_to_css_selector(how, selector)3789 self.__demo_mode_highlight_if_active(how, selector)3790 if not self.demo_mode and not self.slow_mode:3791 self.scroll_to(how, selector, timeout=timeout)3792 css_selector = re.escape(css_selector) # Add "\\" to special chars3793 css_selector = shared.escape_quotes_if_needed(css_selector)3794 if ":contains\\(" not in css_selector:3795 script = """return document.querySelector('%s').value;""" % (3796 css_selector3797 )3798 value = self.execute_script(script)3799 else:3800 script = """return jQuery('%s')[0].value;""" % css_selector3801 value = self.safe_execute_script(script)3802 return value3803 def set_time_limit(self, time_limit):3804 self.__check_scope__()3805 if time_limit:3806 try:3807 sb_config.time_limit = float(time_limit)3808 except Exception:3809 sb_config.time_limit = None3810 else:3811 sb_config.time_limit = None3812 if sb_config.time_limit and sb_config.time_limit > 0:3813 sb_config.time_limit_ms = int(sb_config.time_limit * 1000.0)3814 self.time_limit = sb_config.time_limit3815 else:3816 self.time_limit = None3817 sb_config.time_limit = None3818 sb_config.time_limit_ms = None3819 def set_default_timeout(self, timeout):3820 """This method changes the default timeout values of test methods3821 for the duration of the current test.3822 Effected timeouts: (used by methods that wait for elements)3823 * settings.SMALL_TIMEOUT - (default value: 6 seconds)3824 * settings.LARGE_TIMEOUT - (default value: 10 seconds)3825 The minimum allowable default timeout is: 0.5 seconds.3826 The maximum allowable default timeout is: 60.0 seconds.3827 (Test methods can still override timeouts outside that range.)3828 """3829 self.__check_scope__()3830 if not type(timeout) is int and not type(timeout) is float:3831 raise Exception('Expecting a numeric value for "timeout"!')3832 if timeout < 0:3833 raise Exception('The "timeout" cannot be a negative number!')3834 timeout = float(timeout)3835 # Min default timeout: 0.5 seconds. Max default timeout: 60.0 seconds.3836 min_timeout = 0.53837 max_timeout = 60.03838 if timeout < min_timeout:3839 logging.info("Minimum default timeout = %s" % min_timeout)3840 timeout = min_timeout3841 elif timeout > max_timeout:3842 logging.info("Maximum default timeout = %s" % max_timeout)3843 timeout = max_timeout3844 self.__overrided_default_timeouts = True3845 sb_config._is_timeout_changed = True3846 settings.SMALL_TIMEOUT = timeout3847 settings.LARGE_TIMEOUT = timeout3848 def reset_default_timeout(self):3849 """Reset default timeout values to the original from settings.py3850 This method reverts the changes made by set_default_timeout()"""3851 if self.__overrided_default_timeouts:3852 if sb_config._SMALL_TIMEOUT and sb_config._LARGE_TIMEOUT:3853 settings.SMALL_TIMEOUT = sb_config._SMALL_TIMEOUT3854 settings.LARGE_TIMEOUT = sb_config._LARGE_TIMEOUT3855 sb_config._is_timeout_changed = False3856 self.__overrided_default_timeouts = False3857 def skip(self, reason=""):3858 """ Mark the test as Skipped. """3859 self.__check_scope__()3860 if self.dashboard:3861 test_id = self.__get_test_id_2()3862 if hasattr(self, "_using_sb_fixture"):3863 test_id = sb_config._test_id3864 if (3865 test_id in sb_config._results.keys()3866 and sb_config._results[test_id] == "Passed"3867 ):3868 # Duplicate tearDown() called where test already passed3869 self.__passed_then_skipped = True3870 self.__will_be_skipped = True3871 sb_config._results[test_id] = "Skipped"3872 if hasattr(self, "with_db_reporting") and self.with_db_reporting:3873 self.__skip_reason = reason3874 # Add skip reason to the logs3875 if not hasattr(self, "_using_sb_fixture"):3876 test_id = self.__get_test_id() # Recalculate the test id3877 test_logpath = os.path.join(self.log_path, test_id)3878 self.__create_log_path_as_needed(test_logpath)3879 browser = self.browser3880 if not reason:3881 reason = "No skip reason given"3882 log_helper.log_skipped_test_data(3883 self, test_logpath, self.driver, browser, reason3884 )3885 # Finally skip the test for real3886 self.skipTest(reason)3887 # Application "Local Storage" controls3888 def set_local_storage_item(self, key, value):3889 self.__check_scope__()3890 self.execute_script(3891 "window.localStorage.setItem('{}', '{}');".format(key, value)3892 )3893 def get_local_storage_item(self, key):3894 self.__check_scope__()3895 return self.execute_script(3896 "return window.localStorage.getItem('{}');".format(key)3897 )3898 def remove_local_storage_item(self, key):3899 self.__check_scope__()3900 self.execute_script(3901 "window.localStorage.removeItem('{}');".format(key)3902 )3903 def clear_local_storage(self):3904 self.__check_scope__()3905 self.execute_script("window.localStorage.clear();")3906 def get_local_storage_keys(self):3907 self.__check_scope__()3908 return self.execute_script(3909 "var ls = window.localStorage, keys = []; "3910 "for (var i = 0; i < ls.length; ++i) "3911 " keys[i] = ls.key(i); "3912 "return keys;"3913 )3914 def get_local_storage_items(self):3915 self.__check_scope__()3916 return self.execute_script(3917 r"var ls = window.localStorage, items = {}; "3918 "for (var i = 0, k; i < ls.length; ++i) "3919 " items[k = ls.key(i)] = ls.getItem(k); "3920 "return items;"3921 )3922 # Application "Session Storage" controls3923 def set_session_storage_item(self, key, value):3924 self.__check_scope__()3925 self.execute_script(3926 "window.sessionStorage.setItem('{}', '{}');".format(key, value)3927 )3928 def get_session_storage_item(self, key):3929 self.__check_scope__()3930 return self.execute_script(3931 "return window.sessionStorage.getItem('{}');".format(key)3932 )3933 def remove_session_storage_item(self, key):3934 self.__check_scope__()3935 self.execute_script(3936 "window.sessionStorage.removeItem('{}');".format(key)3937 )3938 def clear_session_storage(self):3939 self.__check_scope__()3940 self.execute_script("window.sessionStorage.clear();")3941 def get_session_storage_keys(self):3942 self.__check_scope__()3943 return self.execute_script(3944 "var ls = window.sessionStorage, keys = []; "3945 "for (var i = 0; i < ls.length; ++i) "3946 " keys[i] = ls.key(i); "3947 "return keys;"3948 )3949 def get_session_storage_items(self):3950 self.__check_scope__()3951 return self.execute_script(3952 r"var ls = window.sessionStorage, items = {}; "3953 "for (var i = 0, k; i < ls.length; ++i) "3954 " items[k = ls.key(i)] = ls.getItem(k); "3955 "return items;"3956 )3957 ############3958 # Duplicates (Avoids name confusion when migrating from other frameworks.)3959 def open_url(self, url):3960 """ Same as self.open() """3961 self.open(url)3962 def visit(self, url):3963 """ Same as self.open() """3964 self.open(url)3965 def visit_url(self, url):3966 """ Same as self.open() """3967 self.open(url)3968 def goto(self, url):3969 """ Same as self.open() """3970 self.open(url)3971 def go_to(self, url):3972 """ Same as self.open() """3973 self.open(url)3974 def reload(self):3975 """ Same as self.refresh_page() """3976 self.refresh_page()3977 def reload_page(self):3978 """ Same as self.refresh_page() """3979 self.refresh_page()3980 def open_new_tab(self, switch_to=True):3981 """ Same as self.open_new_window() """3982 self.open_new_window(switch_to=switch_to)3983 def switch_to_tab(self, tab, timeout=None):3984 """ Same as self.switch_to_window()3985 Switches control of the browser to the specified window.3986 The window can be an integer: 0 -> 1st tab, 1 -> 2nd tab, etc...3987 Or it can be a list item from self.driver.window_handles """3988 self.switch_to_window(window=tab, timeout=timeout)3989 def switch_to_default_tab(self):3990 """ Same as self.switch_to_default_window() """3991 self.switch_to_default_window()3992 def switch_to_newest_tab(self):3993 """ Same as self.switch_to_newest_window() """3994 self.switch_to_newest_window()3995 def input(3996 self, selector, text, by=By.CSS_SELECTOR, timeout=None, retry=False3997 ):3998 """ Same as self.update_text() """3999 self.__check_scope__()4000 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)4001 self.update_text(selector, text, by=by, timeout=timeout, retry=retry)4002 def fill(4003 self, selector, text, by=By.CSS_SELECTOR, timeout=None, retry=False4004 ):4005 """ Same as self.update_text() """4006 self.__check_scope__()4007 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)4008 self.update_text(selector, text, by=by, timeout=timeout, retry=retry)4009 def write(4010 self, selector, text, by=By.CSS_SELECTOR, timeout=None, retry=False4011 ):4012 """ Same as self.update_text() """4013 self.__check_scope__()4014 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)4015 self.update_text(selector, text, by=by, timeout=timeout, retry=retry)4016 def send_keys(self, selector, text, by=By.CSS_SELECTOR, timeout=None):4017 """ Same as self.add_text() """4018 self.__check_scope__()4019 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)4020 self.add_text(selector, text, by=by, timeout=timeout)4021 def click_link(self, link_text, timeout=None):4022 """ Same as self.click_link_text() """4023 self.__check_scope__()4024 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)4025 self.click_link_text(link_text, timeout=timeout)4026 def click_partial_link(self, partial_link_text, timeout=None):4027 """ Same as self.click_partial_link_text() """4028 self.__check_scope__()4029 timeout = self.get_timeout(timeout, constants.SMALL_TIMEOUT)4030 self.click_partial_link_text(partial_link_text, timeout=timeout)4031 def wait_for_element_visible(4032 self, selector, by=By.CSS_SELECTOR, timeout=None4033 ):4034 """ Same as self.wait_for_element() """4035 self.__check_scope__()4036 timeout = self.get_timeout(timeout, constants.SMALL_TIMEOUT)4037 if self._is_shadow_selector(selector):4038 return self._shadow.wait_for_shadow_element_visible(4039 selector, timeout4040 )4041 return element_actions.wait_for_element_visible(self.driver, selector, by, timeout)4042 def wait_for_element_interactable(4043 self, selector, by=By.CSS_SELECTOR, timeout=None4044 ):4045 """ Same as self.wait_for_element() """4046 self.__check_scope__()4047 timeout = self.get_timeout(timeout, constants.SMALL_TIMEOUT)4048 if self._is_shadow_selector(selector):4049 return self._shadow.wait_for_shadow_element_visible(4050 selector, timeout4051 )4052 return element_actions.wait_for_element_interactable(self.driver, selector, by, timeout)4053 def wait_for_element_not_present(4054 self, selector, by=By.CSS_SELECTOR, timeout=None4055 ):4056 """Same as self.wait_for_element_absent()4057 Waits for an element to no longer appear in the HTML of a page.4058 A hidden element still counts as appearing in the page HTML.4059 If waiting for elements to be hidden instead of nonexistent,4060 use wait_for_element_not_visible() instead.4061 """4062 self.__check_scope__()4063 timeout = self.get_timeout(timeout, constants.LARGE_TIMEOUT)4064 selector, by = self.__recalculate_selector(selector, by)4065 return page_actions.wait_for_element_absent(4066 self.driver, selector, by, timeout4067 )4068 def get_google_auth_password(self, totp_key=None):4069 """ Same as self.get_mfa_code() """4070 return self.get_mfa_code(totp_key=totp_key)4071 def get_google_auth_code(self, totp_key=None):4072 """ Same as self.get_mfa_code() """4073 return self.get_mfa_code(totp_key=totp_key)4074 def get_totp_code(self, totp_key=None):4075 """ Same as self.get_mfa_code() """4076 return self.get_mfa_code(totp_key=totp_key)4077 def enter_totp_code(4078 self, selector, totp_key=None, by=By.CSS_SELECTOR, timeout=None4079 ):4080 """ Same as self.enter_mfa_code() """4081 return self.enter_mfa_code(4082 selector=selector, totp_key=totp_key, by=by, timeout=timeout4083 )4084 def _print(self, msg):4085 """Same as Python's print(), but won't print during multithreaded runs4086 because overlapping print() commands may lead to unexpected output.4087 In most cases, the print() command won't print for multithreaded tests,4088 but there are some exceptions, and this will take care of those.4089 Here's an example of running tests multithreaded: "pytest -n=4".4090 To force a print during multithreaded tests, use: "sys.stderr.write()".4091 To print without the new-line character end, use: "sys.stdout.write()".4092 """4093 if not sb_config._multithreaded:4094 print(msg)4095 def start_tour(self, name=None, interval=0):4096 self.play_tour(name=name, interval=interval)4097 ############4098 def add_css_link(self, css_link):4099 self.__check_scope__()4100 self.__check_browser()4101 js_utils.add_css_link(self.driver, css_link)4102 def add_js_link(self, js_link):4103 self.__check_scope__()4104 self.__check_browser__()4105 js_utils.add_js_link(self.driver, js_link)4106 def add_css_style(self, css_style):4107 self.__check_scope__()4108 self.__check_browser__()4109 js_utils.add_css_style(self.driver, css_style)4110 def add_js_code_from_link(self, js_link):4111 self.__check_scope__()4112 self.__check_browser__()4113 js_utils.add_js_code_from_link(self.driver, js_link)4114 def add_js_code(self, js_code):...

Full Screen

Full Screen

bart_old.py

Source:bart_old.py Github

copy

Full Screen

...410 else:411 xpath_class = 'day'412 xpath_day = prior_day.day413 414 self.__check_browser()415 416 # click the day before the currently displayed day417 calendar_day = self.browser.find_element_by_xpath(418 f"//td[@class='{xpath_class}' "419 f"and contains(text(), '{xpath_day}')]")420 # https://stackoverflow.com/questions/2009268/how-to-write-an-xpath-query-to-match-two-attributes421 calendar_day.click()422 # refresh soup & re-parse calendar423 self.__scrape_nav_page()424 self.__parse_calendar()425 426 return self.active_date427 428 def __load_nav_page(self):429 if self.verbose: print('Loading navigation page...')430 self.__check_browser()431 # Browse to feed archive page432 self.browser.get(self.url)433 434 # Wait for page to render435 element = WebDriverWait(self.browser, 10).until(436 EC.presence_of_element_located((By.CLASS_NAME, 437 "cursor-link")))438 439 # Get current_first_uri, if none populated440 if not self.current_first_uri:441 self.current_first_uri = self.__get_current_first_uri()442 443 def __scrape_nav_page(self):444 if self.verbose: print('Scraping navigation page...')445 self.__check_browser()446 # Wait for page to render447 element = WebDriverWait(self.browser, 10).until_not(448 EC.text_to_be_present_in_element((By.XPATH, _FIRST_URI_IN_ATT_XPATH), 449 self.current_first_uri))450 self.current_first_uri = self.__get_current_first_uri()451 452 # Scrape page content453 soup = BeautifulSoup(self.browser.page_source, 'lxml')454 # Isolate the calendar and the archiveTimes table455 self.calendar_soup = soup.find('table', 456 {'class': 'table-condensed'})457 self.att_soup = soup.find('table', 458 attrs={'id': 'archiveTimes'}459 ).find('tbody')460 461 def __parse_calendar(self):462 """463 Uses a bs4 ResultSet of the <td> tags representing days currently displayed464 on the calendar to set calendarattributes. Items have the format of 465 `<td class="[class]">[D]</td>` where 466 - [D] is the one- or two-digit day (as a string) and467 - [class] is one of468 "old day" = a day with archives but in a prior month (clicking469 will refresh the calendar)470 "day" = a past day in the current month471 "active day" = the day currently displayed in the ATT472 "disabled day" = a day for which no archive is available in a month473 (past or future) that has other days with archives. 474 For example, if today is July 27, July 28-31 will 475 be disabled days, as will January 1-26 (since the 476 archive goes back only 180 days). December 31 would477 be an "old disabled day".478 past month for which archives are no longer available479 "new disabled day" = a day in a future month480 "old disabled day" = see explanation in "disabled day"481 482 """483 if self.verbose: print('Parsing calendar...')484 485 # Get the tags representing the days currently displayed on the calendar486 days_on_calendar = self.calendar_soup.find_all('td')487 488 # Get the month & year currently displayed489 month, year = self.calendar_soup.find('th', 490 {'class': 'datepicker-switch'}491 ).text.split(' ')492 493 displayed_month = _MONTHS.index(month)494 displayed_year = int(year)495 496 # Parse the various calendar attributes497 active_day = int([day.text for day in days_on_calendar498 if (day['class'][0] == 'active')][0])499 500 month_max_day = int([day.text for day in days_on_calendar501 if (day['class'][0] == 'day') or502 (day['class'][0] == 'active')][::-1][0])503 504 month_min_day = int(self.__parse_month_min_day(days_on_calendar))505 506 # Set class attributes507 self.active_date = date(displayed_year, displayed_month, active_day) 508 self.month_min_date = date(displayed_year, displayed_month, month_min_day)509 self.month_max_date = date(displayed_year, displayed_month, month_max_day)510 511 def __parse_month_min_day(self, days_on_calendar):512 """Parse the lowest valid day in the displayed month"""513 disabled_found = False514 for day in days_on_calendar:515 if day['class'][0] == 'disabled':516 disabled_found = True517 elif day['class'][0] in 'day active'.split():518 return day.text519 elif day['class'][0] != 'old' and disabled_found:520 return day.text521 522 return None523 def __get_current_first_uri(self):524 return self.browser.find_element_by_xpath(525 _FIRST_URI_IN_ATT_XPATH526 ).get_attribute('href').split('/')[-1]527 528 def open_browser(self):529 if self.verbose: print('Opening browser...')530 # Make Chrome invisible, comment if you want to see it in action...531 options = Options()532 options.headless = True533 # Launch Chrome534 self.browser = webdriver.Chrome(_WEBDRIVER_PATH, chrome_options=options)535 def close_browser(self):536 if self.verbose: print('Closing browser...')537 self.browser.quit()538 def __check_browser(self):539 if not self.browser:540 raise NavigatorException("Please open a browser. And remember to close it when you're done.")541 542 def __repr__(self):543 return(f'_ArchiveNavigator(URL: {self.url}, '544 f'Currently Displayed: {str(self.active_date)}, '545 f'Max Day: {str(self.archive_max_date)}, '546 f'Min Day: {str(self.archive_min_date)}, ')547 548 549# In[ ]:550class _DownloadNavigator:551 def __init__(self, login=False, username=None, password=None, verbose=False):552 self.download_page_soup = None...

Full Screen

Full Screen

messenger.py

Source:messenger.py Github

copy

Full Screen

...10 def __init__(self, test: "WebDriverTest"):11 self.test = test12 def activate_messenger(self):13 self.__check_scope()14 self.__check_browser()15 js_utils.activate_messenger(self.driver)16 self.wait_for_ready_state_complete()17 def set_messenger_theme(18 self, theme="default", location="default", max_messages="default"19 ):20 """Sets a theme for posting messages.21 Themes: ["flat", "future", "block", "air", "ice"]22 Locations: ["top_left", "top_center", "top_right",23 "bottom_left", "bottom_center", "bottom_right"]24 max_messages is the limit of concurrent messages to display.25 """26 self.__check_scope()27 self.__check_browser()28 if not theme:29 theme = "default" # "flat"30 if not location:31 location = "default" # "bottom_right"32 if not max_messages:33 max_messages = "default" # "8"34 else:35 max_messages = str(max_messages) # Value must be in string format36 js_utils.set_messenger_theme(37 self.driver,38 theme=theme,39 location=location,40 max_messages=max_messages,41 )42 def post_message(self, message, duration=None, pause=True, style="info"):43 """Post a message on the screen with Messenger.44 Arguments:45 message: The message to display.46 duration: The time until the message vanishes. (Default: 2.55s)47 pause: If True, the program waits until the message completes.48 style: "info", "success", or "error".49 You can also post messages by using =>50 self.execute_script('Messenger().post("My Message")')51 """52 self.__check_scope()53 self.__check_browser()54 if style not in ["info", "success", "error"]:55 style = "info"56 if not duration:57 if not self.message_duration:58 duration = settings.DEFAULT_MESSAGE_DURATION59 else:60 duration = self.message_duration61 if (self.headless or self.xvfb) and float(duration) > 0.75:62 duration = 0.7563 try:64 js_utils.post_message(self.driver, message, duration, style=style)65 except Exception:66 print(" * %s message: %s" % (style.upper(), message))67 if pause:68 duration = float(duration) + 0.1569 time.sleep(float(duration))70 def post_message_and_highlight(71 self, message, selector, by=By.CSS_SELECTOR72 ):73 """Post a message on the screen and highlight an element.74 Arguments:75 message: The message to display.76 selector: The selector of the Element to highlight.77 by: The type of selector to search by. (Default: CSS Selector)78 """79 self.__check_scope__()80 self.__highlight_with_assert_success(message, selector, by=by)81 def post_success_message(self, message, duration=None, pause=True):82 """Post a success message on the screen with Messenger.83 Arguments:84 message: The success message to display.85 duration: The time until the message vanishes. (Default: 2.55s)86 pause: If True, the program waits until the message completes.87 """88 self.__check_scope()89 self.__check_browser()90 if not duration:91 if not self.message_duration:92 duration = settings.DEFAULT_MESSAGE_DURATION93 else:94 duration = self.message_duration95 if (self.headless or self.xvfb) and float(duration) > 0.75:96 duration = 0.7597 try:98 js_utils.post_message(99 self.driver, message, duration, style="success"100 )101 except Exception:102 print(" * SUCCESS message: %s" % message)103 if pause:104 duration = float(duration) + 0.15105 time.sleep(float(duration))106 def post_error_message(self, message, duration=None, pause=True):107 """Post an error message on the screen with Messenger.108 Arguments:109 message: The error message to display.110 duration: The time until the message vanishes. (Default: 2.55s)111 pause: If True, the program waits until the message completes.112 """113 self.__check_scope()114 self.__check_browser()115 if not duration:116 if not self.message_duration:117 duration = settings.DEFAULT_MESSAGE_DURATION118 else:119 duration = self.message_duration120 if (self.headless or self.xvfb) and float(duration) > 0.75:121 duration = 0.75122 try:123 js_utils.post_message(124 self.driver, message, duration, style="error"125 )126 except Exception:127 print(" * ERROR message: %s" % message)128 if pause:...

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