def get_table_element_by_css(locator, anchor): table_element = javascript.execute_javascript( 'return document.querySelectorAll(\'table[summary^="{0}"], ' 'table[name^="{0}"], table[title^="{0}"], th[title^="{0}"], ' 'tr[title^="{0}"], td[title^="{0}"]\')'.format(locator)) if table_element: try: anchor = int(anchor) - 1 if table_element[anchor].tag_name == 'table': return table_element[anchor] table_element = javascript.execute_javascript( 'return arguments[0].closest("table")', table_element[anchor]) return table_element except (ValueError, TypeError): raise IndexError( 'Element found by it\'s attribute. When using CSS Selectors' # pylint: disable=W0707 ' for finding table, anchor has to be index when anchor is not ' 'related to separate locator element') except StaleElementReferenceException: logger.debug('Staling element..Retrying') return None try: locator_element = text.get_text_using_anchor(locator, anchor) table_element = javascript.execute_javascript( 'return arguments[0].closest("table")', locator_element) except (ValueError, NoSuchElementException, StaleElementReferenceException): return None if table_element: return table_element return None
def get_checkbox_by_locator(locator, anchor): """Get checkbox element. Parameters ---------- locator : str Either text that points to the checkbox or direct xpath to the checkbox. If using direct XPath then add prefix xpath=. anchor : str Using if locator is not an XPath. Returns ------- WebElement """ if locator.startswith("xpath=") or locator.startswith("//"): checkbox_element = element.get_unique_element_by_xpath(locator) # TODO: Check that the element is actually a checkbox else: # No prefix given text_element = text.get_text_using_anchor(locator, anchor) xpath = '//input[@type="checkbox"]|//*[@role="checkbox"]' checkbox_elements = element.get_webelements_in_active_area( xpath, stay_in_current_frame=True) checkbox_element = element.get_closest_element(text_element, checkbox_elements) return checkbox_element, None
def get_checkbox_by_css_selector(locator, anchor, index, **kwargs): """Get checkbox using css selectors.""" checkbox_elements = [] partial_matches = [] css = '[type="checkbox"], [role="checkbox"]' if 'qweb_old' not in kwargs: full_matches, partial_matches = element.get_elements_by_css( locator, css, **kwargs) if full_matches: checkbox_elements = element.get_visible_elements_from_elements( full_matches, **kwargs) if checkbox_elements: return checkbox_elements[index], None try: locator_element = text.get_text_using_anchor(locator, anchor) checkbox_elements = list( dict.fromkeys( element.get_element_from_childnodes(locator_element, css, ** kwargs) + partial_matches)) return checkbox_elements[index], locator_element except QWebElementNotFoundError: logger.trace( 'Element not found by visible text. Trying with partial match') checkbox_elements = partial_matches if checkbox_elements: logger.debug("Found element {}, index {}".format( checkbox_elements, index)) return checkbox_elements[index], None return None, None
def get_dropdown_element_by_css_selector(locator, anchor, index, **kwargs): """Get Dropdown element using css selectors. Parameters ---------- locator : str Label text or attribute that points to the dropdown. Looking for placeholder and commonly used tooltip-attributes first. If locator is label text, finds input element by it's for attribute. if for attribute is not available, then finds element by doing some DOM traversing. anchor : str Using if locator is not an XPath. index : int If multiple elements use index to pick correct one. Returns ------- WebElement """ dropdown_elements = [] partial_matches = [] css = 'select' if 'qweb_old' not in kwargs: full_matches, partial_matches = element.get_elements_by_css( locator, css, **kwargs) if full_matches: if index != 0: try: return full_matches[index] except IndexError as e: raise QWebInstanceDoesNotExistError( f'Found {len(full_matches)} elements. Given index was {index}' ) from e correct_element = text.get_element_using_anchor( full_matches, anchor) return correct_element try: locator_element = text.get_text_using_anchor(locator, anchor) # if this is option, return parent select immediately if locator_element.tag_name.lower() == "option": return javascript.execute_javascript( "return arguments[0].parentNode;", locator_element) dropdown_elements = list( dict.fromkeys( element.get_element_from_childnodes(locator_element, css, ** kwargs) + partial_matches)) except QWebElementNotFoundError: logger.trace( 'Element not found by visible text. Trying with partial match') dropdown_elements = partial_matches if dropdown_elements: return dropdown_elements[index] return None
def get_dropdown_element_by_locator(locator, anchor): """Find dropdown element. Parameters ---------- locator : str Text that locates the input field. The input field that is closest to the text is selected. Also one can use xpath by adding xpath= prefix and then the xpath. Error is raised if the xpath matches to multiple elements. anchor : str Text near the input field's locator element. If the page contains many places where the locator is then anchor is used to get the one that is closest to it. """ if locator.startswith("xpath=") or locator.startswith("//"): dropdown_element = element.get_unique_element_by_xpath(locator) else: # Search using text # First we look through all select elements' options, matching locator matches = [] elements = _get_all_dropdown_elements() for dd_element in elements: options = [x.text for x in Select(dd_element).options] if locator in options: logger.debug("Found dropdown with options %s" % options) matches.append(dd_element) if matches: correct_element = text.get_element_using_anchor(matches, anchor) return correct_element # Then we try to find the element using attributes and text dropdown_xpath = ( # pylint: disable=line-too-long '//select[normalize-space(@placeholder)="{0}" or normalize-space(@value)="{0}" or normalize-space(text())="{0}"]' .format(locator)) dropdown_elements = element.get_webelements_in_active_area( dropdown_xpath) if len(dropdown_elements) == 1: dropdown_element = dropdown_elements[0] elif not dropdown_elements: # Find dropdown element using locator locator_element = text.get_text_using_anchor(locator, anchor) dropdown_elements = _get_all_dropdown_elements( stay_in_current_frame=True) dropdown_element = element.get_closest_element( locator_element, dropdown_elements) else: # Found many logger.debug("found many, using anchor") dropdown_element = text.get_element_using_anchor( dropdown_elements, anchor) return dropdown_element
def get_table_element(self, locator, anchor): if util.xpath_validator(locator): table_element = element.get_unique_element_by_xpath(locator) else: # Search using text table_xpath = "//*[text()= '{0}']/ancestor::table".format(locator) table_elements = element.get_webelements_in_active_area( table_xpath) if table_elements and len(table_elements) == 1: table_element = table_elements[0] elif not table_elements: # Find table element using locator locator_element = text.get_text_using_anchor(locator, anchor) table_elements = self._get_all_table_elements() table_element = element.get_closest_element( locator_element, table_elements) else: # Found many table_element = text.get_element_using_anchor( table_elements, anchor) if table_element: return table_element raise QWebElementNotFoundError( 'Table element not found by locator {}'.format(locator))
def get_input_element_by_locator(locator, anchor, **kwargs): """Find input element. Parameters ---------- locator : str Text that locates the input field. The input field that is closest to the text is selected. Also one can use xpath by adding xpath= prefix and then the xpath. Error is raised if the xpath matches to multiple elements. anchor : str Text near the input field's locator element. If the page contains many places where the locator is then anchor is used to get the one that is closest to it. """ if locator.startswith("xpath=") or locator.startswith( "//") or locator.startswith("(//"): if locator.startswith("xpath="): xpath = locator.split("=", 1)[1] else: xpath = locator input_element = element.get_unique_element_by_xpath(xpath, **kwargs) else: # Search using text input_xpath = CONFIG["MatchingInputElement"].format(locator) input_elements = element.get_webelements_in_active_area( input_xpath, **kwargs) if not input_elements: # Find input element using locator locator_element = text.get_text_using_anchor( locator, anchor, **kwargs) input_elements = _get_all_input_elements() input_element = element.get_closest_element( locator_element, input_elements) elif len(input_elements) == 1: input_element = input_elements[0] # pylint: disable=unsubscriptable-object else: # Found many input_element = text.get_element_using_anchor( input_elements, anchor, **kwargs) return input_element
def get_draggable_element(text, index, anchor): attribute_match = '[title^="{0}"][draggable="true"],[alt^="{0}"][draggable="true"],' \ '[tooltip^="{0}"][draggable="true"],' \ '[data-tooltip^="{0}"][draggable="true"],' \ '[data-icon^="{0}"][draggable="true"],' \ '[aria-label^="{0}"][draggable="true"],' \ '[title^="{0}"][class*="draggableCell"]'.format(text) web_elements = [] matches = [] if text.startswith('xpath=') or text.startswith('//'): web_element = element.get_unique_element_by_xpath(text) if web_element: return web_element raise QWebElementNotFoundError('Draggable element not found by locator {}'.format(text)) try: index = int(index) - 1 except ValueError as e: raise QWebValueError('Index needs to be number') from e web_elements = javascript.execute_javascript( 'return document.querySelectorAll(\'{}\')'.format(attribute_match)) if web_elements: return web_elements[index] web_elements = javascript.execute_javascript( 'return document.querySelectorAll(\'[draggable="true"]\')') if web_elements: matches = _find_matches(web_elements, text) if matches: return matches[index] if text == 'index': logger.warn('Text is not matching to any draggable element. Found {} ' 'draggable elements. Using index..'.format(len(web_elements))) return web_elements[index] web_elements = get_text_using_anchor(text, anchor) if web_elements: return web_elements raise QWebElementNotFoundError('Draggable element not found by locator {}'.format(text))
def drag_drop(locator, target_locator, index=1, anchor="1", target_anchor="1", timeout=0, dragtime='0.5s', left=0, right=0, above=0, below=0): # pylint: disable=unused-argument """Drag and drop element. Finds draggable element by it's visible text, tooltip attribute, index or xpath. Target element is found by it's visible text or xpath. Keyword tries to drag element to target element. Gets coordinates from WebDriver and uses pyautogui to simulate mouse actions based on those coordinates. Zoom level needs to be 100% in screen settings so that coordinates are matching with actual view. (Preferable resolution 1920x1080) Examples -------- .. code-block:: robotframework DragDrop draggable target DragDrop draggable //*[@id="some_id"] DragDrop index Foo index=3 DragDrop draggable target dragtime=2s DragDrop draggable target right=5 below=2 Parameters ---------- locator : str Visible text, some element attribute(check ClickItem), xpath or text index to locate draggable element. target_locator : str Visible text or xpath to locate target element for draggable. index : int Index to point out right draggable if there is many or if there is no visible text/attribute which can be use to locate correct element. anchor : str In some cases(f.e Angular) element could be draggable even if draggable attribute doesn't exists. Then we are using traditional text match(check clicktext) to find correct element. Anchor can be index or some text near to draggable element. (default 1) target_anchor Text near the target element or index. If the page contains many places where the text argument is then anchor is used to get the one that is closest to it. (default 1) timeout : str | int How long we try to find elemenst before failing dragtime : str |int How long drag should take. Some applications need longer time right : int Offset how many pixels right of target center we drag left : int Offset how many pixels left of target center we drag above : int Offset how many pixels above of target center we drag below : int Offset how many pixels below of target center we drag """ pyautogui.FAILSAFE = False draggable = dragdrop.get_draggable_element(locator, index, anchor) if target_locator.startswith('xpath=') or target_locator.startswith('//'): target_elem = element.get_unique_element_by_xpath(target_locator) else: target_elem = internal_text.get_text_using_anchor( target_locator, target_anchor) x, y = _get_coordinates(draggable) logger.debug('draggable x is {} and y is {}'.format(x, y)) pyautogui.moveTo(x, y) x, y = _get_coordinates(target_elem) x = x + int(right) - int(left) y = y - int(above) + int(below) logger.debug('target x is {} and y is {}'.format(x, y)) dragtime = timestr_to_secs(dragtime) pyautogui.dragTo(x, y, dragtime, button='left') pyautogui.FAILSAFE = True
def get_input_element_by_css_selector(locator, anchor, index=0, enable_check=False, **kwargs): """Get input element using css selectors. Parameters ---------- locator : str Label text or attribute that points to the input. Looking for placeholder and commonly used tooltip-attributes first. If locator is label text, finds input element by it's for attribute. if for attribute is not available, then finds element by doing some DOM traversing. anchor : str Text near the locator element or index. If placeholder or another direct attribute (title, tooltip, value) exists then anchor has to be index. Text is aloud when searching by label or some other text which is near to input element. index: int If multiple input elements is nested or in same table cell, index is needed. enable_check: bool If enable_check is set to true returns first match even if disabled one. Returns ------- WebElement """ partial_matches = [] upload = kwargs.get('upload') if upload: try: index = int(locator) - 1 kwargs['any_element'] = True input_elements = element.get_elements_by_attributes(**kwargs) if input_elements: return input_elements[index] except ValueError: logger.debug('locator was text') if 'qweb_old' not in kwargs: full_matches, partial_matches = element.get_elements_by_css( locator, **kwargs) if full_matches: input_element = element.get_visible_elements_from_elements( full_matches, **kwargs) if input_element and str(anchor) == '1': input_element = input_element[index] return input_element if input_element: input_element = text.get_element_using_anchor( input_element, anchor, **kwargs) return input_element try: locator_element = text.get_text_using_anchor(locator, anchor, **kwargs) input_elements = list( dict.fromkeys( element.get_element_from_childnodes(locator_element, **kwargs) + partial_matches)) except QWebElementNotFoundError: logger.trace( 'Element not found by visible text. Trying with partial match') input_elements = partial_matches if input_elements: visibles = element.get_visible_elements_from_elements( input_elements, **kwargs) if visibles: if element.is_enabled(visibles[index]) or enable_check is True: return visibles[index] return None