How to use double_click_with_offset method in SeleniumBase

Best Python code snippet using SeleniumBase

webdriver.py

Source:webdriver.py Github

copy

Full Screen

...483 Args:484 locator (str/WebElement): The locator to identify the element or WebElement485 """486 self.find_element(locator).double_click()487 def double_click_with_offset(self, locator, x_offset=1, y_offset=1):488 """Double-click the element from x and y offsets.489 Args:490 locator (str/WebElement): The locator to identify the element or WebElement491 Keyword Arguments:492 x_offset (int): X offset from the left of the element. Defaults to 1.493 y_offset (int): Y offset from the top of the element. Defaults to 1.494 """495 self.find_element(locator).double_click_with_offset(x_offset=x_offset, y_offset=y_offset)496 def drag_and_drop(self, source_locator, target_locator):497 """Hold down the left mouse button on the source element,498 then move to the target element and releases the mouse button.499 Args:500 source_locator (str/WebElement): The element to mouse down501 target_locator (str/WebElement): The element to mouse up502 """503 source_element = self.find_element(source_locator)504 target_element = self.find_element(target_locator)505 self.actions().drag_and_drop(source_element, target_element()).perform()506 def drag_and_drop_by_offset(self, source_locator, x_offset, y_offset):507 """Hold down the left mouse button on the source element,508 then move to the target offset and releases the mouse button.509 Args:510 source_locator (str/WebElement): The element to mouse down511 Keyword Arguments:512 x_offset (int): X offset to move to513 y_offset (int): Y offset to move to514 """515 source_element = self.find_element(source_locator)516 self.actions().drag_and_drop_by_offset(source_element, x_offset, y_offset).perform()517 def draw_rectangle(self, locator, color='#f33', top=4, right=8, bottom=4, left=8):518 """Draw(Append) a bordered DIV around the given element.519 Args:520 locator (str/WebElement): The locator to identify the element or WebElement521 Keyword Arguments:522 color (str): The color of the bordered DIV. Defaults to '#f33'.523 top (int): padding-top of the bordered DIV. Defaults to 4.524 right (int): padding-right of the bordered DIV. Defaults to 8.525 bottom (int): padding-bottom of the bordered DIV. Defaults to 4.526 left (int): padding-left of the bordered DIV. Defaults to 8.527 Returns:528 [type]: [description]529 """530 rect = self.rect(locator)531 x = rect.get('x', 0)532 y = rect.get('y', 0)533 width = rect.get('width', 0)534 height = rect.get('height', 0)535 id = 'spydr_' + self.randomized_string()536 self.execute_script(f'''537 let rectangle = window.document.createElement('div');538 rectangle.id = '{id}';539 rectangle.style.border = '3px solid {color}';540 rectangle.style.display = 'block';541 rectangle.style.height = ({height} + {top} + {bottom}) + 'px';542 rectangle.style.left = ({x} - {left}) + 'px';543 rectangle.style.margin = '0px';544 rectangle.style.padding = '0px';545 rectangle.style.position = 'absolute';546 rectangle.style.top = ({y} - {top}) + 'px';547 rectangle.style.width = ({width} + {left} + {right}) + 'px';548 rectangle.style.zIndex = '99999';549 window.document.body.appendChild(rectangle);550 return;551 ''')552 return self.find_element(f'#{id}')553 def draw_text(self, locator, text, color='#f33', font_size=16, top=5, right=20):554 """Draw(Append) a text DIV element to the given element, by locator.555 Args:556 locator (str/WebElement): The locator to identify the element or WebElement557 text (str): Text558 Keyword Arguments:559 color (str): The color of the text. Defaults to '#f33'.560 font_size (int): The font size of the text. Defaults to 16.561 top (int): CSS style of top. Defaults to 5.562 right (int): CSS style of right. Defaults to 20.563 Returns:564 WebElement: The text DIV element565 """566 rect = self.rect(locator)567 x = rect.get('x', 0)568 y = rect.get('y', 0)569 height = rect.get('height', 0)570 id = 'spydr_' + self.randomized_string()571 self.execute_script(f'''572 let textbox = window.document.createElement('div');573 textbox.id = '{id}';574 textbox.innerText = '{text}';575 textbox.style.border = 'none';576 textbox.style.color = '{color}';577 textbox.style.display = 'block';578 textbox.style.fontFamily = 'Verdana, sans-serif';579 textbox.style.fontSize = {font_size} + 'px';580 textbox.style.fontWeight= 'bold';581 textbox.style.left = {x} + 'px';582 textbox.style.margin = '0';583 textbox.style.padding = '0';584 textbox.style.position = 'absolute';585 textbox.style.right = {right} + 'px';586 textbox.style.top = ({y} + {height} + {top}) + 'px';587 textbox.style.zIndex = '99999';588 window.document.body.appendChild(textbox);589 return;590 ''')591 return self.find_element(f'#{id}')592 @property593 def driver(self):594 """Instance of Selenium WebDriver.595 Returns:596 WebDriver: Instance of Selenium WebDriver597 """598 return self.__driver599 @driver.setter600 def driver(self, driver_):601 self.__driver = driver_602 def execute_async_script(self, script, *args):603 """Asynchronously execute JavaScript in the current window or frame.604 Args:605 script (str): JavaScript to execute606 *args: Any applicable arguments for JavaScript607 Returns:608 Any applicable return from JavaScript609 """610 return self.driver.execute_async_script(script, *args)611 def execute_cdp_cmd(self, cmd, cmd_args={}):612 """Execute Chrome Devtools Protocol command and get returned result.613 `cmd` and `cmd_args` should follow Chrome DevTools Protocol.614 Refer to: https://chromedevtools.github.io/devtools-protocol/615 Args:616 cmd (str): Command name617 cmd_args (dict): Command arguments. Defaults to {}.618 Returns:619 dict: A dict, empty dict {} if there is no result to return.620 """621 return self.driver.execute_cdp_cmd(cmd, cmd_args)622 def execute_script(self, script, *args):623 """Synchronously execute JavaScript in the current window or frame.624 Args:625 script (str): JavaScript to execute626 *args: Any applicable arguments for JavaScript627 Returns:628 Any applicable return from JavaScript629 """630 return self.driver.execute_script(script, *args)631 def explicitly_run(self, seconds, method, *args, **kwargs):632 """Explicitly run the given method for the given seconds.633 Args:634 seconds (int): Seconds to run before timing out635 method (callable): Method to call636 *args: Any applicable arguments637 *kwargs: Any applicable keyword arguments638 Returns:639 Return the result of the given method.640 """641 timeout = self.timeout642 self.timeout = seconds643 try:644 return method(*args, **kwargs)645 finally:646 self.timeout = timeout647 @_WebElementSpydrify()648 def find_element(self, locator):649 """Find the element by the given locator.650 Args:651 locator (str/WebElement): The locator to identify the element or WebElement652 Raises:653 NoSuchElementException: Raise an error when no element found654 Returns:655 WebElement: The element found656 """657 if isinstance(locator, WebElement):658 return locator659 element = None660 how, what = self._parse_locator(locator)661 if how == HOWS['css']:662 matched = re.search(r'(.*):eq\((\d+)\)', what)663 if matched:664 new_what, index = matched.group(1, 2)665 try:666 element = self.find_elements(f'css={new_what}')[int(index)]667 except IndexError:668 raise NoSuchElementException(f'{locator} does not have ":eq({index})" element')669 if not element:670 element = self.is_located(locator)671 if not isinstance(element, WebElement):672 raise NoSuchElementException(f'Cannot locate element in the given time using: {locator}')673 return element674 @_WebElementSpydrify()675 def find_elements(self, locator):676 """Find all elements by the given locator.677 Args:678 locator (str): The locator to identify the elements or list[WebElement]679 Returns:680 list[WebElement]: All elements found681 """682 if isinstance(locator, (list, tuple)) and all(isinstance(el, WebElement) for el in locator):683 return locator684 how, what = self._parse_locator(locator)685 elements = self.driver.find_elements(how, what)686 return elements687 def first_child(self, locator):688 """Get the first child element of the given element.689 Args:690 locator (str/WebElement): The locator to identify the element or WebElement691 Returns:692 WebElement: The first child element of the given element.693 """694 return self.find_element(locator).first_child695 def focus(self, locator):696 """Trigger focus event on the element.697 Args:698 locator (str/WebElement): The locator to identify the element or WebElement699 """700 self.find_element(locator).focus()701 def forward(self):702 """Goes one step forward in the browser history."""703 self.driver.forward()704 def fullscreen_window(self):705 """Invokes the window manager-specific 'full screen' operation."""706 self.driver.fullscreen_window()707 def get_attribute(self, locator, name):708 """Get the given attribute or property of the element.709 Args:710 locator (str/WebElement): The locator to identify the element or WebElement711 name (str): Attribute name712 Returns:713 bool/str/None: The attribute value714 """715 return self.find_element(locator).get_attribute(name)716 def get_cookie(self, name):717 """Get the cookie by name.718 Args:719 name (str): The name of the cookie720 Returns:721 dict/None: Return the cookie or None if not found.722 """723 return self.driver.get_cookie(name)724 def get_cookies(self):725 """Get the cookies visible in the current session.726 Returns:727 list[dict]: Return cookies in a set of dictionaries728 """729 return self.driver.get_cookies()730 def get_ini_key(self, key, section=None):731 """Get value of the given key from INI.732 Args:733 key (str): Key name734 section: INI section. Defaults to the default section.735 Returns:736 Value (any data type JSON supports)737 """738 if self.ini:739 return self.ini.get_key(key, section)740 def get_local_storage_item(self, name):741 """Get item's value from localStorage.742 Args:743 name (str): Item name in localStorage744 Returns:745 Item's value from localStorage. (Deserialized with `json.loads`)746 """747 return self.local_storage.get(name)748 def get_property(self, locator, name):749 """Get the given property of the element.750 Args:751 locator (str/WebElement): The locator to identify the element or WebElement752 name (str): Property name753 Returns:754 bool/dict/int/list/str/None: The property value755 """756 return self.find_element(locator).get_property(name)757 def get_screenshot_as_base64(self):758 """Get a screenshot of the current window as a base64 encoded string.759 Returns:760 str: Base64 encoded string of the screenshot761 """762 self.wait_until_page_loaded()763 return self.driver.get_screenshot_as_base64()764 def get_screenshot_as_file(self, filename):765 """Save a screenshot of the current window to filename (PNG).766 Default directory for saved screenshots is defined in: screen_root.767 Args:768 filename (str): Filename of the screenshot769 Returns:770 bool: Whether the file is saved771 """772 self.wait_until_page_loaded()773 return self.driver.get_screenshot_as_file(self.abspath(filename, suffix='.png', root=self.screen_root))774 def get_screenshot_as_png(self):775 """Get a screenshot of the current window as a binary data.776 Returns:777 bytes: Binary data of the screenshot778 """779 self.wait_until_page_loaded()780 return self.driver.get_screenshot_as_png()781 def get_session_storage_item(self, name):782 """Get item's value from sessionStorage.783 Args:784 name (str): Item name in sessionStorage785 Returns:786 Item's value from sessionStorage. (Deserialized with `json.loads`)787 """788 return self.session_storage.get(name)789 def get_window_position(self, window_handle='current'):790 """Get the x and y position of the given window.791 Keyword Arguments:792 window_handle (str): The handle of the window. Defaults to 'current'.793 Returns:794 dict: The position of the window as dict: {'x': 0, 'y': 0}795 """796 return self.driver.get_window_position(window_handle)797 def get_window_rect(self):798 """Get the x, y, height, and width of the current window.799 Returns:800 dict: The position, height, and width as dict: {'x': 0, 'y': 0, 'width': 100, 'height': 100}801 """802 return self.driver.get_window_rect()803 def get_window_size(self, window_handle='current'):804 """Get the width and height of the given window.805 Keyword Arguments:806 window_handle (str): The handle of the window. Defaults to 'current'.807 Returns:808 dict: The height and width of the window as dict: {'width': 100, 'height': 100}809 """810 return self.driver.get_window_size(window_handle)811 def has_attribute(self, locator, attribute):812 """Check if the element has the given attribute.813 Args:814 locator (str/WebElement): The locator to identify the element or WebElement815 attribute (str): Attribute name816 Returns:817 bool: Whether the attribute exists818 """819 return self.find_element(locator).has_attribute(attribute)820 def has_attribute_value(self, locator, attribute, value):821 """Check if the element's attribute contains the given `value`.822 Args:823 locator (str/WebElement): The locator to identify the element or WebElement824 attribute (str): Attribute name825 value (bool/str): value to check826 Returns:827 bool: Whether value is found in the element's attribute828 """829 return self.find_element(locator).has_attribute_value(attribute, value)830 def has_class(self, locator, class_name):831 """Check if the element has the given CSS class.832 Args:833 locator (str/WebElement): The locator to identify the element or WebElement834 class_name (str): CSS class name835 Returns:836 bool: Whether the CSS class exists837 """838 return self.find_element(locator).has_class(class_name)839 def has_local_storage(self):840 """Check access to localStorage.841 Returns:842 bool: Whether has access to localStorage or not843 """844 return self.local_storage.has_storage()845 def has_session_storage(self):846 """Check access to sessionStorage.847 Returns:848 bool: Whether has access to sessionStorage or not849 """850 return self.session_storage.has_storage()851 def has_text(self, locator, text):852 """Check if the element contains the given `text`.853 Args:854 locator (str/WebElement): The locator to identify the element or WebElement855 text (str): Text to check856 Returns:857 bool: Whether the element has the given text858 """859 return self.find_element(locator).has_text(text)860 def hide(self, locator):861 """Hide the element."""862 self.find_element(locator).hide()863 def highlight(self, locator, hex_color='#ff3'):864 """Highlight the element with the given color.865 Args:866 locator (str/WebElement): The locator to identify the element or WebElement867 hex_color (str, optional): Hex color. Defaults to '#ff3'.868 """869 self.find_element(locator).highlight(hex_color)870 @property871 def implicitly_wait(self):872 """Timeout for implicitly wait.873 Returns:874 int: The timeout of implicitly wait875 """876 return self.__implicitly_wait877 @implicitly_wait.setter878 def implicitly_wait(self, seconds):879 self.__implicitly_wait = seconds880 self.driver.implicitly_wait(seconds)881 def info(self, message):882 """Log **INFO** messages.883 Args:884 message (str): **INFO** Message885 """886 self.logger.info(message)887 @property888 def ini(self):889 """INI file as an INI instance.890 Returns:891 INI: INI instance892 """893 return self.__ini894 @ini.setter895 def ini(self, file):896 if isinstance(file, INI):897 self.__ini = file898 else:899 self.__ini = INI(file) if file else None900 def is_displayed(self, locator, seconds=None):901 """Check if the element is displayed.902 Args:903 locator (str/WebElement): The locator to identify the element or WebElement904 Keyword Arguments:905 seconds (int): Seconds to wait until giving up. Defaults to `self.implicitly_wait`.906 Returns:907 bool: Whether the element is displayed908 """909 implicitly_wait = self.implicitly_wait910 seconds = int(seconds) if seconds is not None else implicitly_wait911 self.implicitly_wait = seconds912 try:913 return self.find_element(locator).is_displayed()914 except (NoSuchElementException, TimeoutException):915 return False916 finally:917 self.implicitly_wait = implicitly_wait918 def is_enabled(self, locator):919 """Check if the element is enabled.920 Args:921 locator (str/WebElement): The locator to identify the element or WebElement922 Returns:923 bool: Whether the element is enabled924 """925 return self.find_element(locator).is_enabled()926 def is_file(self, file_path):927 """Whether the file exists.928 Args:929 file_path (str): File Path930 Returns:931 bool: Whether the file exists932 """933 return Utils.is_file(file_path)934 @_WebElementSpydrify()935 def is_located(self, locator, seconds=None):936 """Check if the element is located in the given seconds.937 Args:938 locator (str): The locator to identify the element939 Keyword Arguments:940 seconds (int): Seconds to wait until giving up. Defaults to `self.implicitly_wait`.941 Returns:942 False/WebElement: Return False if not located. Return WebElement if located.943 """944 how, what = self._parse_locator(locator)945 implicitly_wait = self.implicitly_wait946 seconds = seconds if seconds is not None else implicitly_wait947 if seconds != implicitly_wait:948 self.implicitly_wait = seconds949 try:950 return self.wait(self.driver, seconds).until(lambda wd: wd.find_element(how, what))951 except (NoSuchElementException, NoSuchWindowException, StaleElementReferenceException, TimeoutException):952 return False953 finally:954 if seconds != implicitly_wait:955 self.implicitly_wait = implicitly_wait956 def is_page_loaded(self):957 """Check if `document.readyState` is `complete`.958 Returns:959 bool: Whether the page is loaded960 """961 return self.execute_script('return document.readyState == "complete";')962 def is_selected(self, locator):963 """Check if the element is selected.964 Can be used to check if a checkbox or radio button is selected.965 Args:966 locator (str/WebElement): The locator to identify the element or WebElement967 Returns:968 bool: Whether the element is selected969 """970 return self.find_element(locator).is_selected()971 def is_text_matched(self, locator, text):972 """Whether the given text matches the element's text.973 Args:974 locator (str/WebElement): The locator to identify the element or WebElement975 text (str): Text to match976 Returns:977 bool: Whether the given text matches the element's text978 """979 return self.find_element(locator).is_text_matched(text)980 def js_click(self, locator):981 """Call `HTMLElement.click()` using JavaScript.982 Args:983 locator (str/WebElement): The locator to identify the element or WebElement984 """985 self.find_element(locator).js_click()986 def js_send_keys(self, locator, text):987 """Send text to the element using JavaScript.988 Args:989 locator (str/WebElement): The locator to identify the element or WebElement990 text (str): Text to send991 """992 self.find_element(locator).js_send_keys(text)993 def last_child(self, locator):994 """Get the last child element of the given element.995 Args:996 locator (str/WebElement): The locator to identify the element or WebElement997 Returns:998 WebElement: The last child element of the element element.999 """1000 return self.find_element(locator).last_child1001 def load_cookies(self, filename):1002 """Load Cookies from a JSON file.1003 Args:1004 filename (str): File name1005 Examples:1006 | # cookies.json file1007 | [1008 | { "name": "name1", "value": "true" },1009 | { "name": "name2", "value": "false" },1010 | ]1011 """1012 file_ = self.abspath(filename, suffix='.json', mkdir=False)1013 with open(file_, "r") as cookie_file:1014 cookies = json.load(cookie_file)1015 for cookie in cookies:1016 self.add_cookie(cookie)1017 def load_local_storage(self, filename):1018 """Load JSON file to localStorage.1019 Args:1020 filename (str): File name1021 Examples:1022 | # local_storage.json file1023 | {1024 | "name1": "true",1025 | "name2": "false"1026 | }1027 """1028 file_ = self.abspath(filename, suffix='.json', mkdir=False)1029 with open(file_, "r") as storage_file:1030 storage = json.load(storage_file)1031 for name, value in storage.items():1032 self.set_local_storage_item(name, value)1033 def load_session_storage(self, filename):1034 """Load JSON file to sessionStorage.1035 Args:1036 filename (str): File name1037 Examples:1038 | # session_storage.json file1039 | {1040 | "name1": "true",1041 | "name2": "false"1042 | }1043 """1044 file_ = self.abspath(filename, suffix='.json', mkdir=False)1045 with open(file_, "r") as storage_file:1046 storage = json.load(storage_file)1047 for name, value in storage.items():1048 self.set_session_storage_item(name, value)1049 def location(self, locator):1050 """The location of the element in the renderable canvas.1051 Args:1052 locator (str/WebElement): The locator to identify the element or WebElement1053 Returns:1054 dict: The location of the element as dict: {'x': 0, 'y': 0}1055 """1056 return self.find_element(locator).location1057 def maximize_window(self):1058 """Maximize the current window."""1059 if not self.headless:1060 self.driver.maximize_window()1061 def maximize_to_screen(self):1062 """Maximize the current window to match the screen size."""1063 size = self.execute_script('return { width: window.screen.width, height: window.screen.height };')1064 self.set_window_position(0, 0)1065 self.set_window_size(size['width'], size['height'])1066 def minimize_window(self):1067 """Minimize the current window."""1068 if not self.headless:1069 self.driver.minimize_window()1070 def move_by_offset(self, x_offset, y_offset):1071 """Moving the mouse to an offset from current mouse position.1072 Keyword Arguments:1073 x_offset (int): X offset1074 y_offset (int): Y offset1075 """1076 self.actions().move_by_offset(x_offset, y_offset).perform()1077 def move_to_element(self, locator):1078 """Moving the mouse to the middle of the element.1079 Args:1080 locator (str/WebElement): The locator to identify the element or WebElement1081 """1082 element = self.find_element(locator)1083 self.actions().move_to_element(element).perform()1084 def move_to_element_with_offset(self, locator, x_offset=1, y_offset=1):1085 """Move the mouse by an offset of the specified element.1086 Offsets are relative to the top-left corner of the element.1087 Args:1088 locator (str/WebElement): The locator to identify the element or WebElement1089 Keyword Arguments:1090 x_offset (int): X offset. Defaults to 1.1091 y_offset (int): Y offset. Defaults to 1.1092 """1093 element = self.find_element(locator)1094 self.actions().move_to_element_with_offset(element, x_offset, y_offset).perform()1095 def next_element(self, locator):1096 """Get the next element of the given element.1097 Args:1098 locator (str/WebElement): The locator to identify the element or WebElement1099 Returns:1100 WebElement: The next element of the given element.1101 """1102 return self.find_element(locator).next_element1103 def new_tab(self):1104 """Open a new tab.1105 Returns:1106 str: Window handle of the new tab1107 """1108 self.execute_script('window.open();')1109 return self.window_handles[-1]1110 def new_window(self, name):1111 """Open a new window.1112 Args:1113 name (str): Name of the window1114 Returns:1115 str: Window handle of the new window1116 """1117 self.execute_script('''1118 var w = Math.max(1119 document.documentElement.clientWidth, window.innerWidth || 01120 );1121 var h = Math.max(1122 document.documentElement.clientHeight, window.innerHeight || 01123 );1124 window.open("about:blank", arguments[0], `width=${w},height=${h}`);1125 ''', name)1126 return self.window_handles[-1]1127 def open(self, url, new_tab=False):1128 """Load the web page by its given URL.1129 Args:1130 url (str): URL of the web page1131 Keyword Arguments:1132 new_tab (bool): Whether to open in a new tab. Defaults to False.1133 Returns:1134 list[str]: List of [current_window_handle, new_tab_window_handle]1135 """1136 current_handle = self.window_handle1137 if new_tab:1138 new_handle = self.new_tab()1139 self.switch_to_window(new_handle)1140 self.driver.get(url)1141 return [current_handle, new_handle] if new_tab else [current_handle, None]1142 def open_data_as_url(self, data, mediatype='text/html', encoding='utf-8'):1143 """Use Data URL to open `data` as inline document.1144 Args:1145 data (str): Data to be open as inline document1146 Keyword Arguments:1147 mediatype (str): MIME type. Defaults to 'text/html'.1148 encoding (str): Data encoding. Defaults to 'utf-8'.1149 """1150 base64_encoded = base64.b64encode(bytes(data, encoding))1151 base64_data = str(base64_encoded, encoding)1152 self.open(f'data:{mediatype};base64,{base64_data}')1153 def open_file(self, filename):1154 """Open file with the browser.1155 Args:1156 filename (str): File name1157 Raises:1158 WebDriverException: Raise an error when filename is not found1159 """1160 file_ = self.abspath(filename, mkdir=False)1161 if os.path.isfile(file_):1162 html_path = file_.replace('\\', '/')1163 self.open(f'file:///{html_path}')1164 else:1165 raise WebDriverException(f'Cannot find file: ${file_}')1166 def open_file_as_url(self, filename, mediatype='text/html', encoding='utf-8'):1167 """Use Data URL to open file content as inline document.1168 Args:1169 filename (str): File name1170 Keyword Arguments:1171 mediatype (str): MIME type. Defaults to 'text/html'.1172 encoding (str): File encoding. Defaults to 'utf-8'.1173 Raises:1174 WebDriverException: Raise an error when filename is not found1175 """1176 file_ = self.abspath(filename, mkdir=False)1177 if os.path.isfile(file_):1178 data = open(file_, 'r', encoding=encoding).read()1179 self.open_data_as_url(data, mediatype=mediatype, encoding=encoding)1180 else:1181 raise WebDriverException(f'Cannot find file: ${file_}')1182 def open_with_auth(self, url, username=None, password=None):1183 """Load the web page by adding username and password to the URL1184 Args:1185 url (str): URL of the web page1186 Keyword Arguments:1187 username (str): Username. Defaults to auth_username or None.1188 password (str): Password. Defaults to auth_password or None.1189 """1190 username = username or self.auth_username1191 password = password or self.auth_password1192 if username and password and self.browser != 'chrome':1193 encoded_username = urllib.parse.quote(username)1194 encoded_password = urllib.parse.quote(password)1195 split_result = urllib.parse.urlsplit(url)1196 split_result_with_auth = split_result._replace(1197 netloc=f'{encoded_username}:{encoded_password}@{split_result.netloc}')1198 url_with_auth = urllib.parse.urlunsplit(split_result_with_auth)1199 self.open(url_with_auth)1200 else:1201 self.open(url)1202 @property1203 def page_load_timeout(self):1204 """Timeout for page load1205 Returns:1206 int: Page load timeout1207 """1208 return self.__page_load_timeout1209 @page_load_timeout.setter1210 def page_load_timeout(self, seconds):1211 self.__page_load_timeout = seconds1212 self.driver.set_page_load_timeout(seconds)1213 @property1214 def page_source(self):1215 """Get the source of the current page.1216 Returns:1217 str: The source of the current page1218 """1219 return self.driver.page_source1220 def paste_from_clipboard(self, locator):1221 """Paste clipboard (send_keys) to the given element. (Chrome only)1222 Args:1223 locator (str/WebElement): The locator to identify the element or WebElement1224 """1225 self.find_element(locator).paste_from_clipboard()1226 def parent_element(self, locator):1227 """Get the parent element of the given element.1228 Args:1229 locator (str/WebElement): The locator to identify the element or WebElement1230 Returns:1231 WebElement: The parent element of the given element.1232 """1233 return self.find_element(locator).parent_element1234 def path_exists(self, path):1235 """Check if path exists.1236 Args:1237 path (str): Path1238 Returns:1239 bool: Whether path exists.1240 """1241 return Utils.path_exists(path)1242 def previous_element(self, locator):1243 """Get the previous element of the given element.1244 Args:1245 locator (str/WebElement): The locator to identify the element or WebElement1246 Returns:1247 WebElement: The previous element of the given element.1248 """1249 return self.find_element(locator).previous_element1250 def quit(self):1251 """Quit the Spydr webdriver."""1252 self.driver.quit()1253 def radio_to_be(self, locator, is_checked):1254 """Set the radio button, identified by the locator, to the given state (is_checked).1255 Args:1256 locator (str/WebElement): The locator to identify the radio button or WebElement1257 is_checked (bool): whether the radio button is to be checked1258 Raises:1259 InvalidSelectorException: Raise an error when the element is not a radio button1260 WebDriverException: Raise an error when failing to set the given state1261 """1262 radio = self.find_element(locator)1263 if radio.tag_name != 'input' and radio.get_attribute('type') != 'radio':1264 raise InvalidSelectorException(f'Element is not a radio button: {locator}')1265 if is_checked:1266 if not radio.is_selected() and radio.is_enabled():1267 if not self._is_checkbox_or_radio_clicked(radio):1268 raise WebDriverException(f'Failed to click on the element: {locator}')1269 else:1270 if radio.is_selected() and radio.is_enabled():1271 self.execute_script('arguments[0].checked = false;', radio)1272 def randomized_string(self, size=10, sequence=string.ascii_letters, digits=True, punctuation=False, whitespace=False, is_upper=False):1273 """Generate a randomized string in the given size using the given characters.1274 Args:1275 size (int, optional): Size of the string. Defaults to 10.1276 Keyword Arguments:1277 sequence (str): Sequence. Defaults to string.ascii_letters.1278 digits (bool): Add `string.digits` to sequence.1279 punctuation (bool): Add `string.punctuation` to sequence.1280 whitespace (bool): Add whitespace to sequence.1281 is_upper (bool): Uppercase the randomized string. Defaults to False.1282 Returns:1283 [type]: [description]1284 """1285 if not isinstance(sequence, str):1286 sequence = string.ascii_letters1287 if digits:1288 sequence += string.digits1289 if punctuation:1290 sequence += string.punctuation1291 if whitespace:1292 sequence += ' '1293 string_ = ''.join(Utils.random_choice(sequence) for _ in range(size))1294 return string_.upper() if is_upper else string_1295 def rect(self, locator):1296 """Get the size and location of the element.1297 Args:1298 locator (str/WebElement): The locator to identify the element or WebElement1299 Returns:1300 dict: The size and location of the element as dict: {'x': 0, 'y': 0, 'width': 100, 'height': 100}1301 """1302 return self.find_element(locator).rect1303 def refresh(self):1304 """Refresh the current page."""1305 self.driver.refresh()1306 def refresh_until_page_changed(self, frequency=2, timeout=10, body_text_diff=True):1307 """Refresh the page (every `frequency`) until the page changes or until `timeout`.1308 Keyword Arguments:1309 frequency (int): Refresh frequency1310 timeout (int): Time allowed to refresh. Defaults to 10.1311 body_text_diff (bool): Compare `body` text when True. Compare `page_source` when False.1312 Returns:1313 bool: Whether the page is changed1314 """1315 return self.wait(self.driver, timeout, poll_frequency=frequency).until(lambda _: self._is_page_changed_after_refresh(body_text_diff))1316 def remove_attribute(self, locator, attribute):1317 """Remove the given attribute from the element.1318 Args:1319 locator (str/WebElement): The locator to identify the element or WebElement1320 attribute (str): Attribute name1321 """1322 self.find_element(locator).remove_attribute(attribute)1323 def remove_class(self, locator, class_name):1324 """Remove the given CSS class to the element.1325 Args:1326 locator (str/WebElement): The locator to identify the element or WebElement1327 class_name (str): CSS class name1328 """1329 self.find_element(locator).remove_class(class_name)1330 def remove_dir(self, dir):1331 """Remove the directory.1332 Args:1333 dir (str): Directory path1334 """1335 Utils.remove_dir(dir)1336 def remove_file(self, file):1337 """Remove the file.1338 Args:1339 file (str): File path1340 """1341 Utils.remove_file(file)1342 def right_click(self, locator):1343 """Right-click on the element.1344 Args:1345 locator (str/WebElement): The locator to identify the element or WebElement1346 """1347 self.find_element(locator).right_click()1348 def right_click_with_offset(self, locator, x_offset=1, y_offset=1):1349 """Right-click on the element with x and y offsets.1350 Args:1351 locator (str/WebElement): The locator to identify the element or WebElement1352 Keyword Arguments:1353 x_offset (int): X offset from the left of the element. Defaults to 1.1354 y_offset (int): Y offset from the top of the element. Defaults to 1.1355 """1356 self.find_element(locator).right_click_with_offset(x_offset=x_offset, y_offset=y_offset)1357 def save_cookies(self, filename):1358 """Save cookies as a JSON file.1359 Args:1360 filename (str): File name1361 """1362 file_ = self.abspath(filename, suffix='.json')1363 with open(file_, "w") as cookie_file:1364 json.dump(self.get_cookies(), cookie_file, indent=2)1365 def save_ini(self):1366 """Save INI file."""1367 if self.ini:1368 self.ini.save()1369 def save_screenshot(self, filename):1370 """Save a screenshot of the current window to filename (PNG).1371 Default directory for saved screenshots is defined in: screen_root.1372 Args:1373 filename (str): Filename of the screenshot1374 Returns:1375 bool: Whether the file is saved1376 """1377 self.wait_until_page_loaded()1378 return self.driver.save_screenshot(self.abspath(filename, suffix='.png', root=self.screen_root))1379 def screenshot(self, locator, filename):1380 """Save a screenshot of the element to the filename (PNG).1381 Args:1382 locator (str/WebElement): The locator to identify the element or WebElement1383 filename ([type]): Filename of the screenshot1384 Returns:1385 bool: Whether the file is saved1386 """1387 return self.find_element(locator).save_screenshot(filename)1388 def screenshot_as_base64(self, locator):1389 """Get the screenshot of the element as a Base64 encoded string1390 Args:1391 locator (str/WebElement): The locator to identify the element or WebElement1392 Returns:1393 str: Base64 encoded string of the screenshot1394 """1395 return self.find_element(locator).screenshot_as_base641396 def screenshot_as_png(self, locator):1397 """Get the screenshot of the element as a binary data.1398 Args:1399 locator (str/WebElement): The locator to identify the element or WebElement1400 Returns:1401 bytes: Binary data of the screenshot1402 """1403 return self.find_element(locator).screenshot_as_png1404 @property1405 def script_timeout(self):1406 """Timeout for script.1407 Returns:1408 int: Script timeout1409 """1410 return self.__script_timeout1411 @script_timeout.setter1412 def script_timeout(self, seconds):1413 self.__script_timeout = seconds1414 self.driver.set_script_timeout(seconds)1415 def scroll_into_view(self, locator, behavior="auto", block="start", inline="nearest"):1416 """Scroll the element's parent to be displayed.1417 Args:1418 locator (str/WebElement): The locator to identify the element or WebElement1419 Keyword Arguments:1420 behavior (str): Defines the transition animation. One of `auto` or `smooth`. Defaults to 'auto'.1421 block (str): Defines vertical alignment. One of `start`, `center`, `end`, or `nearest`. Defaults to 'start'.1422 inline (str): Defines horizontal alignment. One of `start`, `center`, `end`, or `nearest`. Defaults to 'nearest'.1423 """1424 self.find_element(locator).scroll_into_view(behavior=behavior, block=block, inline=inline)1425 def scroll_to(self, locator, x, y):1426 """Scroll the element to the given x- and y-coordinates. (IE not supported)1427 Args:1428 locator (str/WebElement): The locator to identify the element or WebElement1429 x (int): x-coordinate1430 y (int): y-coordinate1431 """1432 self.find_element(locator).scroll_to(x, y)1433 def select_options(self, select_locator, filter_by='value', filter_value=None):1434 """Get options of an select element. Filter the options by attribute if `filter_value` is given.1435 Args:1436 select_locator (str/WebElement): The locator to identify the element or WebElement1437 Keyword Arguments:1438 filter_by (str): Filter options by attribute. Defaults to 'value'.1439 filter_value (str): Filter option's attribute by value. Defaults to None.1440 Returns:1441 list[WebElement]: All filtered options1442 """1443 return self.find_element(select_locator).select_options(filter_by='value', filter_value=None)1444 def select_to_be(self, select_locator, option_value, selected=True, option_by='value'):1445 """Set `selected` state of the given `option` in the `select` drop-down menu.1446 Args:1447 select_locator (str/WebElement): The locator to identify the element or WebElement1448 option_value (int/str): The value to identify the option by using `option_by` method.1449 Keyword Arguments:1450 selected (bool): Option `selected` state to be1451 option_by (str): The method to identify the options. One of `value`, `text`, `index`, or 'attribute_name'. Defaults to 'value'.1452 Raises:1453 InvalidSelectorException: Raise an error when the element is not a select1454 Examples:1455 | # Deselect option: <option value="3">Three</option>1456 | select_to_be('#group', 3, selected=False)1457 | # Select option: <option value="5">Volvo</option>1458 | select_to_be('#car', 'Volvo', option_by='text')1459 | # Select option: <option id="18">Peyton Manning</option>1460 | select_to_be('#qb', 18, option_by='id')1461 """1462 select = self.wait_until(lambda _: self._is_selectable(select_locator))1463 self._option_to_be(select, option_value, selected, option_by)1464 def select_to_be_all(self, select_locator):1465 """Select all `option` in a **multiple** `select` drop-down menu.1466 Args:1467 select_locator (str/WebElement): The locator to identify the element or WebElement1468 """1469 select = self.find_element(select_locator)1470 self._multiple_select_to_be(select, True)1471 def select_to_be_none(self, select_locator):1472 """De-select all `option` in a **multiple** `select` drop-down menu.1473 Args:1474 select_locator (str/WebElement): The locator to identify the element or WebElement1475 """1476 select = self.find_element(select_locator)1477 self._multiple_select_to_be(select, False)1478 def select_to_be_random(self, select_locator, ignored_options=[None, "", "0"]):1479 """Randomly select an `option` in the `select` menu1480 Args:1481 select_locator (str/WebElement): The locator to identify the element or WebElement1482 Keyword Arguments:1483 ignored_options (list): Options to exclude from selection. Defaults to [None, "", "0"].1484 Raises:1485 WebDriverException: Raise an error if failing to randomly select an option1486 """1487 select = self.wait_until(lambda _: self._is_selectable(select_locator))1488 options = select.find_elements('css=option')1489 random_option = self._random_option(options, ignored_options=ignored_options)1490 if random_option:1491 random_option.click()1492 else:1493 raise WebDriverException(f'Cannot randomly select an option in: {select_locator}')1494 def select_to_be_some(self, select_locator, option_values, selected=True, option_by='value'):1495 """Set `selected` state on the given options, by `option_values`, in a `multiple` select element.1496 Args:1497 select_locator (str/WebElement): The locator to identify the element or WebElement1498 option_values (list): The list of values to identify the options by using `option_by` method.1499 Keyword Arguments:1500 selected (bool): Option `selected` state to be1501 option_by (str): The method to identify the options. One of `value`, `text`, `index`, or 'attribute_name'. Defaults to 'value'.1502 Raises:1503 InvalidSelectorException: Raise an error when the element is not a select1504 WebDriverException: Raise an error if select_locator is not `multiple`1505 WebDriverException: Raise an error if option_values is not a `list`1506 """1507 select = self.wait_until(lambda _: self._is_selectable(select_locator))1508 if not select.get_attribute('multiple'):1509 raise WebDriverException(f'select is not multiple: {select_locator}')1510 if not isinstance(option_values, list):1511 raise WebDriverException(f'option_values is not a list: {option_values}')1512 for option_value in option_values:1513 self._option_to_be(select, option_value, selected, option_by, multiple=True)1514 def selected_options(self, select_locator, by='value'):1515 """Get values of **selected** `option` in a `select` drop-down menu.1516 Args:1517 select_locator (str/WebElement): The locator to identify the element or WebElement1518 Keyword Arguments:1519 by (str): Get selected options by `value`, `text`, or `index`. Defaults to 'value'.1520 Raises:1521 InvalidSelectorException: Raise an error when element is not a select element1522 WebDriverException: Raise an error when the given `by` is unsupported1523 Returns:1524 list[int/str]: list of values of all selected options1525 """1526 select = self.find_element(select_locator)1527 options = []1528 if select.tag_name != 'select':1529 raise InvalidSelectorException(f'Element is not a select: {select_locator}')1530 if self.browser == 'ie':1531 multiple = select.get_attribute('multiple')1532 for option in select.find_elements('tag_name=option'):1533 if option.is_selected():1534 options.append(option)1535 if not multiple:1536 break1537 else:1538 options.extend(select.selected_options())1539 if by == 'value':1540 return [opt.value for opt in options]1541 if by == 'text':1542 return [opt.text for opt in options]1543 if by == 'index':1544 return [opt.get_property('index') for opt in options]1545 raise WebDriverException(f'Unsupported selected options by: {by}')1546 def send_keys(self, locator, *keys, blur=False, wait_until_enabled=False):1547 """Simulate typing into the element.1548 Args:1549 locator (str/WebElement): The locator to identify the element or WebElement1550 *keys: Any combinations of strings1551 Keyword Arguments:1552 blur (bool): Lose focus after sending keys. Defaults to False.1553 wait_until_enabled (bool): Whether to wait until the element `is_enabled()` before sending keys. Defaults to False.1554 """1555 self.find_element(locator).send_keys(*keys, blur=blur, wait_until_enabled=wait_until_enabled)1556 def set_attribute(self, locator, attribute, value):1557 """Set the given value to the attribute of the element.1558 Args:1559 locator (str/WebElement): The locator to identify the element or WebElement1560 attribute (str): Attribute name1561 value (str): Attribute name1562 """1563 self.find_element(locator).set_attribute(attribute, value)1564 def set_download_dir(self, download_dir):1565 """Set Download directory (Chrome only)1566 Args:1567 download_dir (str): Download directory1568 """1569 self.execute_cdp_cmd('Browser.setDownloadBehavior',1570 {'behavior': 'allow', 'downloadPath': self.abspath(download_dir, isdir=True)})1571 def set_ini_key(self, key, value, section=None):1572 """Set the value of the given key in INI.1573 Args:1574 key (str): Key name1575 value: Value (any data type JSON supports)1576 section: INI section. Defaults to the default section.1577 """1578 if self.ini:1579 self.ini.set_key(key, value, section)1580 def set_local_storage_item(self, name, value):1581 """Set Item and its value to localStorage.1582 Args:1583 name (str): Item name in localStorage1584 value (str): Item's value. Non-string value is auto serialized with `json.dumps`.1585 """1586 self.local_storage.set(name, value)1587 def set_session_storage_item(self, name, value):1588 """Set Item and its value to sessionStorage.1589 Args:1590 name (str): Item name in sessionStorage1591 value (str): Item's value. Non-string value is auto-serialized with `json.dumps`.1592 """1593 self.session_storage.set(name, value)1594 def set_window_position(self, x, y, window_handle='current'):1595 """Set the x and y position of the current window1596 Args:1597 x (int): x-coordinate in pixels1598 y (int): y-coordinate in pixels1599 Keyword Arguments:1600 window_handle (str): Window handle. Defaults to 'current'.1601 Returns:1602 dict: Window rect as dict: {'x': 0, 'y': 0, 'width': 100, 'height': 100}1603 """1604 return self.driver.set_window_position(x, y, window_handle)1605 def set_window_rect(self, x=None, y=None, width=None, height=None):1606 """Set the x, y, width, and height of the current window.1607 Keyword Arguments:1608 x (int): x-coordinate in pixels. Defaults to None.1609 y (int): y-coordinate in pixels. Defaults to None.1610 width (int): Window width in pixels. Defaults to None.1611 height (int): Window height in pixels. Defaults to None.1612 Returns:1613 dict: Window rect as dict: {'x': 0, 'y': 0, 'width': 100, 'height': 100}1614 """1615 return self.driver.set_window_rect(x, y, width, height)1616 def set_window_size(self, width, height, window_handle='current'):1617 """Set the width and height of the current window.1618 Args:1619 width (int, optional): Window width in pixels. Defaults to None.1620 height (int, optional): Window height in pixels. Defaults to None.1621 Keyword Arguments:1622 window_handle (str): Window handle. Defaults to 'current'.1623 Returns:1624 dict: Window rect as dict: {'x': 0, 'y': 0, 'width': 100, 'height': 100}1625 """1626 return self.driver.set_window_size(width, height, window_handle)1627 def shift_click_from_and_to(self, from_locator, to_locator):1628 """Shift click from `from_locator` to `to_locator`.1629 Args:1630 from_locator (str/WebElement): The locator to identify the element or WebElement1631 to_locator (str/WebElement): The locator to identify the element or WebElement1632 """1633 from_element = self.find_element(from_locator)1634 to_element = self.find_element(to_locator)1635 shift = self.keys.SHIFT1636 self.actions().key_down(shift).click(from_element).click(to_element).key_up(shift).perform()1637 def show(self, locator):1638 """Show the element.1639 Args:1640 locator (str/WebElement): The locator to identify the element or WebElement1641 """1642 self.find_element(locator).show()1643 def size(self, locator):1644 """The size of the element.1645 Args:1646 locator (str/WebElement): The locator to identify the element or WebElement1647 Returns:1648 dict: The size of the element as dict: {'width': 100, 'height': 100}1649 """1650 return self.find_element(locator).size1651 def sleep(self, seconds):1652 """Sleep the given seconds.1653 Args:1654 seconds (int): Seconds to sleep1655 """1656 try:1657 self.wait(self.driver, seconds).until(lambda _: False)1658 except:1659 pass1660 def strptime(self, date_string, format=r'%m/%d/%Y %H:%M:%S', timezone=None):1661 """Parse date string to a `datetime` object.1662 Args:1663 date_string (str): Date string. 1664 Keyword Arguments:1665 format (str, optional): Date format. Defaults to r'%m/%d/%Y %H:%M:%S'.1666 timezone (str): Timezone name, such as 'Asia/Taipei'. Name is handled by `dateutil.tz.gettz()`. Defaults to None.1667 Returns:1668 datetime: `datetime`1669 """1670 now = datetime.strptime(date_string, format)1671 return now if timezone is None else now.replace(tzinfo=tz.gettz(timezone))1672 def submit(self, locator):1673 """Submit a form.1674 Args:1675 locator (str/WebElement): The locator to identify the element or WebElement1676 """1677 self.find_element(locator).submit()1678 def switch_to_active_element(self):1679 """Switch to active element.1680 Returns:1681 WebElement: Active Element1682 """1683 return self.driver.switch_to.active_element1684 def switch_to_alert(self):1685 """Switch to alert.1686 Returns:1687 Alert: Alert1688 """1689 return self.driver.switch_to.alert1690 def switch_to_default_content(self):1691 """Switch to default content."""1692 self.driver.switch_to.default_content()1693 def switch_to_frame(self, frame_locator):1694 """Switch to frame.1695 Args:1696 frame_locator (str/WebElement): The locator to identify the frame or WebElement1697 """1698 self.driver.switch_to.frame(self.find_element(frame_locator))1699 def switch_to_frame_and_wait_until_element_located_in_frame(self, frame_locator, element_locator):1700 """Switch to the given frame and wait until the element is located within the frame.1701 Args:1702 frame_locator (str/WebElement): The locator to identify the frame or WebElement1703 element_locator (str): The locator to identify the element1704 Returns:1705 False/WebElement: Return False if not located. Return WebElement if located.1706 """1707 self.wait_until_frame_available_and_switch(frame_locator)1708 return self.wait_until(lambda _: self.is_located(element_locator))1709 def switch_to_last_window_handle(self):1710 """Switch to the last opened tab or window."""1711 self.switch_to_window(self.window_handles[-1])1712 def switch_to_parent_frame(self):1713 """Switch to parent frame."""1714 self.driver.switch_to.parent_frame()1715 def switch_to_window(self, window_name):1716 """Switch to window.1717 Args:1718 window_name (str): Window name1719 """1720 self.driver.switch_to.window(window_name)1721 def t(self, key, **kwargs):1722 """Get value from YML instance by using "dot notation" key.1723 Args:1724 key (str): Dot notation key1725 Keyword Arguments:1726 **kwargs: Format key value (str) with `str.format(**kwargs)`.1727 Returns:1728 value of dot notation key1729 Examples:1730 | # YAML1731 | today:1732 | dashboard:1733 | search: '#search'1734 | name: 'Name is {name}'1735 |1736 | t('today.dashboard.search') # '#search'1737 | t('today.dashboard.name', name='Spydr') # 'Name is Spydr'1738 """1739 return self.yml.t(key, **kwargs)1740 def tag_name(self, locator):1741 """Get the element's tagName.1742 Args:1743 locator (str/WebElement): The locator to identify the element or WebElement1744 Returns:1745 str: tagName1746 """1747 return self.find_element(locator).tag_name1748 def text(self, locator, typecast=str):1749 """The the element's text. (Only works when the element is in the viewport)1750 Args:1751 locator (str/WebElement): The locator to identify the element or WebElement1752 Keyword Arguments:1753 typecast: Typecast the text. Defaults to `str`.1754 Returns:1755 The text, by `typecast`, of the element1756 """1757 return typecast(self.find_element(locator).text)1758 def text_content(self, locator, strip=True):1759 """Get the element's text. (Works whether the element is in the viewport or not)1760 Args:1761 locator (str/WebElement): The locator to identify the element or WebElement1762 Keyword Arguments:1763 strip (bool): Whether to strip textContent. Defaults to True.1764 Returns:1765 str: The text of the element1766 """1767 return self.find_element(locator).text_content.strip(None if strip else '')1768 def texts(self, locator, typecast=str):1769 """Texts of all elements located by the locator.1770 Args:1771 locator (str/list[WebElement]): The locator to identify the elements or list[WebElement]1772 Keyword Arguments:1773 typecast: Typecast the texts. Defaults to `str`.1774 Returns:1775 list: list of texts, by `typecast`, of the given elements1776 """1777 return [typecast(element.text) for element in self.find_elements(locator)]1778 def text_to_file(self, text, filename, suffix):1779 """Write text to the given filename1780 Args:1781 text (str): Text to write1782 filename (str): filename of the text file1783 suffix (str): suffix of the text file1784 Returns:1785 str: Absolute path of the file1786 """1787 file_ = self.abspath(filename, suffix=suffix)1788 with open(file_, 'w') as text_file:1789 text_file.write(text)1790 return file_1791 def timedelta(self, days, format=r'%m/%d/%Y', timezone=None):1792 """Get the date by the given delta from today.1793 Args:1794 days (int): Delta days from today1795 format (str, optional): Date format. Defaults to '%m/%d/%Y'.1796 Keyword Arguments:1797 timezone (str): Timezone name, such as 'Asia/Taipei'. Name is handled by `dateutil.tz.gettz()`. Defaults to None.1798 Returns:1799 str: Delta date from today1800 Examples:1801 | today() # 2020/12/101802 | timedelta(1) # 2020/12/111803 | timedelta(-1) # 2020/12/091804 """1805 delta = datetime.now(tz.gettz(timezone)) + timedelta(days=days)1806 return delta.strftime(format)1807 @property1808 def timeout(self):1809 """Spydr webdriver timeout for implicitly_wait, page_load_timeout, and script_timeout1810 Returns:1811 int: Spydr webdriver timeout1812 """1813 return self.__timeout1814 @timeout.setter1815 def timeout(self, seconds):1816 self.__timeout = seconds1817 self.implicitly_wait = seconds1818 self.page_load_timeout = seconds1819 self.script_timeout = seconds1820 @staticmethod1821 def timestamp(prefix='', suffix=''):1822 """Get current local timestamp with optional prefix and/or suffix.1823 Keyword Arguments:1824 prefix (str): Prefix for timestamp. Defaults to ''.1825 suffix (str): Suffix for timestamp. Defaults to ''.1826 Returns:1827 str: Timestamp with optional prefix and suffix1828 """1829 timestamp = strftime(r'%Y%m%d%H%M%S', localtime())1830 return f'{prefix}{timestamp}{suffix}'1831 @property1832 def title(self):1833 """Get the title of the current page.1834 Returns:1835 str: Title of the current page1836 """1837 return self.driver.title1838 def today(self, format=r'%m/%d/%Y', timezone=None):1839 """Get Today's date.1840 Args:1841 format (str, optional): Date format. Defaults to '%m/%d/%Y'.1842 Keyword Arguments:1843 timezone (str): Timezone name, such as 'Asia/Taipei'. Name is handled by `dateutil.tz.gettz()`. Defaults to None.1844 Returns:1845 str/datetime: Today's date in the given format. When `format` is None, it returns as `datetime`.1846 """1847 now = datetime.now(tz.gettz(timezone))1848 return now.strftime(format) if format else now1849 def toggle_attribute(self, locator, name):1850 """Toggle a Boolean attribute of the given element. (IE not supported)1851 Args:1852 locator (str/WebElement): The locator to identify the element or WebElement1853 name ([type]): Attribute name1854 """1855 self.find_element(locator).toggle_attribute(name)1856 def toggle_class(self, locator, class_name):1857 """Toggle the given CSS class of the element.1858 Args:1859 locator (str/WebElement): The locator to identify the element or WebElement1860 class_name (str): CSS class name1861 """1862 self.find_element(locator).toggle_class(class_name)1863 def trigger(self, locator, event):1864 """Trigger the given event on the element.1865 Args:1866 locator (str/WebElement): The locator to identify the element or WebElement1867 event (str): Event name1868 """1869 self.find_element(locator).trigger(event)1870 def value(self, locator, typecast=str):1871 """Get the value of the element using `get_property`.1872 Args:1873 locator (str/WebElement): The locator to identify the element or WebElement1874 Keyword Arguments:1875 typecast: Typecast the value. Defaults to `str`.1876 Returns:1877 The value, by `typecast`, of the element1878 """1879 return typecast(self.find_element(locator).value)1880 def value_now(self, locator, typecast=str):1881 """Get the current value of the element using `get_attribute`.1882 Args:1883 locator (str/WebElement): The locator to identify the element or WebElement1884 Keyword Arguments:1885 typecast: Typecast the value. Defaults to `str`.1886 Returns:1887 The value, by `typecast`, of the element1888 """1889 return typecast(self.find_element(locator).value_now)1890 def values(self, locator, typecast=str):1891 """Get the values of the elements.1892 Args:1893 locator (str): The locator to identify the elements or list[WebElement]1894 Keyword Arguments:1895 typecast: Typecast the values. Defaults to `str`.1896 Returns:1897 list: list of values, by `typecast`, of the given elements1898 """1899 return [typecast(element.value) for element in self.find_elements(locator)]1900 def wait_until(self, method, timeout=None, poll_frequency=0.5, ignored_exceptions=[NoSuchElementException]):1901 """Create a WebDriverWait instance and wait until the given method is evaluated to not False.1902 Args:1903 method (callable): Method to call, and the method takes WebDriver instance as the parameter.1904 Keyword Arguments:1905 timeout (int): Timeout. Defaults to `self.timeout`.1906 poll_frequency (float): Sleep interval between method calls. Defaults to 0.5.1907 ignored_exceptions (list[Exception]): Exception classes to ignore during calls. Defaults to (NoSuchElementException).1908 Returns:1909 Any applicable return from the method call1910 Examples:1911 | wait_until(lambda wd: method(wd), timeout=5)1912 """1913 timeout = int(timeout) if timeout is not None else self.timeout1914 return self.wait(self.driver, timeout, poll_frequency, ignored_exceptions).until(method)1915 def wait_until_alert_present(self):1916 """Wait until alert is present.1917 Returns:1918 False/Alert: Return False if not present. Return Alert if present.1919 """1920 return self.wait_until(lambda _: self._alert_is_present())1921 def wait_until_attribute_contains(self, locator, attribute, value):1922 """Wait until the element's attribute contains the given value.1923 Args:1924 locator (str/WebElement): The locator to identify the element or WebElement1925 attribute (str): Attribute name1926 value (str): value to check1927 Returns:1928 bool: Whether value is found in the element's attribute1929 """1930 try_fn = self._try_and_catch(lambda: self.has_attribute_value(locator, attribute, value))1931 return self.wait_until(lambda _: try_fn())1932 def wait_until_class_contains(self, locator, class_name):1933 """Wait until the element contains the given CSS class.1934 Args:1935 locator (str/WebElement): The locator to identify the element or WebElement1936 class_name (str): CSS class name1937 Returns:1938 bool: Whether the element contains the given CSS class1939 """1940 return self.wait_until(lambda _: self.has_class(locator, class_name))1941 def wait_until_class_excludes(self, locator, class_name):1942 """Wait until the element excludes the given CSS class.1943 Args:1944 locator (str/WebElement): The locator to identify the element or WebElement1945 class_name (str): CSS class name1946 Returns:1947 bool: Whether the element excludes the given CSS class1948 """1949 return self.wait_until(lambda _: not self.has_class(locator, class_name))1950 def wait_until_displayed(self, locator):1951 """Wait until the element is displayed.1952 Args:1953 locator (str/WebElement): The locator to identify the element or WebElement1954 Returns:1955 bool: Whether the element is displayed1956 """1957 return self.wait_until(lambda _: self.is_displayed(locator))1958 def wait_until_displayed_and_get_element(self, locator):1959 """Wait until the element is displayed and return the element.1960 Args:1961 locator (str/WebElement): The locator to identify the element or WebElement1962 Returns:1963 WebElement: WebElement1964 """1965 self.wait_until_displayed(locator)1966 return self.find_element(locator)1967 def wait_until_enabled(self, locator):1968 """Wait until the element is enabled.1969 Args:1970 locator (str/WebElement): The locator to identify the element or WebElement1971 Returns:1972 bool: Whether the element is enabled1973 """1974 return self.wait_until(lambda _: self.is_enabled(locator))1975 def wait_until_frame_available_and_switch(self, frame_locator):1976 """Wait until the given frame is available and switch to it.1977 Args:1978 frame_locator (str/WebElement): The locator to identify the frame or WebElement1979 """1980 self.wait_until(lambda _: self._is_frame_switched(frame_locator))1981 def wait_until_ignored_timeout(self, method, timeout=3):1982 """Wait until the given method timed-out and ignore `TimeoutException`.1983 Args:1984 method ([type]): Method to call1985 Keyword Arguments:1986 timeout (int): [description]. Defaults to 3.1987 Returns:1988 Any applicable return from the method call1989 """1990 _timeout = self.timeout1991 self.timeout = int(timeout)1992 try:1993 return self.wait_until(method, timeout=self.timeout)1994 except TimeoutException:1995 pass1996 finally:1997 self.timeout = _timeout1998 def wait_until_listdir_equal_to(self, directory, number, sleep=2):1999 """Wait until the directory has the given number of files.2000 Args:2001 directory (str): Directory2002 number (int): Number of files in the directory2003 Keyword Arguments:2004 sleep (int): Seconds to sleep after number of files matched. Defaults to 2.2005 Raises:2006 WebDriverException: Raise an error when `directory` is not a directory or when number of files not matched.2007 Returns:2008 bool: Whether the directory has the given number of files2009 """2010 abs_dir = self.abspath(directory, mkdir=False, isdir=True)2011 if not os.path.isdir(abs_dir):2012 raise WebDriverException(f'Not a directory: {directory}')2013 try:2014 self.wait_until(lambda _: len(os.listdir(abs_dir)) == number)2015 if isinstance(sleep, int):2016 self.sleep(sleep)2017 return True2018 except TimeoutException:2019 raise WebDriverException(f'Number of files ({len(os.listdir(abs_dir))}) not equal to {number}.')2020 def wait_until_loading_finished(self, locator, seconds=2, loading_wait=None, sleep=None):2021 """Wait the given `seconds` until loading/spinning element, by `locator`, shows up.2022 If/when shown, wait until not displayed. If not, this is equivalent to sleep the given `seconds`.2023 Args:2024 locator (str/WebElement): The locator to identify the loading-like element2025 Keyword Arguments:2026 seconds (int): Seconds to wait for loading-like element to show. Defaults to 2.2027 loading_wait (int): Seconds to wait for the loading-like element to disappear.2028 When None, it is default to `implicit_wait`. Defaults to None.2029 sleep (int): Seconds to sleep after loading finished. Defaults to None.2030 Returns:2031 bool: Whether the element is not displayed2032 """2033 how, what = self._parse_locator(locator)2034 implicitly_wait = self.implicitly_wait2035 self.implicitly_wait = seconds2036 if loading_wait is None or not isinstance(loading_wait, int):2037 loading_wait = implicitly_wait2038 try:2039 self.wait(self.driver, seconds).until(lambda wd: wd.find_element(how, what).is_displayed())2040 self.implicitly_wait = 02041 try:2042 return self.wait(self.driver, loading_wait).until_not(lambda wd: wd.find_element(how, what).is_displayed())2043 except (NoSuchElementException, StaleElementReferenceException):2044 return True2045 except TimeoutException:2046 raise WebDriverException('Loading element not disappeared before timeout.')2047 except (NoSuchElementException, StaleElementReferenceException, TimeoutException):2048 return True2049 finally:2050 self.implicitly_wait = implicitly_wait2051 if sleep is not None:2052 self.sleep(sleep)2053 def wait_until_located(self, locator):2054 """Wait until the element is located.2055 Args:2056 locator (str/WebElement): The locator to identify the element or WebElement2057 Returns:2058 bool: Whether the element is located2059 """2060 return self.wait_until(lambda _: self.is_located(locator))2061 def wait_until_not(self, method):2062 """Create a WebDriverWait instance and wait until the given method is evaluated to False.2063 Args:2064 method (callable): Method to call2065 Returns:2066 Any applicable return from the method call2067 """2068 return self.wait(self.driver, self.timeout).until_not(method)2069 def wait_until_not_displayed(self, locator, seconds=2):2070 """Wait until the element is not displayed in the given seconds.2071 Args:2072 locator (str): The locator to identify the element2073 Keyword Arguments:2074 seconds (int): Seconds to give up waiting. Defaults to 2.2075 Returns:2076 bool: Whether the element is not displayed2077 """2078 how, what = self._parse_locator(locator)2079 implicitly_wait = self.implicitly_wait2080 self.implicitly_wait = seconds2081 try:2082 return self.wait(self.driver, seconds).until(lambda wd: not wd.find_element(how, what))2083 except (NoSuchElementException, StaleElementReferenceException, TimeoutException):2084 return True2085 finally:2086 self.implicitly_wait = implicitly_wait2087 def wait_until_number_of_windows_to_be(self, number):2088 """Wait until number of windows matches the given number.2089 Args:2090 number (int): Number of windows2091 Returns:2092 bool: Whether number of windows matching the given number2093 """2094 return self.wait_until(expected_conditions.number_of_windows_to_be(number))2095 def wait_until_page_loaded(self):2096 """Wait until `document.readyState` is `complete`."""2097 self.wait_until(lambda _: self.is_page_loaded())2098 def wait_until_page_not_changed(self, seconds=10, interval=2):2099 """Wait until page_source not changed (page_source are compared at the interval)2100 Keyword Arguments:2101 seconds (int): Seconds to give up waiting. Defaults to 10.2102 interval (int): Interval to compare page_source. Defaults to 2.2103 Returns:2104 bool: Whether page_source not changed2105 """2106 implicitly_wait = self.implicitly_wait2107 self.implicitly_wait = seconds2108 try:2109 self.wait(self.driver, seconds).until(lambda _: not self._is_page_changed_at_interval(interval=interval))2110 except TimeoutException:2111 return True2112 finally:2113 self.implicitly_wait = implicitly_wait2114 def wait_until_selected(self, locator):2115 """Wait until the element is selected.2116 Args:2117 locator (str/WebElement): The locator to identify the element or WebElement2118 Returns:2119 bool: Whether the element is selected2120 """2121 return self.wait_until(lambda _: self.is_selected(locator))2122 def wait_until_selection_to_be(self, locator, is_selected):2123 """Wait until the element's `selected` state to match the given state.2124 Args:2125 locator (str/WebElement): The locator to identify the element or WebElement2126 is_selected (bool): Element's `selected` state2127 Returns:2128 bool: Whether the element's `selected` state matching the given state2129 """2130 return self.wait_until(lambda _: self.is_selected(locator) == is_selected)2131 def wait_until_text_contains(self, locator, text):2132 """Wait until the element's text contains the given text.2133 Args:2134 locator (str/WebElement): The locator to identify the element or WebElement2135 text (str): Text to match2136 Returns:2137 bool: Whether the element's text containing the given text2138 """2139 try_fn = self._try_and_catch(lambda: self.has_text(locator, text))2140 return self.wait_until(lambda _: try_fn())2141 def wait_until_text_equal_to(self, locator, text):2142 """Wait until the element's text equal to the given text.2143 Args:2144 locator (str/WebElement): The locator to identify the element or WebElement2145 text (str): Text to not match2146 Returns:2147 bool: Whether the element's text equal to the given text2148 """2149 try_fn = self._try_and_catch(lambda: self.is_text_matched(locator, text))2150 return self.wait_until(lambda _: try_fn())2151 def wait_until_text_excludes(self, locator, text):2152 """Wait until the element's text to exclude the given text.2153 Args:2154 locator (str/WebElement): The locator to identify the element or WebElement2155 text (str): Text to not match2156 Returns:2157 bool: Whether the element's text excluding the given text2158 """2159 try_fn = self._try_and_catch(lambda: not self.has_text(locator, text))2160 return self.wait_until(lambda _: try_fn())2161 def wait_until_text_not_equal_to(self, locator, text):2162 """Wait until the element's text not equal to the given text.2163 Args:2164 locator (str/WebElement): The locator to identify the element or WebElement2165 text (str): Text to not match2166 Returns:2167 bool: Whether the element's text not equal to the given text2168 """2169 try_fn = self._try_and_catch(lambda: not self.is_text_matched(locator, text))2170 return self.wait_until(lambda _: try_fn())2171 def wait_until_title_contains(self, title):2172 """Wait until the title of the current page contains the given title.2173 Args:2174 title (str): Title to match2175 Returns:2176 bool: Whether the title containing the given title2177 """2178 return self.wait_until(expected_conditions.title_contains(title))2179 def wait_until_url_contains(self, url, timeout=None):2180 """Wait until the URL of the current window contains the given URL.2181 Args:2182 url (str): URL to match2183 Keyword Arguments:2184 timeout (int): Timeout. Defaults to `self.page_load_timeout`.2185 Returns:2186 bool: Whether the URL containing the given URL2187 """2188 page_load_timeout = self.page_load_timeout2189 timeout = int(timeout) if timeout is not None else page_load_timeout2190 self.page_load_timeout = timeout2191 try:2192 return self.wait_until(expected_conditions.url_contains(url), timeout=timeout)2193 except TimeoutException:2194 return False2195 finally:2196 self.page_load_timeout = page_load_timeout2197 @property2198 def window_handle(self):2199 """Return the handle of the current window.2200 Returns:2201 str: The current window handle2202 """2203 return self.driver.current_window_handle2204 @property2205 def window_handles(self):2206 """Return the handles of all windows within the current session.2207 Returns:2208 list[str]: List of all window handles2209 """2210 return self.driver.window_handles2211 @property2212 def yml(self):2213 """YAML file as YML instance.2214 Returns:2215 YML: YML instance2216 """2217 return self.__yml2218 @yml.setter2219 def yml(self, file):2220 if isinstance(file, YML):2221 self.__yml = file2222 else:2223 self.__yml = YML(file)2224 def zoom(self, scale):2225 """Set the zoom factor of a document defined by the viewport.2226 Args:2227 scale (float/str): Zoom factor: 0.8, 1.5, or '150%'2228 """2229 self.execute_script('document.body.style.zoom = arguments[0];', scale)2230 def _alert_is_present(self):2231 try:2232 return self.switch_to_alert()2233 except NoAlertPresentException:2234 return False2235 def _auth_extension_as_base64(self, username, password):2236 bytes_ = self._auth_extension_as_bytes(username, password)2237 return base64.b64encode(bytes_).decode('ascii')2238 def _auth_extension_as_bytes(self, username, password):2239 manifest = {2240 "manifest_version": 2,2241 "name": 'Spydr Authentication Extension',2242 "version": '1.0.0',2243 "permissions": ['<all_urls>', 'webRequest', 'webRequestBlocking'],2244 "background": {2245 "scripts": ['background.js']2246 }2247 }2248 background = '''2249 var username = '%s';2250 var password = '%s';2251 chrome.webRequest.onAuthRequired.addListener(2252 function handler(details) {2253 if (username == null) {2254 return { cancel: true };2255 }2256 var authCredentials = { username: username, password: username };2257 // username = password = null;2258 return { authCredentials: authCredentials };2259 },2260 { urls: ['<all_urls>'] },2261 ['blocking']2262 );2263 ''' % (username, password)2264 buffer = BytesIO()2265 zip = zipfile.ZipFile(buffer, 'w')2266 zip.writestr('manifest.json', json.dumps(manifest))2267 zip.writestr('background.js', background)2268 zip.close()2269 return buffer.getvalue()2270 def _auth_extension_as_file(self, username, password, suffix='.crx'):2271 bytes_ = self._auth_extension_as_bytes(username, password)2272 filename = self.abspath('spydr_auth', suffix=suffix, root=self.extension_root)2273 with open(filename, 'wb') as crx_file:2274 crx_file.write(bytes_)2275 return filename2276 def _chrome_options(self):2277 # https://chromium.googlesource.com/chromium/src/+/master/chrome/common/chrome_switches.cc2278 # https://chromium.googlesource.com/chromium/src/+/master/chrome/common/pref_names.cc2279 options = webdriver.ChromeOptions()2280 options.add_argument('allow-running-insecure-content')2281 options.add_argument('ignore-certificate-errors')2282 options.add_argument('ignore-ssl-errors=yes')2283 if self.whitelist:2284 options.add_argument(f'auth-server-whitelist={self._get_whitelist(self.whitelist, wildcard=True)}')2285 options.add_experimental_option("excludeSwitches", ['enable-automation', 'enable-logging'])2286 options.add_experimental_option('useAutomationExtension', False)2287 options.add_experimental_option("prefs", {2288 "credentials_enable_service": False,2289 "download": {2290 "prompt_for_download": False,2291 "directory_upgrade": True,2292 },2293 "intl": {2294 "accept_languages": self.locale2295 },2296 "profile": {2297 "password_manager_enabled": False2298 },2299 "safebrowsing_for_trusted_sources_enabled": False,2300 "safebrowsing": {2301 "enabled": False2302 },2303 "webkit": {2304 "webprefs": {2305 "javascript_can_access_clipboard": True2306 }2307 }2308 })2309 if self.headless:2310 options.add_argument('headless')2311 options.add_argument(f'window-size={self.window_size}')2312 else:2313 # Extension can only be installed when not headless2314 if self.auth_username and self.auth_password:2315 options.add_encoded_extension(self._auth_extension_as_base64(self.auth_username, self.auth_password))2316 return options2317 def _decorator(self, fn):2318 @wraps(fn)2319 def wrapper(*args, **kwargs):2320 # namespace = inspect.currentframe().f_back.f_locals2321 namespace = inspect.stack()[0].frame.f_back.f_locals2322 if 'self' not in namespace or not isinstance(namespace['self'], self.__class__):2323 p1_args = ', '.join(f'{str(x).strip()}' for x in args)2324 p2_args = ', '.join([f'{k}={str(v).strip()}' for k, v in kwargs.items()])2325 fn_name = fn.__name__2326 fn_arguments = ", ".join(x for x in [p1_args, p2_args] if x)2327 self.debug(f'{fn_name}({fn_arguments})')2328 return fn(*args, **kwargs)2329 return wrapper2330 def _firefox_options(self):2331 profile = webdriver.FirefoxProfile()2332 profile.accept_untrusted_certs = True2333 profile.assume_untrusted_cert_issuer = False2334 profile.set_preference('intl.accept_languages', self.locale)2335 if self.whitelist:2336 profile.set_preference('network.automatic-ntlm-auth.trusted-uris', self._get_whitelist(self.whitelist))2337 options = webdriver.FirefoxOptions()2338 options.profile = profile2339 if self.headless:2340 options.add_argument('--headless')2341 return options2342 def _format_locale(self, locale):2343 locale = locale.replace('_', '-')2344 pattern = r'(-[a-zA-Z]{2})$'2345 if self.browser == 'firefox':2346 return re.sub(pattern, lambda m: m.group().lower(), locale)2347 return re.sub(pattern, lambda m: m.group().upper(), locale)2348 def _get_logger(self):2349 logger = logging.getLogger(__name__)2350 logger.setLevel(self.log_level)2351 ch = logging.StreamHandler()2352 ch.setLevel(self.log_level)2353 formatter = logging.Formatter(2354 f'{" " * self.log_indent}%(asctime)s.%(msecs)03d> %(message)s', datefmt=r'%Y-%m-%d %H:%M:%S')2355 ch.setFormatter(formatter)2356 logger.addHandler(ch)2357 return logger2358 def _get_webdriver(self):2359 browsers = ('chrome', 'edge', 'firefox', 'ie', 'safari')2360 config = {'path': self.drivers_root, 'log_level': 50}2361 if self.browser not in browsers:2362 raise WebDriverException(f'Browser must be one of {browsers}: {self.browser}')2363 if self.browser == 'chrome':2364 # https://chromedevtools.github.io/devtools-protocol/tot/Browser/#type-PermissionType2365 return webdriver.Chrome(executable_path=ChromeDriverManager(**config).install(),2366 options=self._chrome_options())2367 if self.browser == 'edge':2368 return webdriver.Edge(EdgeChromiumDriverManager(**config).install())2369 if self.browser == 'firefox':2370 return webdriver.Firefox(executable_path=GeckoDriverManager(**config).install(),2371 options=self._firefox_options(),2372 service_log_path=os.path.devnull)2373 if self.browser == 'ie':2374 return webdriver.Ie(executable_path=IEDriverManager(**config).install(), options=self._ie_options())2375 if self.browser == 'safari':2376 return webdriver.Safari()2377 def _get_whitelist(self, urls, sep=r',?\s+', wildcard=False):2378 url_list = []2379 for url in re.split(sep, urls):2380 o = urllib.parse.urlparse(url)2381 netloc = (o.netloc or o.path).lstrip('*.')2382 url_list.append(f'*.{netloc}' if wildcard else netloc)2383 return ','.join(url_list)2384 def _ie_options(self):2385 options = webdriver.IeOptions()2386 options.ensure_clean_session = True2387 options.full_page_screenshot = True2388 options.ignore_protected_mode_settings = True2389 options.ignore_zoom_level = True2390 options.native_events = False2391 return options2392 def _is_checkbox_or_radio_clicked(self, element):2393 is_selected = element.is_selected()2394 implicitly_wait = self.implicitly_wait2395 self.implicitly_wait = 02396 try:2397 element.click()2398 except:2399 try:2400 element.send_keys(self.keys.SPACE, blur=True)2401 except:2402 element.js_click()2403 finally:2404 self.implicitly_wait = implicitly_wait2405 return True if element.is_selected() is not is_selected else False2406 def _is_clicked(self, locator, scroll_into_view=False, behavior='auto'):2407 try:2408 element = self.find_element(locator)2409 if scroll_into_view:2410 element.scroll_into_view(behavior=behavior)2411 if not element.is_displayed() or not element.is_enabled():2412 return False2413 element.click()2414 return True2415 except (NoSuchWindowException, ElementClickInterceptedException, ElementNotInteractableException, StaleElementReferenceException):2416 return False2417 def _is_frame_switched(self, locator):2418 try:2419 self.switch_to_frame(locator)2420 return True2421 except NoSuchFrameException:2422 return False2423 def _is_page_changed_at_interval(self, interval=1):2424 before_page = self.page_source2425 self.sleep(interval)2426 after_page = self.page_source2427 return before_page != after_page2428 def _is_page_changed_after_refresh(self, body_text_diff=True):2429 before_page = self.find_element('//body').text_content if body_text_diff else self.page_source2430 self.refresh()2431 self.wait_until_page_loaded()2432 after_page = self.find_element('//body').text_content if body_text_diff else self.page_source2433 return before_page != after_page2434 def _is_selectable(self, locator):2435 select = self.find_element(locator)2436 if select.tag_name != 'select':2437 raise WebDriverException(f'Locator is not a select element: {locator}')2438 if not select.is_enabled():2439 return False2440 try:2441 options = select.find_elements('css=option')2442 return select if len(options) > 0 else False2443 except (NoSuchWindowException, StaleElementReferenceException):2444 return False2445 def _multiple_select_to_be(self, element, state):2446 if not isinstance(element, WebElement):2447 raise WebDriverException(f'Not WebElement: {element}')2448 if element.tag_name != 'select':2449 raise WebDriverException(f'Element is not a select: {element}')2450 if element.get_attribute('multiple'):2451 for option in element.find_elements('css=option'):2452 if option.is_selected() != state:2453 option.click()2454 else:2455 raise WebDriverException(f'Element is not a multiple select: {element}')2456 def _option_to_be(self, select, option_value, selected, option_by, multiple=False):2457 option = None2458 if option_by == 'value':2459 option = select.find_element(f'[value="{option_value}"]')2460 elif option_by == 'text':2461 option = select.find_element(f'//*[text()="{option_value}"]')2462 elif option_by == 'index':2463 options = select.find_elements('tag_name=option')2464 index = int(option_value)2465 option = options[index] if index < len(options) else None2466 else:2467 option = select.find_element(f'[{option_by}="{option_value}"]')2468 if not option:2469 raise WebDriverException(f'Cannot using "{option_by}" to identify the option: {option_value}')2470 if option.is_selected() != selected:2471 if multiple:2472 option.click()2473 else:2474 self.click(option)2475 def _parse_locator(self, locator):2476 how, what = Utils.parse_locator(locator)2477 if how == 'yml':2478 if self.yml:2479 return Utils.parse_locator(self.t(what))2480 else:2481 raise WebDriverException(2482 'Cannot use "yml=" as locator strategy when the instance is not assigned with .yml file.')2483 return how, what2484 def _random_option(self, options, ignored_options=[None, "", "0"]):2485 option = Utils.random_choice(options)2486 if option.value in ignored_options:2487 options.remove(option)2488 if len(options) > 0:2489 return self._random_option(options, ignored_options=ignored_options)2490 return None2491 return option2492 def _try_and_catch(self, fn, exceptions=(NoSuchElementException, StaleElementReferenceException), exception_return=False):2493 @wraps(fn)2494 def wrapper(*args, **kwargs):2495 try:2496 return fn(*args, **kwargs)2497 except exceptions:2498 return exception_return2499 return wrapper2500 def _try_and_timeout(self, fn, seconds=None, exception_return=False):2501 @wraps(fn)2502 def wrapper(*args, **kwargs):2503 timeout_ = self.timeout2504 seconds_ = seconds if seconds is not None else timeout_2505 if timeout_ != seconds_:2506 self.timeout = seconds_2507 try:2508 return fn(*args, **kwargs)2509 except TimeoutException:2510 return exception_return2511 finally:2512 if timeout_ != seconds_:2513 self.timeout = timeout_2514 return wrapper2515 def __getattribute__(self, fn_name):2516 log_level = object.__getattribute__(self, 'log_level')2517 fn_method = object.__getattribute__(self, fn_name)2518 if logging.DEBUG >= log_level and not fn_name.startswith('_') and fn_name not in ['debug', 'info', 't'] and hasattr(fn_method, '__self__'):2519 decorator = object.__getattribute__(self, '_decorator')2520 return decorator(fn_method)2521 return fn_method2522class SpydrElement(WebElement):2523 """Wrap WebElement with Spydr-specific implementations.2524 Goals:2525 - Add additional functionality to WebElement2526 - Add Spydr locator formats to WebElement2527 Args:2528 spydr_or_element_self (Spydr/SpydrElement): Spydr or SpydrElement self2529 element (WebElement): WebElement instance2530 """2531 def __new__(cls, spydr_or_element_self, element):2532 instance = super().__new__(cls)2533 instance.__dict__.update(element.__dict__)2534 return instance2535 def __init__(self, spydr_or_element_self, element):2536 if isinstance(spydr_or_element_self, Spydr):2537 self.spydr = spydr_or_element_self2538 elif isinstance(spydr_or_element_self, WebElement):2539 self.spydr = spydr_or_element_self.spydr2540 def add_class(self, class_name):2541 """Add the given CSS class to the element.2542 Args:2543 class_name (str): CSS class name2544 """2545 self.parent.execute_script('return arguments[0].classList.add(arguments[1]);', self, class_name)2546 def blur(self):2547 """Trigger blur event on the element."""2548 self.parent.execute_script('arguments[0].blur();', self)2549 @property2550 @_WebElementSpydrify()2551 def children(self):2552 """Get the children elements.2553 Returns:2554 list[WebElement]: The children elements of the current element.2555 """2556 return self.parent.execute_script('return arguments[0].children;', self)2557 def clear(self):2558 """Clears the text if it’s a text-entry element."""2559 super().clear()2560 def clear_and_send_keys(self, *keys, blur=False, wait_until_enabled=False):2561 """Clear the element and then send the given keys.2562 Args:2563 *keys: Any combinations of strings2564 Keyword Arguments:2565 blur (bool): Lose focus after sending keys. Defaults to False.2566 wait_until_enabled (bool): Whether to wait until the element `is_enabled()` before clearing and sending keys. Defaults to False.2567 Returns:2568 WebElement: WebElement2569 """2570 if wait_until_enabled:2571 self.spydr.wait_until_enabled(self)2572 self.clear()2573 self.send_keys(*keys, blur=blur)2574 return self2575 def click(self, scroll_into_view=False):2576 """Click the element.2577 Keyword Arguments:2578 scroll_into_view (bool): Whether to scroll the element into view before clicking. Defaults to False.2579 """2580 if scroll_into_view:2581 self.scroll_into_view()2582 super().click()2583 @_WebElementSpydrify()2584 def closest(self, locator):2585 """Traverse the current element and its parents until it finds an element that matches the given locator.2586 Will return itself or the matching ancestor. (IE not supported)2587 Args:2588 locator (str): The locator to identify the element2589 Returns:2590 WebElement: WebElement2591 """2592 how, what = self._parse_locator(locator, descendant=False)2593 if how == HOWS['css']:2594 return self.parent.execute_script('return arguments[0].closest(`${arguments[1]}`);', self, what)2595 if how == HOWS['class']:2596 return self.parent.execute_script('return arguments[0].closest(`.${arguments[1]}`);', self, what)2597 if how == HOWS['id']:2598 return self.parent.execute_script('return arguments[0].closest(`#${arguments[1]}`);', self, what)2599 if how == HOWS['link_text']:2600 return self.find_element(f'xpath=./ancestor-or-self::a[normalize-space(.)="{what}"]')2601 if how == HOWS['name']:2602 return self.parent.execute_script('return arguments[0].closest(`[name="${arguments[1]}"]`);', self, what)2603 if how == HOWS['partial_link_text']:2604 return self.find_element(f'xpath=./ancestor-or-self::a[contains(normalize-space(.), "{what}")]')2605 if how == HOWS['tag_name']:2606 return self.parent.execute_script('return arguments[0].closest(`${arguments[1]}`);', self, what)2607 if how == HOWS['xpath']:2608 return self.find_element(f'xpath=./ancestor-or-self::{what.lstrip("/")}')2609 def copy_and_paste(self, text):2610 """Copy text to clipboard and paste it (send_keys) to the element. (Chrome only)2611 Args:2612 text (str): Text to paste2613 """2614 self.spydr.copy_to_clipboard(text)2615 self.paste_from_clipboard()2616 def css_property(self, name):2617 """The value of CSS property.2618 Args:2619 name (str): CSS property name2620 Returns:2621 str: CSS property value2622 """2623 return self.value_of_css_property(name)2624 def ctrl_click(self):2625 """Ctrl-click the element."""2626 control = Keys.CONTROL2627 self._actions().key_down(control).click(self).key_up(control).perform()2628 @property2629 def current_url(self):2630 """The element's current URL.2631 Returns:2632 str: URL2633 """2634 return self.parent.current_url2635 def double_click(self):2636 """Double-click the element."""2637 self._actions().move_to_element(self).double_click().perform()2638 def double_click_with_offset(self, x_offset=1, y_offset=1):2639 """Double-click the element from x and y offsets.2640 Keyword Arguments:2641 x_offset (int): X offset from the left of the element. Defaults to 1.2642 y_offset (int): Y offset from the top of the element. Defaults to 1.2643 """2644 self._actions().move_to_element_with_offset(self, x_offset, y_offset).double_click().perform()2645 @_WebElementSpydrify()2646 def find_element(self, locator):2647 """Find the element by the given locator.2648 Args:2649 locator (str): The locator to identify the element2650 Returns:2651 WebElement: The element found2652 """...

Full Screen

Full Screen

wf_reporting_object.py

Source:wf_reporting_object.py Github

copy

Full Screen

...90 field_path=utillity.UtillityMethods.get_masterfile_field_path(self, master_file_name, field_path_key)91 Wf_Reporting_Object.select_data_field(self, field_path, position)92 selected_row_css="#metaDataBrowser div[id*='MetaDataTree-'] tr[class*='selected'] img[class*='icon']"93 newelement = self.driver.find_element_by_css_selector(selected_row_css)94 utillity.UtillityMethods.double_click_with_offset(self, newelement, x_offset=40)95 time.sleep(5)96 97 def ro_create_filter_group(self, input_textvalue, msg):98 """99 @Param : input_textvalue ->'Product' or 'Product, Category'100 @Usage : ro_create_filter_group('Product', "Step X: Verify the given input value is valid")101 """102 input_css=self.driver.find_element_by_css_selector("#promptDlg #inputBox input")103 utillity.UtillityMethods.set_text_field_using_actionchains(self, input_css, input_textvalue)104 expected_text_value=input_css.get_attribute('value')105 utillity.UtillityMethods.asequal(self, expected_text_value, input_textvalue, msg)106 filter_btn="#btnOK"107 parent_css=self.driver.find_element_by_css_selector(filter_btn)108 utillity.UtillityMethods.click_on_screen(self, parent_css, "middle", click_type=0)...

Full Screen

Full Screen

metadata.py

Source:metadata.py Github

copy

Full Screen

...22 Example Usage : double_click_on_data_filed('Dimensions->COUNTRY->COUNTRY->COUNTRY', field_position=3)23 """24 MetaData.select_data_field(self, data_field_path, field_position=field_position)25 field_object=self.driver.find_element_by_css_selector(MetaData.SELECTED_DATA_FIELD_CSS)26 utillityobject.double_click_with_offset(self, field_object, x_offset=30, mouse_duration=0)27 time.sleep(1)28 29 def right_click_on_data_filed(self, data_field_path, field_position=1):30 """31 This method used to expand and right click on specific data field32 data_field_path = 'Dimensions->COUNTRY->COUNTRY->COUNTRY'33 field_position = 1 , 2, 334 Example Usage : right_click_on_data_filed('Dimensions->COUNTRY->COUNTRY->COUNTRY', field_position=3)35 """36 MetaData.select_data_field(self, data_field_path, field_position=field_position)37 field_object=self.driver.find_element_by_css_selector(MetaData.SELECTED_DATA_FIELD_CSS)38 utillityobject.right_click_with_offset(self, field_object, x_offset=30, mouse_duration=0)39 utillityobject.synchronize_with_number_of_element(self, "div[id^='BiPopup'][style*='inherit']", 1, expire_time=4)40 ...

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