您的位置:首页 > 其它

splinter webdriver API 的基本实现

2012-08-12 15:52 417 查看
# -*- coding: utf-8 -*-

# Copyright 2012 splinter authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

from __future__ import with_statement
import logging
import subprocess
import time
import re
from contextlib import contextmanager

from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.action_chains import ActionChains

from splinter.driver import DriverAPI, ElementAPI
from splinter.element_list import ElementList
from splinter.utils import warn_deprecated
from tempfile import TemporaryFile

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.extension_connection',
'selenium.webdriver.remote.remote_connection',
'selenium.webdriver.remote.utils',
]

class MutedHandler(logging.Handler):
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

def _unpatch_subprocess(self):
# cleaning up the house
subprocess.Popen = self.old_popen

def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, traceback):
self.quit()

@property
def title(self):
return self.driver.title

@property
def html(self):
return self.driver.page_source

@property
def url(self):
return self.driver.current_url

def visit(self, url):
self.connect(url)
self.ensure_success_response()
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)

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)

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_value(self, value, wait_time=None):
return self.is_element_present(self.find_by_value, value, wait_time)

def is_element_not_present_by_value(self, value, wait_time=None):
return self.is_element_not_present(self.find_by_value, value, 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, original_find="option by value", original_query=value)

def find_option_by_text(self, text):
return self.find_by_xpath('//option[normalize-space(text())="%s"]' % text, original_find="option by text", original_query=text)

def find_link_by_href(self, href):
return self.find_by_xpath('//a[@href="%s"]' % href, original_find="link by href", original_query=href)

def find_link_by_partial_href(self, partial_href):
return self.find_by_xpath('//a[contains(@href, "%s")]' % partial_href, original_find="link by partial href", original_query=partial_href)

def find_link_by_partial_text(self, partial_text):
return self.find_by_xpath('//a[contains(text(), "%s")]' % partial_text, original_find="link by partial text", original_query=partial_text)

def find_link_by_text(self, text):
return self.find_by_xpath('//a[text()="%s"]' % text, original_find="link by text", original_query=text)

def find_by(self, finder, selector, original_find=None, original_query=None):
elements = None
end_time = time.time() + self.wait_time

func_name = finder.im_func.func_name
find_by = original_find or func_name[func_name.rfind('_by_') + 4:]
query = original_query or selector

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], find_by=find_by, query=query)
return ElementList([], find_by=find_by, query=query)

def find_by_css(self, css_selector):
return self.find_by(self.driver.find_elements_by_css_selector, css_selector, original_find='css', original_query=css_selector)

def find_by_xpath(self, xpath, original_find=None, original_query=None):
original_find = original_find or "xpath"
original_query = original_query or xpath
return self.find_by(self.driver.find_elements_by_xpath, xpath, original_find=original_find, original_query=original_query)

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_value(self, value):
return self.find_by_xpath('//*[@value="%s"]' % value, original_find='value', original_query=value)

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

attach_file = fill

def fill_form(self, field_values):
for name, value in field_values.items():
elements = self.find_by_name(name)
element = elements.first
if element['type'] == 'text' or element.tag_name == 'textarea':
element.value = value
elif element['type'] == 'checkbox':
if value:
element.check()
else:
element.uncheck()
elif element['type'] == 'radio':
for field in elements:
if field.value == value:
field.click()
elif element._element.tag_name == 'select':
element.find_by_value(value).first._element.click()

def type(self, name, value, slowly=False):
element = self.driver.find_element_by_css_selector('input[name="%s"]' % name)
if slowly:
return TypeIterator(element, value)
element.send_keys(value)
return value

def choose(self, name, value):
fields = self.find_by_name(name)
for field in fields:
if field.value == value:
field.click()

def check(self, name):
self.find_by_name(name).first.check()

def uncheck(self, name):
self.find_by_name(name).first.uncheck()

def select(self, name, value):
self.find_by_xpath('//select[@name="%s"]/option[@value="%s"]' % (name, value)).first._element.click()

def quit(self):
self.driver.quit()

@property
def cookies(self):
return self._cookie_manager

class TypeIterator(object):

def __init__(self, element, keys):
self._element = element
self._keys = keys

def __iter__(self):
for key in self._keys:
self._element.send_keys(key)
yield key

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 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 has_class(self, class_name):
element_class_name = self._element.get_attribute('class')
return bool(re.search(r'(?:^|\s)' + re.escape(class_name) + r'(?:$|\s)', element_class_name))

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 AlertElement(object):

def __init__(self, alert):
self._alert = alert
self.text = alert.text

def accept(self):
self._alert.accept()

def dismiss(self):
self._alert.dismiss()

def fill_with(self, text):
self._alert.send_keys(text)

def __enter__(self):
return self

def __exit__(self, type, value, traceback):
pass
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: