class WebDriverElement(ElementAPI): def __init__(self, element, parent): self._element = element self.parent = parent self.action_chains = ActionChains(parent.driver) def _get_value(self): value = self["value"] if value: return value else: return self._element.text def _set_value(self, value): if self._element.get_attribute('type') != 'file': self._element.clear() self._element.send_keys(value) value = property(_get_value, _set_value) @property def text(self): return self._element.text @property def tag_name(self): return self._element.tag_name def fill(self, value): self.value = value def type(self, value, slowly=False): if slowly: return TypeIterator(self._element, value) self._element.send_keys(value) return value def click(self): self._element.click() def check(self): if not self.checked: self._element.click() def uncheck(self): if self.checked: self._element.click() @property def checked(self): return self._element.is_selected() selected = checked @property def visible(self): return self._element.is_displayed() def find_by_css(self, selector, original_find=None, original_query=None): find_by = original_find or 'css' query = original_query or selector elements = self._element.find_elements_by_css_selector(selector) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by=find_by, query=query) def find_by_xpath(self, selector): elements = ElementList(self._element.find_elements_by_xpath(selector)) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by='xpath', query=selector) def find_by_name(self, name): elements = ElementList(self._element.find_elements_by_name(name)) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by='name', query=name) def find_by_tag(self, tag): elements = ElementList(self._element.find_elements_by_tag_name(tag)) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by='tag', query=tag) def find_by_value(self, value): selector = '[value="%s"]' % value return self.find_by_css(selector, original_find='value', original_query=value) def find_by_id(self, id): elements = ElementList(self._element.find_elements_by_id(id)) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by='id', query=id) def mouse_over(self): """ Performs a mouse over the element. Currently works only on Chrome driver. """ self.action_chains.move_to_element(self._element) self.action_chains.perform() def mouse_out(self): """ Performs a mouse out the element. Currently works only on Chrome driver. """ self.action_chains.move_by_offset(5000, 5000) self.action_chains.perform() mouseover = warn_deprecated(mouse_over, 'mouseover') mouseout = warn_deprecated(mouse_out, 'mouseout') def double_click(self): """ Performs a double click in the element. Currently works only on Chrome driver. """ self.action_chains.double_click(self._element) self.action_chains.perform() def right_click(self): """ Performs a right click in the element. Currently works only on Chrome driver. """ self.action_chains.context_click(self._element) self.action_chains.perform() def drag_and_drop(self, droppable): """ Performs drag a element to another elmenet. Currently works only on Chrome driver. """ self.action_chains.drag_and_drop(self._element, droppable._element) self.action_chains.perform() def __getitem__(self, attr): return self._element.get_attribute(attr)
class WebDriverElement(ElementAPI): def __init__(self, element, parent): self._element = element self.parent = parent self.action_chains = ActionChains(parent.driver) def _get_value(self): return self['value'] or self._element.text def _set_value(self, value): if self._element.get_attribute('type') != 'file': self._element.clear() self._element.send_keys(value) value = property(_get_value, _set_value) @property def text(self): return self._element.text @property def tag_name(self): return self._element.tag_name def clear(self): if self._element.get_attribute('type') in [ 'textarea', 'text', 'password', 'tel' ]: self._element.clear() def fill(self, value): self.value = value def select(self, value): self.find_by_xpath('//select[@name="%s"]/option[@value="%s"]' % (self["name"], value))._element.click() def select_by_text(self, text): self.find_by_xpath('//select[@name="%s"]/option[text()="%s"]' % (self["name"], text))._element.click() def type(self, value, slowly=False): if slowly: return TypeIterator(self._element, value) self._element.send_keys(value) return value def click(self): self._element.click() def check(self): if not self.checked: self._element.click() def uncheck(self): if self.checked: self._element.click() @property def checked(self): return self._element.is_selected() selected = checked @property def visible(self): return self._element.is_displayed() @property def html(self): return self['innerHTML'] @property def outer_html(self): return self['outerHTML'] def find_by_css(self, selector, original_find=None, original_query=None): find_by = original_find or 'css' query = original_query or selector elements = self._element.find_elements_by_css_selector(selector) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by=find_by, query=query) def find_by_xpath(self, selector, original_find=None, original_query=None): elements = ElementList(self._element.find_elements_by_xpath(selector)) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by='xpath', query=selector) def find_by_name(self, name): elements = ElementList(self._element.find_elements_by_name(name)) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by='name', query=name) def find_by_tag(self, tag): elements = ElementList(self._element.find_elements_by_tag_name(tag)) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by='tag', query=tag) def find_by_value(self, value): selector = '[value="%s"]' % value return self.find_by_css(selector, original_find='value', original_query=value) def find_by_text(self, text): selector = '//*[text()="%s"]' % text return self.find_by_xpath(selector, original_find='text', original_query=text) def find_by_id(self, id): elements = ElementList(self._element.find_elements_by_id(id)) return ElementList( [self.__class__(element, self.parent) for element in elements], find_by='id', query=id) def has_class(self, class_name): return bool( re.search(r'(?:^|\s)' + re.escape(class_name) + r'(?:$|\s)', self['class'])) def mouse_over(self): """ Performs a mouse over the element. Currently works only on Chrome driver. """ self.action_chains.move_to_element(self._element) self.action_chains.perform() def mouse_out(self): """ Performs a mouse out the element. Currently works only on Chrome driver. """ self.action_chains.move_by_offset(5000, 5000) self.action_chains.perform() mouseover = warn_deprecated(mouse_over, 'mouseover') def double_click(self): """ Performs a double click in the element. Currently works only on Chrome driver. """ self.action_chains.double_click(self._element) self.action_chains.perform() def right_click(self): """ Performs a right click in the element. Currently works only on Chrome driver. """ self.action_chains.context_click(self._element) self.action_chains.perform() def drag_and_drop(self, droppable): """ Performs drag a element to another elmenet. Currently works only on Chrome driver. """ self.action_chains.drag_and_drop(self._element, droppable._element) self.action_chains.perform() def __getitem__(self, attr): return self._element.get_attribute(attr)
class BaseWebDriver(DriverAPI): old_popen = subprocess.Popen def __init__(self, wait_time=2): self.wait_time = wait_time def _patch_subprocess(self): loggers_to_silence = [ 'selenium.webdriver.firefox.utils', 'selenium.webdriver.firefox.firefoxlauncher', 'selenium.webdriver.firefox.firefox_profile', 'selenium.webdriver.remote.utils', 'selenium.webdriver.remote.remote_connection', 'addons.xpi', 'webdriver.ExtensionConnection', ] class MutedHandler(logging.Handler): def emit(self, record): pass for name in loggers_to_silence: logger = logging.getLogger(name) logger.addHandler(MutedHandler()) logger.setLevel(99999) # selenium is such a verbose guy let's make it open the # browser without showing all the meaningless output def MyPopen(*args, **kw): kw['stdout'] = TemporaryFile() kw['stderr'] = TemporaryFile() kw['close_fds'] = True return self.old_popen(*args, **kw) subprocess.Popen = MyPopen # also patching firefox profile in order to NOT produce output firefox_profile.FirefoxProfile. \ DEFAULT_PREFERENCES['extensions.logging.enabled'] = "false" def _unpatch_subprocess(self): # cleaning up the house subprocess.Popen = self.old_popen @property def title(self): return self.driver.title @property def html(self): return self.driver.get_page_source() @property def url(self): return self.driver.current_url def visit(self, url): self.driver.get(url) def back(self): self.driver.back() def forward(self): self.driver.forward() def reload(self): self.driver.refresh() def execute_script(self, script): self.driver.execute_script(script) def evaluate_script(self, script): return self.driver.execute_script("return %s" % script) def is_element_present(self, finder, selector, wait_time=None): wait_time = wait_time or self.wait_time end_time = time.time() + wait_time while time.time() < end_time: if finder(selector): return True return False def is_element_not_present(self, finder, selector, wait_time=None): wait_time = wait_time or self.wait_time end_time = time.time() + wait_time while time.time() < end_time: if not finder(selector): return True return False def is_element_present_by_css(self, css_selector, wait_time=None): return self.is_element_present(self.find_by_css, css_selector, wait_time) is_element_present_by_css_selector = warn_deprecated( is_element_present_by_css, 'is_element_present_by_css_selector') def is_element_not_present_by_css(self, css_selector, wait_time=None): return self.is_element_not_present(self.find_by_css, css_selector, wait_time) is_element_not_present_by_css_selector = warn_deprecated( is_element_not_present_by_css, 'is_element_not_present_by_css_selector') def is_element_present_by_xpath(self, xpath, wait_time=None): return self.is_element_present(self.find_by_xpath, xpath, wait_time) def is_element_not_present_by_xpath(self, xpath, wait_time=None): return self.is_element_not_present(self.find_by_xpath, xpath, wait_time) def is_element_present_by_tag(self, tag, wait_time=None): return self.is_element_present(self.find_by_tag, tag, wait_time) def is_element_not_present_by_tag(self, tag, wait_time=None): return self.is_element_not_present(self.find_by_tag, tag, wait_time) def is_element_present_by_name(self, name, wait_time=None): return self.is_element_present(self.find_by_name, name, wait_time) def is_element_not_present_by_name(self, name, wait_time=None): return self.is_element_not_present(self.find_by_name, name, wait_time) def is_element_present_by_id(self, id, wait_time=None): return self.is_element_present(self.find_by_id, id, wait_time) def is_element_not_present_by_id(self, id, wait_time=None): return self.is_element_not_present(self.find_by_id, id, wait_time) def get_alert(self): return AlertElement(self.driver.switch_to_alert()) def is_text_present(self, text, wait_time=None): wait_time = wait_time or self.wait_time end_time = time.time() + wait_time while time.time() < end_time: try: self.driver.find_element_by_tag_name('body').text.index(text) return True except ValueError: pass return False def is_text_not_present(self, text, wait_time=None): wait_time = wait_time or self.wait_time end_time = time.time() + wait_time while time.time() < end_time: try: self.driver.find_element_by_tag_name('body').text.index(text) except ValueError: return True return False @contextmanager def get_iframe(self, id): self.driver.switch_to_frame(id) try: yield self finally: self.driver.switch_to_frame(None) def find_option_by_value(self, value): return self.find_by_xpath('//option[@value="%s"]' % value) def find_option_by_text(self, text): return self.find_by_xpath('//option[normalize-space(text())="%s"]' % text) def find_link_by_href(self, href): return self.find_by_xpath('//a[@href="%s"]' % href) def find_link_by_text(self, text): return ElementList([ self.element_class(element, self) for element in self.driver.find_elements_by_link_text(text) ]) def find_by(self, finder, selector): elements = None end_time = time.time() + self.wait_time while time.time() < end_time: try: elements = finder(selector) if not isinstance(elements, list): elements = [elements] except NoSuchElementException: pass if elements: return ElementList([ self.element_class(element, self) for element in elements ]) return ElementList([]) def find_by_css(self, css_selector): selector = CSSSelector(css_selector) return self.find_by(self.driver.find_elements_by_xpath, selector.path) find_by_css_selector = warn_deprecated(find_by_css, 'find_by_css_selector') def find_by_xpath(self, xpath): return self.find_by(self.driver.find_elements_by_xpath, xpath) def find_by_name(self, name): return self.find_by(self.driver.find_elements_by_name, name) def find_by_tag(self, tag): return self.find_by(self.driver.find_elements_by_tag_name, tag) def find_by_id(self, id): return self.find_by(self.driver.find_element_by_id, id) def fill(self, name, value): field = self.find_by_name(name).first field.value = value fill_in = warn_deprecated(fill, 'fill_in') attach_file = fill def choose(self, name): field = self.find_by_name(name).first field.click() def check(self, name): field = self.find_by_name(name).first field.check() def uncheck(self, name): field = self.find_by_name(name).first field.uncheck() def select(self, name, value): self.find_by_xpath('//select[@name="%s"]/option[@value="%s"]' % (name, value)).first._element.select() def quit(self): self.driver.quit()
class ZopeTestBrowser(DriverAPI): def __init__(self): self._browser = Browser() self._last_urls = [] def visit(self, url): self._browser.open(url) def back(self): self._last_urls.insert(0, self.url) self._browser.goBack() def forward(self): try: self.visit(self._last_urls.pop()) except IndexError: pass def reload(self): self._browser.reload() def quit(self): pass @property def title(self): return self._browser.title @property def html(self): return self._browser.contents @property def url(self): return self._browser.url def find_option_by_value(self, value): html = lxml.html.fromstring(self.html) element = html.xpath('//option[@value="%s"]' % value)[0] control = self._browser.getControl(element.text) return ElementList([ZopeTestBrowserOptionElement(control, self)]) def find_option_by_text(self, text): html = lxml.html.fromstring(self.html) element = html.xpath('//option[normalize-space(text())="%s"]' % text)[0] control = self._browser.getControl(element.text) return ElementList([ZopeTestBrowserOptionElement(control, self)]) def find_by_css(self, selector): xpath = CSSSelector(selector).path return self.find_by_xpath(xpath) find_by_css_selector = warn_deprecated(find_by_css, 'find_by_css_selector') def find_by_xpath(self, xpath): html = lxml.html.fromstring(self.html) elements = [] for xpath_element in html.xpath(xpath): if self._element_is_link(xpath_element): return self.find_link_by_text(xpath_element.text) elif self._element_is_control(xpath_element): return self.find_by_name(xpath_element.name) else: elements.append(xpath_element) return ElementList( [ZopeTestBrowserElement(element, self) for element in elements]) def find_by_tag(self, tag): return self.find_by_xpath('//%s' % tag) def find_by_id(self, id_value): return self.find_by_xpath('//*[@id="%s"][1]' % id_value) def find_by_name(self, name): elements = [] index = 0 while True: try: control = self._browser.getControl(name=name, index=index) elements.append(control) index += 1 except IndexError: break return ElementList([ ZopeTestBrowserControlElement(element, self) for element in elements ]) def find_link_by_text(self, text): return self._find_links_by_xpath("//a[text()='%s']" % text) def find_link_by_href(self, href): return self._find_links_by_xpath("//a[@href='%s']" % href) def fill(self, name, value): self.find_by_name(name=name).first._control.value = value fill_in = warn_deprecated(fill, 'fill_in') def choose(self, name): control = self._browser.getControl(name=name) control.value = control.options check = choose def uncheck(self, name): control = self._browser.getControl(name=name) control.value = [] def attach_file(self, name, file_path): control = self._browser.getControl(name=name) content_type, _ = mimetypes.guess_type(file_path) control.add_file(open(file_path), content_type, None) def _find_links_by_xpath(self, xpath): html = lxml.html.fromstring(self.html) links = html.xpath(xpath) return ElementList( [ZopeTestBrowserLinkElement(link, self) for link in links]) def select(self, name, value): self.find_by_name(name).first._control.value = [ value, ] def _element_is_link(self, element): return element.tag == 'a' def _element_is_control(self, element): return hasattr(element, 'type')