Source code for nerodia.browser

from importlib import import_module

import six
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support.event_firing_webdriver import EventFiringWebDriver

import nerodia
from nerodia.elements.scroll import Scrolling
from . import locators
from .after_hooks import AfterHooks
from .alert import Alert
from .capabilities import Capabilities
from .container import Container
from .cookies import Cookies
from .exception import Error
from .has_window import HasWindow
from .wait.timer import Timer
from .wait.wait import Waitable

try:
    from urlparse import urlparse
except ImportError:
    from urllib.parse import urlparse


[docs]class Browser(Container, HasWindow, Waitable, Scrolling): def __init__(self, browser='chrome', *args, **kwargs): """ Creates a nerodia.browser.Browser instance :param browser: firefox, ie, chrome, remote or Selenium WebDriver instance :type browser: selenium.webdriver.remote.webdriver.WebDriver or str :param args: args passed to the underlying driver :param kwargs: kwargs passed to the underlying driver """ if isinstance(browser, six.string_types[0]): caps = Capabilities(browser, **kwargs) module = import_module('selenium.webdriver.{}' '.webdriver'.format(caps.selenium_browser.lower())) self.driver = module.WebDriver(**caps.kwargs) elif isinstance(browser, WebDriver): self.driver = browser else: raise TypeError('A browser name or WebDriver instance must be supplied, ' 'got {}'.format(type(browser))) if 'listener' in kwargs: self.driver = EventFiringWebDriver(self.driver, kwargs.get('listener')) self.after_hooks = AfterHooks(self) self.current_frame = None self.closed = False self.default_context = True self._original_window = None self._locator_namespace = locators self._timer = Timer() @property def locator_namespace(self): """ Whether the locators should be used from a different namespace. Defaults to nerodia.locators :return: """ return self._locator_namespace @locator_namespace.setter def locator_namespace(self, namespace): self._locator_namespace = namespace @property def timer(self): return self._timer @timer.setter def timer(self, timer): self._timer = timer @property def wd(self): return self.driver
[docs] @staticmethod def start(url, browser='chrome', *args, **kwargs): """ Creates a Browser instance :param url: url to navigate to after starting browser :type url: str :param browser: firefox, ie, chrome, remote or Selenium WebDriver instance :type browser: selenium.webdriver.remote.webdriver.WebDriver or str :param args: args passed to the underlying driver :param kwargs: kwargs passed to the underlying driver """ b = Browser(browser, *args, **kwargs) b.goto(url) return b
def __repr__(self): try: if self.alert.exists: return '#<{}:0x{:x} alert=True>'.format(self.__class__.__name__, self.__hash__() * 2) else: return '#<{}:0x{:x} url={!r} title={!r}>'.format(self.__class__.__name__, self.__hash__() * 2, self.url, self.title) except: # noqa return '#<{}:0x{:x} closed={}>'.format(self.__class__.__name__, self.__hash__() * 2, self.closed) selector_string = __repr__
[docs] def goto(self, uri): """ Goes to the given URL :param uri: the URL :type uri: str :return: the url you end up at :rtype: str """ scheme = urlparse(uri).scheme if scheme == '' or '.' in scheme: uri = 'http://{}'.format(uri) self.driver.get(uri) self.after_hooks.run() return uri
[docs] def back(self): """ Navigates back in history """ self.driver.back() self.after_hooks.run()
[docs] def forward(self): """ Navigates forward in history """ self.driver.forward() self.after_hooks.run()
@property def url(self): """ Returns the URL of the current page :rtype: str """ return self.driver.current_url @property def title(self): """ Returns the title of the current page :rtype: str """ return self.driver.title
[docs] def close(self): """ Closes the browser """ if not self.closed: self.driver.quit() self.closed = True
quit = close @property def cookies(self): """ Handles cookies :rtype: nerodia.cookies.Cookies """ return Cookies(self.driver) @property def name(self): """ Returns the browser name :rtype: str """ return self.driver.name @property def text(self): """ Returns the text of the page body :return: """ return self.body().text @property def html(self): """ Returns HTML code of the current page :rtype: str """ return self.driver.page_source @property def alert(self): """ Handles Javascript alerts, confirms and prompts :rtype: nerodia.alert.Alert """ return Alert(self)
[docs] def refresh(self): """ Refreshes the current page """ self.driver.refresh() self.after_hooks.run()
[docs] def wait(self, timeout=5): """ Waits until the readyState of document is complete, raises a TimeoutException if timeout is exceeded :param timeout: time to wait :type timeout: int """ return self.wait_until(lambda b: b.ready_state == "complete", timeout=timeout, message="waiting for document.readyState == 'complete'")
@property def ready_state(self): """ Returns the readyState of the document :rtype: str """ return self.execute_script('return document.readyState;') @property def status(self): """ Returns the text of the status bar :return: """ return self.execute_script('return window.status;')
[docs] def execute_script(self, script, *args): """ Executes JavaScript snippet :param script: Javascript Snippet to execute :type script: str :param args: Arguments will be available in the given script in the 'arguments' pseudo-array :return: result of script """ from .elements.element import Element args = [e.wait_until(lambda x: x.exists).wd if isinstance(e, Element) else e for e in args] returned = self.driver.execute_script(script, *args) return self._wrap_elements_in(self, returned)
[docs] def send_keys(self, *args): """ Sends sequence of keystrokes to currently active element :param args: keystrokes """ self.driver.switch_to.active_element.send_keys(*args)
@property def screenshot(self): """ Handles screenshots of current pages :rtype: nerodia.screenshot.Screenshot """ from .screenshot import Screenshot return Screenshot(self) @property def exist(self): """ True if browser is not closed and False otherwise :rtype: bool """ return not self.closed and self.window().present exists = exist @property def browser(self): return self
[docs] def locate(self): if self.closed: raise Error('browser was closed') self._ensure_context()
# private def _ensure_context(self): if self.default_context: return self.driver.switch_to.default_content() self.default_context = True self.after_hooks.run() @staticmethod def _wrap_elements_in(scope, obj): if isinstance(obj, WebElement): return Browser._wrap_element(scope, obj) elif isinstance(obj, list): return [Browser._wrap_elements_in(scope, e) for e in obj] elif isinstance(obj, dict): for k, v in obj.items(): obj[k] = Browser._wrap_elements_in(scope, v) return obj else: return obj @staticmethod def _wrap_element(scope, element): from .elements.html_elements import HTMLElement klass = nerodia.element_class_for(element.tag_name.lower()) or HTMLElement return klass(scope, {'element': element})