def _get_row_by_locator_text(rows, locator, anchor): matches = [] input_elements = [] row_index = [] anchor_text = None try: anchor = int(anchor) - 1 except ValueError: anchor_text = anchor for index, row in enumerate(rows): row_content = row.text if locator == 'EMPTY' and row_content.strip() == '': return row, index input_elements = javascript.execute_javascript( 'return arguments[0].querySelectorAll("input, textarea")', row) for elem in input_elements: row_content += str( javascript.execute_javascript('return arguments[0].value', elem)) if locator in row_content: if anchor_text and anchor_text in row_content: return row, index row_index.append(index) matches.append(row) if matches and not anchor_text: return matches[anchor], row_index[anchor] raise QWebElementNotFoundError( 'Row that includes texts {} and {} not found'.format( locator, anchor_text))
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 open_window(): r"""Open new tab. Uses javascript to do this so javascript has to be enabled. Examples -------- .. code-block:: robotframework OpenWindow Related keywords ---------------- \`CloseAllBrowsers\`, \`CloseBrowser\`, \`CloseOthers\`, \`GoTo\`, \`OpenBrowser\`, \`SwitchWindow\` """ script = 'window.open()' javascript.execute_javascript(script) window_handles = window.get_window_handles() current_window_handle = window.get_current_window_handle() index = window_handles.index(current_window_handle) new_window_index = index + 1 window.switch_to_window(window_handles[new_window_index]) try: xhr.setup_xhr_monitor() except QWebDriverError: logger.debug('XHR monitor threw exception. Bypassing jQuery injection')
def checkbox_set(checkbox_element, locator_element, value, **kwargs): # pylint: disable=unused-argument if checkbox.is_checked(checkbox_element) != value: try: checkbox_element.click() except WebDriverException: if locator_element: locator_element.click() else: javascript.execute_javascript( "arguments[0].checked={}".format( "true" if value else "false"), checkbox_element)
def _get_coordinates(web_element): x_diff = javascript.execute_javascript( 'return window.outerWidth-window.innerWidth+screen.availLeft') y_diff = javascript.execute_javascript( 'return window.outerHeight-window.innerHeight+screen.availTop') elem = javascript.execute_javascript( "return arguments[0].getBoundingClientRect()", web_element) logger.debug("coords: {0}".format(elem)) y = elem['y'] x_coord = web_element.location['x'] + x_diff + web_element.size['width'] / 2 y_coord = y + y_diff + web_element.size['height'] / 2 return x_coord, y_coord
def scroll_dynamic_web_page(text_to_find, scroll_length, slow_mode, timeout): visible = None js_browser_height = "return window.innerHeight" height = javascript.execute_javascript(js_browser_height) # Length of one scroll js_current_pos = "return window.pageYOffset;" js_scroll = 'window.scrollBy(0,{})'.format(scroll_length or height) current_pos = javascript.execute_javascript(js_current_pos) old_pos = None start = time.time() if not slow_mode: while not visible and old_pos != current_pos and time.time() < timeout + start: old_pos = javascript.execute_javascript(js_current_pos) javascript.execute_javascript(js_scroll) time.sleep(.5) current_pos = javascript.execute_javascript(js_current_pos) visible = internal_text.get_element_by_locator_text(text_to_find, allow_non_existent=True) logger.info('\nOld pos: {}\nCurrent pos: {}\nVisible: {}' .format(old_pos, current_pos, visible), also_console=True) else: logger.info('\nSlow mode is on, execution will only stop if the text "{}" is found or if ' 'the timeout is reached.'.format(text_to_find), also_console=True) while not visible and time.time() < timeout + start: javascript.execute_javascript(js_scroll) time.sleep(.5) visible = internal_text.get_element_by_locator_text(text_to_find, allow_non_existent=True) logger.info('\nVisible: {}'.format(visible), also_console=True) if visible: return True raise QWebTextNotFoundError('Could not find text "{}" after scrolling for {} pixels.' .format(text_to_find, current_pos))
def execute_javascript(script, variable_name=None): """Execute javascript and save the result to suite variable. Examples -------- .. code-block:: robotframework ExecuteJavascript document.getElementsByTagName("p")[0].innerText="Write text"; ExecuteJavascript return document.title; $TITLE Parameters ---------- script : str Javascript code. variable_name : str Robot framework variable name without {}. (Default None) """ output = javascript.execute_javascript(script) logger.info('Output of execution:\n{}'.format(output)) if variable_name: try: BuiltIn().set_suite_variable(variable_name, output) except Exception as e: logger.warn(e.__str__()) raise QWebValueError("Invalid variable syntax '{}'.".format(variable_name))
def use_frame(locator): """Make following keywords to use frame on a page. Examples -------- .. code-block:: robotframework UseFrame //iframe Parameters ---------- locator : str Xpath expression without xpath= prefix or index (first = 1 etc.) Raises ------ NoSuchFrameException If the frame is not found """ frame.wait_page_loaded() try: index = int(locator) - 1 webelement = javascript.execute_javascript( 'document.querySelectorAll("iframe, frame")[{}]'.format(index)) except ValueError: webelement = element.get_unique_element_by_xpath(locator) driver = browser.get_current_browser() try: driver.switch_to_frame(webelement) except NoSuchFrameException: raise NoSuchFrameException('No frame wound with xpath: {0}'.format(locator))
def setup_xhr_monitor(): """Inject jQuery if needed and check if page is ready. Setup_xhr_monitor injects jQuery to page if there isn't one already. """ try: js = """ function inject(){ if (typeof(jQuery) === "undefined"){ var head = document.querySelector('head'); var script = document.createElement('script'); script.type = "text/javascript"; script.src = "https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js" head.appendChild(script); if (typeof(jQuery) === "undefined"){ return false; } } return true; } return inject()""" return javascript.execute_javascript(js) except (WebDriverException, JavascriptException) as e: raise QWebDriverError(e) # pylint: disable=W0707
def get_element_to_click_from_list(active_list, index, **kwargs): if 'tag' in kwargs: element = javascript.execute_javascript( 'return arguments[0].querySelector("{}")'.format(kwargs['tag']), active_list[index]) else: element = active_list[index] return element
def scroll_first_scrollable_parent_element(locator, anchor, text_to_find, scroll_length, slow_mode, timeout): visible = None js_get_parent_element = """ function getScrollParent(node) { if (node == null) { return null; } if (node.scrollHeight > node.clientHeight) { return node; } else { return getScrollParent(node.parentNode); } } return getScrollParent(arguments[0]); """ js_element_position = "return arguments[0].scrollTop;" js_element_scroll = "arguments[0].scrollBy(0, {})".format(scroll_length or '1000') web_element = internal_text.get_element_by_locator_text(locator, anchor) scrollable_element = javascript.execute_javascript(js_get_parent_element, web_element) current_pos = javascript.execute_javascript(js_element_position, scrollable_element) old_pos = None start = time.time() if not slow_mode: while not visible and old_pos != current_pos and time.time( ) < timeout + start: old_pos = javascript.execute_javascript(js_element_position, scrollable_element) javascript.execute_javascript(js_element_scroll, scrollable_element) time.sleep(.5) current_pos = javascript.execute_javascript( js_element_position, scrollable_element) visible = internal_text.get_element_by_locator_text( text_to_find, allow_non_existent=True) logger.info('Old pos: {}\nNew pos: {}\nVisible: {}'.format( old_pos, current_pos, visible), also_console=True) else: logger.info( '\nSlow mode is on, execution will only stop if the text "{}" is found or if ' 'the timeout is reached.'.format(text_to_find), also_console=True) while not visible and time.time() < timeout + start: javascript.execute_javascript(js_element_scroll, scrollable_element) time.sleep(.5) visible = internal_text.get_element_by_locator_text( text_to_find, allow_non_existent=True) logger.info('\nVisible: {}'.format(visible), also_console=True) if visible: return raise QWebTextNotFoundError('Text {} not found.'.format(text_to_find))
def find_text(text): try: if javascript.execute_javascript( "return window.find('{}')".format(text.replace("\'", "\\'"))): return True except WebDriverException as e: logger.debug('Got webdriver exception from find text func: {}'.format(e)) raise QWebElementNotFoundError('Text not found')
def get_table_by_locator_table(locator, parent, child, level, index): if parent: script = ".parentElement.closest('table')" * int(level) parent_table = javascript.execute_javascript( "return arguments[0]{}".format(script), locator) if parent_table: if not child: return parent_table locator = parent_table else: raise QWebElementNotFoundError('No parent table found') if child: script = ".querySelectorAll('table')[{}]".format(int(index) - 1) child_table = javascript.execute_javascript( "return arguments[0]{}".format(script), locator) if child_table: return child_table raise QWebElementNotFoundError('No child table found') raise QWebElementNotFoundError('Sub/parent table not found')
def get_cell_by_locator(self, locator): rows = self.get_all_rows() for i, r in enumerate(rows): # pylint: disable=unused-variable cells = self.get_cells_from_row(r) for index, c in enumerate(cells): cell_text = "" if c.text: cell_text += c.text elif javascript.execute_javascript( 'return arguments[0].querySelector("input, textarea")', c): value = javascript.execute_javascript( 'return arguments[0].value', c) if value: cell_text += str(value) if locator in cell_text: return index + 1 raise QWebValueError( 'Matching table cell not found for locator {}.'.format(locator))
def write(self, input_element, input_text, **kwargs): """ Writes the given text using configured writer. """ write = self._get_writer() # By clearing the input field with Javascript, # we avoid triggering focus events right after # clear and trigger them only on send_keys call. clear_key = self.check_key(kwargs.get('clear_key', self.clear_key)) if not clear_key: if self.is_editable_text_element(input_element): javascript.execute_javascript('arguments[0].innerText=""', input_element) else: javascript.execute_javascript("arguments[0].value = \"\"", input_element) else: input_element.send_keys(clear_key) write(input_element, input_text) if 'check' not in kwargs: line_break = kwargs.get('key', self.check_key(self.line_break_key)) if line_break: input_element.send_keys(line_break)
def get_using_text_in_coordinates(self, coordinates, anchor): row_elem = None cell = None locator = coordinates.split('/') if locator[0].startswith('r?'): row_elem = self.get_row(locator[0][2:], anchor) else: row, _ = self._convert_coordinates(locator[0]) if locator[1].startswith('c?'): column = self.get_cell_by_locator(locator[1][2:]) else: _, column = self._convert_coordinates(locator[1]) if row_elem: cell = javascript.execute_javascript( 'return arguments[0].cells[{}]'.format(column - 1), row_elem) else: cell = javascript.execute_javascript( 'return arguments[0].rows[{}].cells[{}]'.format( row - 1, column - 1), self.table) return cell
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_elements_by_locator_xpath_and_tag_name(locator, index=1, **kwargs): index = int(index) - 1 if 'tag' in kwargs: tag_name = kwargs.get('tag') elif 'parent' in kwargs and kwargs['parent']: tag_name = kwargs['parent'] elif 'child' in kwargs and kwargs['child']: tag_name = kwargs['child'] else: tag_name = 'ul' if 'parent' in kwargs and kwargs['parent']: web_element = element.get_unique_element_by_xpath(locator) css = kwargs.get('parent') web_element = element.get_parent_list_element(web_element, css) if tag_name not in ["ul", "ol", "dl", "UL", "OL", "DL"]: web_element = javascript.execute_javascript( 'return arguments[0].querySelectorAll("{}")'.format( tag_name), web_element) else: web_element = javascript.execute_javascript( 'return arguments[0].closest("{}").querySelectorAll("li, dt, dd")' .format(tag_name), web_element) elif 'child' in kwargs and kwargs['child']: web_element = element.get_unique_element_by_xpath(locator) css = kwargs.get('child') web_element = element.get_element_from_childnodes( web_element, css, dom_traversing=False)[index] if tag_name not in ["ul", "ol", "dl", "UL", "OL", "DL"]: web_element = javascript.execute_javascript( 'return arguments[0].querySelectorAll("{}")'.format( tag_name), web_element) else: web_element = javascript.execute_javascript( 'return arguments[0].closest("{}").querySelectorAll("li, dt, dd")' .format(tag_name), web_element) else: web_element = element.get_webelements_in_active_area(locator) return web_element
def get_elements_by_locator_text_and_tag_name(locator, anchor, index=1, **kwargs): index = int(index) - 1 if 'tag' in kwargs: tag_name = kwargs.get('tag') elif 'parent' in kwargs and kwargs['parent']: tag_name = kwargs['parent'] elif 'child' in kwargs and kwargs['child']: tag_name = kwargs['child'] else: tag_name = 'ul' web_element = text.get_element_by_locator_text(locator, anchor) if 'parent' in kwargs and kwargs['parent']: tag = kwargs['parent'] locator_element = element.get_parent_list_element(web_element, tag) elif 'child' in kwargs and kwargs['child']: tag = kwargs['child'] locator_element = element.get_element_from_childnodes( web_element, tag, dom_traversing=False)[index] if tag_name not in ["ul", "ol", "dl", "UL", "OL", "DL"]: return locator_element else: locator_element = text.get_element_by_locator_text(locator, anchor) if tag_name not in ["ul", "ol", "dl", "UL", "OL", "DL"]: web_elements = javascript.execute_javascript( 'return arguments[0].querySelectorAll("{}")'.format(tag_name), locator_element) else: web_elements = javascript.execute_javascript( 'return arguments[0].closest("{}").querySelectorAll("li, dt, dd")' .format(tag_name), locator_element) return web_elements
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 is_visible(element): """Is the element interactable? Uses the display attribute to determine if form element is visible or not. Parameters ---------- element : WebElement Returns ------- bool """ visibility = javascript.execute_javascript('return arguments[0].style.display', element) return bool(visibility.lower() != 'none')
def is_readonly(element): """Is the element interactable? Uses the readonly attribute to determine if form element is enabled or not. Parameters ---------- element : WebElement Returns ------- bool """ return util.par2bool(javascript.execute_javascript( 'return arguments[0].hasAttribute("readonly")', element))
def check_frames(driver, **kwargs): visible_frames = [] frames = javascript.execute_javascript( 'return document.querySelectorAll("iframe, frame")') frames += driver.find_elements_by_xpath("//iframe|//frame") visible_only = kwargs.get('visibility', True) if not visible_only: return frames frames_obj = javascript.get_visibility(list(dict.fromkeys(frames))) for frame in frames_obj: offset = frame.get('offset') if offset: visible_frames.append(frame.get('elem')) if visible_frames: logger.debug('Found {} visible frames'.format(len(visible_frames))) return visible_frames
def get_texts(self, locator): """Return texts that are containing locator. Examples -------- .. code-block:: robotframework GetTexts ITEM- Parameters ---------- locator : str Text that we are searching for Returns ------- list : List of found texts """ js = """var web_elements = function(locator){ var matches = []; var text = ""; var elems = document.querySelectorAll('button, a'); for (var i = 0; i < elems.length; i++) { if(elems[i].tagName.toLowerCase() === 'input'){ text = elems[i].value; } else { text = elems[i].innerText; } if (text.trim().includes(locator)){ matches.push(elems[i]); } } return matches; } return(web_elements('""" + locator.replace("\'", "\\'") + """'));""" text_elements = javascript.execute_javascript(js) texts = list() for e in text_elements: texts.append(e.text) self.QWeb.verify_text(e.text) logger.debug('Found texts: {}'.format(texts)) return texts
def _convert_coordinates(self, coordinate_str): """Return row and column from coordinate string.""" try: row = int(re.findall('r([+-]?[0-9]+)', coordinate_str)[0]) if row < 0: row = int(self.get_row('//last', self.anchor)) + (row + 1) except IndexError: row = None try: col = int(re.findall('c([+-]?[0-9]+)', coordinate_str)[0]) if col < 0: row_index = row - 1 col = int( javascript.execute_javascript( ' return arguments[0].rows[{0}].cells.length'.format( row_index), self.table)) + (col + 1) except IndexError: col = None return row, col
def is_checked(checkbox_element): """Is checkbox checked. Parameters ---------- checkbox_element : WebElement Returns ------- bool """ js = """ var checked = function(el) { if (el.hasAttribute("aria-checked")) { return el.attributes["aria-checked"].value; console.log(el.attributes["aria-checked"].value); } return el.checked; } return checked(arguments[0]); """ checked = util.par2bool(javascript.execute_javascript( js, checkbox_element)) return bool(checked)
def is_editable_text_element(input_element): if javascript.execute_javascript( 'return arguments[0].getAttribute("contenteditable") == "true"', input_element): return True return False
def get_parent_element(web_element, tag): web_element = javascript.execute_javascript( 'return arguments[0].closest(\'{}\')'.format(tag), web_element) if web_element: return web_element raise QWebElementNotFoundError('Parent with tag {} not found.'.format(tag))
def get_jquery_ready(): jqueries_ready = javascript.execute_javascript( 'return window.jQuery.active === 0;') return jqueries_ready
def get_ready_state(): ready_state = javascript.execute_javascript( 'return document.readyState === "complete"') logger.debug('Readystate = {}'.format(ready_state)) return ready_state