Compare commits
49
Commits
javascript
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97635dbe40 | ||
|
|
04cadf52bb | ||
|
|
70750c9d79 | ||
|
|
8988dc48ba | ||
|
|
63bb5264cd | ||
|
|
f02cd75c94 | ||
|
|
5a5c27a19e | ||
|
|
c84eaaeef0 | ||
|
|
ab334f1f63 | ||
|
|
fcedd5ade4 | ||
|
|
6dc1990728 | ||
|
|
4c0e888986 | ||
|
|
26320ea0d6 | ||
|
|
4a6671964c | ||
|
|
510b2c4e94 | ||
|
|
2b369072a4 | ||
|
|
ed5b29f280 | ||
|
|
6218d1865e | ||
|
|
bc6dcaa4ed | ||
|
|
68c2429616 | ||
|
|
1dc40f610c | ||
|
|
bbe21ab410 | ||
|
|
c114785723 | ||
|
|
c55de045c0 | ||
|
|
b594988524 | ||
|
|
e812fb1f12 | ||
|
|
d1566409e3 | ||
|
|
e3c6b32a6b | ||
|
|
1bb4dd1d98 | ||
|
|
3945c17147 | ||
|
|
14d1dc202a | ||
|
|
5d2c28d1ee | ||
|
|
66f1efb313 | ||
|
|
2a1c7403f0 | ||
|
|
f6e8b40b29 | ||
|
|
cc33da521e | ||
|
|
8a51b48946 | ||
|
|
ce9da9cdcf | ||
|
|
ddaf7441cc | ||
|
|
a5f64e9abc | ||
|
|
38ebf2613b | ||
|
|
394f096dab | ||
|
|
3707d9f0bf | ||
|
|
433b8db2d4 | ||
|
|
1339b9c95d | ||
|
|
f6a3e91c3f | ||
|
|
4997a316c1 | ||
|
|
a9ce4718c2 | ||
|
|
ad17ce2f4b |
@@ -7,3 +7,4 @@ build/
|
||||
dist/
|
||||
*.egg-info
|
||||
.idea
|
||||
.tox
|
||||
+24
-5
@@ -1,9 +1,28 @@
|
||||
language: python
|
||||
python:
|
||||
- "2.6"
|
||||
- "2.7"
|
||||
- '2.6'
|
||||
- '2.7'
|
||||
- '3.2'
|
||||
- '3.3'
|
||||
- '3.4'
|
||||
install:
|
||||
- pip install -r requirements.txt --use-mirrors
|
||||
- pip install -e . --use-mirrors
|
||||
- pip install -r requirements.txt --use-mirrors
|
||||
- pip install -e . --use-mirrors
|
||||
script:
|
||||
- nosetests
|
||||
- python setup.py test
|
||||
deploy:
|
||||
provider: pypi
|
||||
user: Keita
|
||||
password:
|
||||
secure: d5aCVLkhV/uh+/Mr/c398KmA3DVgx6TAO9HYAsDiLbzh1JQO4jsOEQ4TSrosFV2dlolDuLaXu6tHzzeoUKg8BO2wF9pTwbhoo21+Xr5CHd3bAx4WTPvC8POEByVur8sJC1lD45VR0A2sPJMppi9778dgIZpvowE8sANlvv3iztU=
|
||||
on:
|
||||
repo: keitaoouchi/seleniumwrapper
|
||||
branch: release/pypi
|
||||
distributions: sdist --formats=gztar,zip
|
||||
python: 3.4
|
||||
allow_failure: false
|
||||
notifications:
|
||||
slack:
|
||||
secure: mRFzPF4qQzRfHCS9rYEKpUI9w5wvyv4AO8AVuzvwU1rExKokdl6jcxsMEYlOvozqztfjY7YSN3hm/KV60UiPBtbuox54GrvkCu/qqfx6tFRc1aS+5JclGvOGrrRyzodCIDJEuayiZIrzUSMwcwRInd+N1atpJUKoa9AgyVn+e0o=
|
||||
on_success: change
|
||||
on_failure: change
|
||||
|
||||
+54
-37
@@ -3,10 +3,23 @@ About this module
|
||||
selenium webdriver wrapper to make manipulation easier.
|
||||
|
||||
.. image:: https://secure.travis-ci.org/keitaoouchi/seleniumwrapper.png
|
||||
.. image:: https://img.shields.io/pypi/dm/seleniumwrapper.svg
|
||||
:target: https://pypi.python.org/pypi//seleniumwrapper/
|
||||
:alt: Downloads
|
||||
.. image:: https://img.shields.io/pypi/v/seleniumwrapper.svg
|
||||
:target: https://pypi.python.org/pypi/seleniumwrapper/
|
||||
:alt: Latest Version
|
||||
.. image:: https://img.shields.io/pypi/pyversions/seleniumwrapper.svg
|
||||
:target: https://pypi.python.org/pypi/seleniumwrapper/
|
||||
:alt: Supported Python versions
|
||||
.. image:: https://img.shields.io/pypi/l/seleniumwrapper.svg
|
||||
:target: https://pypi.python.org/pypi/seleniumwrapper/
|
||||
:alt: License
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
* Support Internet Explorer, Chrome, Opera, Firefox, PhantomJS
|
||||
* Support remote webdriver.
|
||||
* Easy to type aliases. (find_element_by_xpath => xpath, etc.)
|
||||
* Wrapped WebdriverWait( ... ).until( ... ) pattern.
|
||||
@@ -15,7 +28,7 @@ Features
|
||||
|
||||
How to install
|
||||
--------------
|
||||
Requires python2.6 or later (exclude python3.x).
|
||||
Requires python2.6 or later.
|
||||
You need *pip* or *distribute* or *setuptools*::
|
||||
|
||||
$ pip install seleniumwrapper
|
||||
@@ -60,25 +73,10 @@ Each contents in SeleniumContainerWrapper also SeleniumWrapper::
|
||||
|
||||
>>> tds = [tr.xpath("//td", eager=True) for tr in br.xpath("//tr", eager=True)]
|
||||
|
||||
If current page already load jquery.js, you can find elements by JQuery selector::
|
||||
|
||||
>>> buttons = br.jquery('#hoge .fuga li:even')
|
||||
|
||||
If current page doesn't load jquery, you can load your local jquery by hand::
|
||||
|
||||
>>> br.load_js("/path/to/your/local/jquery.js")
|
||||
|
||||
or::
|
||||
|
||||
>>> br.load_js(StringIO.StringIO("/path/to/your/local/jquery.js")
|
||||
|
||||
You can execute javascript by invoking **script** method::
|
||||
|
||||
>>> br.script('alert("hoge")')
|
||||
|
||||
Basic API
|
||||
---------
|
||||
* seleniumwrapper.create(drivername)
|
||||
* seleniumwrapper.connect(drivername, executor, custom_capabilities)
|
||||
Create webdriver instance and wrap it with SeleniumWrapper.
|
||||
|
||||
SeleniumWrapper
|
||||
@@ -94,6 +92,15 @@ SeleniumWrapper
|
||||
|
||||
>>> price = br.by_tag("th", "Price").parent.by_tag("td").text
|
||||
|
||||
* performance
|
||||
Returns window.performance wrapped object::
|
||||
|
||||
>>> performance = br.performance
|
||||
>>> timing = performance.timing
|
||||
>>> navigation = performance.navigation
|
||||
>>> timing.loadEventEnd
|
||||
1358319427476
|
||||
|
||||
* to_select
|
||||
Convert wrapped WebElement to raw Select object::
|
||||
|
||||
@@ -101,7 +108,7 @@ SeleniumWrapper
|
||||
|
||||
select method returns the same as below::
|
||||
|
||||
>>> br.select(id = 'select_button).select_by_visible_text("hoge")
|
||||
>>> br.select(id = 'select_button').select_by_visible_text("hoge")
|
||||
|
||||
* alert
|
||||
Returns Alert(switch_to_alert()) object::
|
||||
@@ -114,7 +121,7 @@ SeleniumWrapper
|
||||
>>> br.current_url
|
||||
|
||||
* timeout
|
||||
Accessor for _timeout property.
|
||||
Accessor for _timeout property::
|
||||
|
||||
>>> br.timeout
|
||||
5
|
||||
@@ -122,6 +129,18 @@ SeleniumWrapper
|
||||
>>> br.timeout
|
||||
10
|
||||
|
||||
* silent
|
||||
Accessor for _silent property::
|
||||
|
||||
# default
|
||||
>>> br.by_id("Hoge")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
NoSuchElementException:...
|
||||
>>> br.silent = True
|
||||
>>> br.by_id("Hoge") is None
|
||||
True
|
||||
|
||||
* attr(name)
|
||||
Shortcut to get_attribute::
|
||||
|
||||
@@ -132,21 +151,6 @@ SeleniumWrapper
|
||||
|
||||
>>> br.button("Send").click()
|
||||
|
||||
* load_js(path_or_file)
|
||||
Load javascript from /path/to/file or file like object that responds to 'read' method::
|
||||
|
||||
>>> br.load_js("/path/to/jquery.js")
|
||||
|
||||
* jquery(target)
|
||||
Find elements by jquery selector::
|
||||
|
||||
>>> br.jquery('#hoge .fuga li:even')
|
||||
|
||||
* script(javascript)
|
||||
Execute given javascript::
|
||||
|
||||
>>> br.script('alert("hoge")')
|
||||
|
||||
* scroll_to(x, y)
|
||||
equivalent to javascript's scrollTo::
|
||||
|
||||
@@ -223,7 +227,7 @@ SeleniumWrapper
|
||||
>>> br.img(alt="I am sorry", ext="sorry.gif")
|
||||
|
||||
* button(value, eager=False, timeout=3)
|
||||
find_element_by_xpath("//input[@type='submit' or @type='button' and @value='{}']".format(value), timeout)::
|
||||
find_element_by_xpath("//input[@type='submit' or @type='button' and @value='{0}']|.//button[text()='{0}']".format(value), timeout)::
|
||||
|
||||
>>> br.button("Send this form").click()
|
||||
|
||||
@@ -263,10 +267,23 @@ SeleniumContainerWrapper
|
||||
|
||||
Recent Change
|
||||
-------------
|
||||
* 0.5.4
|
||||
* Add support for Python-3.4.
|
||||
* Fix **button** to look for `<button>` tag.
|
||||
* 0.5.3
|
||||
* Fix README
|
||||
* 0.5.2
|
||||
* Add silent mode option.
|
||||
* 0.5.0
|
||||
* Support Python3.
|
||||
* 0.4.3
|
||||
* Add **perfomance**, **performance.timing**, **performance.navigation**, **performance.memory** properties.
|
||||
* 0.4.2
|
||||
* Add 'PhantomJS' support.
|
||||
* 0.4.1
|
||||
* Fixed some bugs.
|
||||
* 0.4.0
|
||||
* Added **scroll_to**, **scroll_by**, **scroll_into_view** methods.
|
||||
* Added **jquery** method to support jquery selecter.
|
||||
* Added **load_js**, **script** methods.
|
||||
* 0.3.5
|
||||
* Added **attr** method.
|
||||
* Fixed some typos.
|
||||
|
||||
+1
-3
@@ -1,3 +1 @@
|
||||
nose
|
||||
unittest2
|
||||
mock
|
||||
selenium>=2.32.0
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from setuptools import setup
|
||||
|
||||
from sys import version
|
||||
|
||||
if version < '2.6.0':
|
||||
raise Exception("This module doesn't support any version less than 2.6")
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append("./test")
|
||||
|
||||
with open('README.rst', 'r') as f:
|
||||
@@ -17,25 +19,34 @@ classifiers = [
|
||||
'Operating System :: OS Independent',
|
||||
"Programming Language :: Python",
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 2.6',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.2',
|
||||
'Programming Language :: Python :: 3.3',
|
||||
'Programming Language :: Python :: 3.4',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules'
|
||||
]
|
||||
|
||||
requires = ['selenium>=2.25.0']
|
||||
requires = ['selenium>=2.44.0']
|
||||
tests_requires = ['mock', 'nose']
|
||||
|
||||
if version < '2.7.0':
|
||||
tests_requires.append('unittest2')
|
||||
|
||||
setup(
|
||||
author='Keita Oouchi',
|
||||
author_email='keita.oouchi@gmail.com',
|
||||
url = 'https://github.com/keitaoouchi/seleniumwrapper',
|
||||
name = 'seleniumwrapper',
|
||||
version = '0.4.0',
|
||||
package_dir={"":"src"},
|
||||
packages = ['seleniumwrapper'],
|
||||
test_suite = "test_seleniumwrapper.suite",
|
||||
url='https://github.com/keitaoouchi/seleniumwrapper',
|
||||
name='seleniumwrapper',
|
||||
version='0.5.4',
|
||||
package_dir={"": "src"},
|
||||
packages=['seleniumwrapper'],
|
||||
license='BSD License',
|
||||
classifiers=classifiers,
|
||||
description = 'selenium webdriver wrapper to make manipulation easier.',
|
||||
description='selenium webdriver wrapper to make manipulation easier.',
|
||||
long_description=long_description,
|
||||
install_requires=requires,
|
||||
tests_require=tests_requires,
|
||||
test_suite='test'
|
||||
)
|
||||
|
||||
+134
-63
@@ -1,12 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os
|
||||
import collections
|
||||
import inspect
|
||||
import time
|
||||
import random
|
||||
import selenium
|
||||
from selenium.webdriver import Ie, Opera, Chrome, Firefox
|
||||
from selenium.webdriver import Ie, Opera, Chrome, Firefox, PhantomJS
|
||||
from selenium.webdriver.remote.webdriver import WebDriver
|
||||
from selenium.webdriver.remote.webelement import WebElement
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
@@ -16,6 +15,7 @@ from selenium.common.exceptions import (NoSuchElementException, TimeoutException
|
||||
NoAlertPresentException)
|
||||
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
|
||||
|
||||
|
||||
def create(drivername, *args, **kwargs):
|
||||
if not isinstance(drivername, str):
|
||||
msg = "drivername should be an instance of string. given {0}".format(type(drivername))
|
||||
@@ -23,7 +23,8 @@ def create(drivername, *args, **kwargs):
|
||||
drivers = {'ie': Ie,
|
||||
'opera': Opera,
|
||||
'chrome': Chrome,
|
||||
'firefox': Firefox}
|
||||
'firefox': Firefox,
|
||||
'phantomjs': PhantomJS}
|
||||
dname = drivername.lower()
|
||||
if dname in drivers:
|
||||
try:
|
||||
@@ -31,7 +32,8 @@ def create(drivername, *args, **kwargs):
|
||||
except Exception as e:
|
||||
raise e
|
||||
else:
|
||||
msg = "drivername should be one of [IE, Opera, Chrome, Firefox](case-insentive). given {0}".format(drivername)
|
||||
msg = "".join(("drivername should be one of [IE, Opera, Chrome, Firefox, PhantomJS]",
|
||||
"(case-insentive). given {0}".format(drivername)))
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@@ -49,7 +51,8 @@ def connect(drivername, executor, custom_capabilities=None, **kwargs):
|
||||
'opera': DesiredCapabilities.OPERA,
|
||||
'chrome': DesiredCapabilities.CHROME,
|
||||
'firefox': DesiredCapabilities.FIREFOX,
|
||||
'android': DesiredCapabilities.ANDROID}
|
||||
'android': DesiredCapabilities.ANDROID,
|
||||
'phatomjs': DesiredCapabilities.PHANTOMJS}
|
||||
dname = drivername.lower()
|
||||
if dname in capabilities:
|
||||
capability = capabilities[dname]
|
||||
@@ -62,7 +65,8 @@ def connect(drivername, executor, custom_capabilities=None, **kwargs):
|
||||
except Exception as e:
|
||||
raise e
|
||||
else:
|
||||
msg = "drivername should be one of [IE, Opera, Chrome, Firefox](case-insentive). given {0}".format(drivername)
|
||||
msg = "".join(("drivername should be one of [IE, Opera, Chrome, Firefox, PhantomJS]",
|
||||
"(case-insentive). given {0}".format(drivername)))
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@@ -86,7 +90,6 @@ def _chainreact(__getattr__):
|
||||
def reaction(*realargs):
|
||||
result = methodobj(*realargs)
|
||||
# for side-effective method(append, ...)
|
||||
result = result if result is not None else self
|
||||
return wrap_or_else(result)
|
||||
|
||||
return reaction
|
||||
@@ -96,11 +99,82 @@ def _chainreact(__getattr__):
|
||||
return containment
|
||||
|
||||
|
||||
class Performance(object):
|
||||
def __init__(self, performance):
|
||||
if not isinstance(performance, dict):
|
||||
raise AttributeError('Wrapped performance object should be an instance of dict.')
|
||||
self._performance = performance
|
||||
|
||||
@property
|
||||
def memory(self):
|
||||
if 'memory' in self._performance:
|
||||
return Memory(self._performance['memory'])
|
||||
raise AttributeError('window.performance.memory is not supported in this browser.')
|
||||
|
||||
@property
|
||||
def navigation(self):
|
||||
if 'navigation' in self._performance:
|
||||
return Navigation(self._performance['navigation'])
|
||||
raise AttributeError('window.performance.navigation is not supported in this browser.')
|
||||
|
||||
@property
|
||||
def timing(self):
|
||||
if 'timing' in self._performance:
|
||||
return Timing(self._performance['timing'])
|
||||
raise AttributeError('window.performance.timing is not supported in this browser.')
|
||||
|
||||
|
||||
class Memory(object):
|
||||
def __init__(self, memory):
|
||||
self._memory = memory
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._memory[name]
|
||||
|
||||
@property
|
||||
def __dict__(self):
|
||||
return self._memory
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._memory)
|
||||
|
||||
|
||||
class Navigation(object):
|
||||
def __init__(self, navigation):
|
||||
self._navigation = navigation
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._navigation[name]
|
||||
|
||||
@property
|
||||
def __dict__(self):
|
||||
return self._navigation
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._navigation)
|
||||
|
||||
|
||||
class Timing(object):
|
||||
def __init__(self, timing):
|
||||
self._timing = timing
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self._timing[name]
|
||||
|
||||
@property
|
||||
def __dict__(self):
|
||||
return self._timing
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._timing)
|
||||
|
||||
|
||||
class SeleniumWrapper(object):
|
||||
def __init__(self, driver):
|
||||
def __init__(self, driver, timeout=5, silent=False):
|
||||
if _is_wrappable(driver):
|
||||
self._wrapped = driver
|
||||
self._timeout = 5
|
||||
self._timeout = timeout
|
||||
self._silent = silent
|
||||
else:
|
||||
msg = "2nd argument should be an instance of WebDriver or WebElement. given {0}.".format(type(driver))
|
||||
raise TypeError(msg)
|
||||
@@ -109,6 +183,24 @@ class SeleniumWrapper(object):
|
||||
def unwrap(self):
|
||||
return self._wrapped
|
||||
|
||||
@property
|
||||
def performance(self):
|
||||
if isinstance(self._wrapped, WebDriver):
|
||||
if self._wrapped.execute_script("return 'performance' in window;"):
|
||||
timeout = time.time() + 120
|
||||
script = "return window.performance.timing.loadEventEnd;"
|
||||
executor = self._wrapped.execute_script
|
||||
while time.time() < timeout and not executor(script):
|
||||
time.sleep(0.2)
|
||||
if not executor(script):
|
||||
raise Exception('Timeout!')
|
||||
performance = self._wrapped.execute_script('return window.performance;')
|
||||
return Performance(performance)
|
||||
else:
|
||||
raise AttributeError("This browser is not supporting Timing APIs.")
|
||||
else:
|
||||
raise AttributeError("'WebElement' object has not attribute 'performance'")
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
if isinstance(self._wrapped, WebElement):
|
||||
@@ -136,16 +228,26 @@ class SeleniumWrapper(object):
|
||||
raise NoAlertPresentException(msg)
|
||||
|
||||
def _settimeout(self, timeout):
|
||||
if isinstance(timeout, int):
|
||||
if isinstance(timeout, (int, float)):
|
||||
self._timeout = timeout
|
||||
else:
|
||||
raise AttributeError('int please.')
|
||||
raise AttributeError
|
||||
|
||||
def _gettimeout(self):
|
||||
return self._timeout
|
||||
|
||||
timeout = property(_gettimeout, _settimeout)
|
||||
|
||||
@property
|
||||
def silent(self):
|
||||
return self._silent
|
||||
|
||||
@silent.setter
|
||||
def silent(self, true_of_false):
|
||||
if not isinstance(true_of_false, bool):
|
||||
raise AttributeError
|
||||
self._silent = true_of_false
|
||||
|
||||
def __getattribute__(self, name):
|
||||
return object.__getattribute__(self, name)
|
||||
|
||||
@@ -153,11 +255,6 @@ class SeleniumWrapper(object):
|
||||
def __getattr__(self, name):
|
||||
return self._wrapped, getattr(self._wrapped, name)
|
||||
|
||||
@property
|
||||
def current_url(self):
|
||||
self.by_tag("body", self._timeout)
|
||||
return self._wrapped.current_url
|
||||
|
||||
def _is_selectable(self):
|
||||
return self.unwrap.tag_name == 'select'
|
||||
|
||||
@@ -226,47 +323,14 @@ class SeleniumWrapper(object):
|
||||
try:
|
||||
if presleep:
|
||||
time.sleep(presleep)
|
||||
self._wait_until_stopping(timeout, 0.1)
|
||||
self._wait_until_displayed(timeout, 0.3)
|
||||
self._wait_until_clickable(timeout, 0.3)
|
||||
self._wait_until_stopping(timeout, 0.01)
|
||||
self._wait_until_displayed(timeout, 0.01)
|
||||
self._wait_until_clickable(timeout, 0.01)
|
||||
if postsleep:
|
||||
time.sleep(postsleep)
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
def load_js(self, path_or_file):
|
||||
"""Load javascript from /path/to/file or file like object that responds to 'read' method."""
|
||||
if isinstance(path_or_file, str) and os.path.isfile(path_or_file):
|
||||
with open(path_or_file, 'r') as f:
|
||||
library = f.read()
|
||||
self._wrapped.execute_script(library)
|
||||
elif hasattr(path_or_file, 'read'):
|
||||
library = path_or_file.read()
|
||||
self._wrapped.execute_script(library)
|
||||
else:
|
||||
raise AttributeError('Given argument is not both file or /path/to/file:: {0}'.format(str(path_or_file)))
|
||||
|
||||
def jquery(self, target):
|
||||
"""Returns SeleniumContainerWrapper if any elements is found."""
|
||||
script = "try{{return $('{0}');}}catch(e){{}}".format(target)
|
||||
result = self._wrapped.execute_script(script)
|
||||
if result:
|
||||
if isinstance(result, collections.Sequence):
|
||||
return SeleniumContainerWrapper(result)
|
||||
else:
|
||||
return SeleniumWrapper(result)
|
||||
else:
|
||||
raise NoSuchElementException("Target {0} not found.".format(target))
|
||||
|
||||
def script(self, javascript, *args):
|
||||
"""Synchronously execute given javascript."""
|
||||
result = self._wrapped.execute_script(javascript, *args)
|
||||
if result:
|
||||
if isinstance(result, collections.Sequence):
|
||||
return SeleniumContainerWrapper(result)
|
||||
else:
|
||||
return SeleniumWrapper(result)
|
||||
|
||||
def scroll_to(self, x, y):
|
||||
if isinstance(self._wrapped, WebDriver):
|
||||
return self._wrapped.execute_script("window.scrollTo({:d}, {:d})".format(x, y))
|
||||
@@ -314,16 +378,19 @@ class SeleniumWrapper(object):
|
||||
try:
|
||||
result = WebDriverWait(self._wrapped, timeout).until(finder)
|
||||
if eager and len(result):
|
||||
return SeleniumContainerWrapper(result)
|
||||
return SeleniumContainerWrapper(result, self.timeout, self.silent)
|
||||
elif _is_wrappable(result):
|
||||
return SeleniumWrapper(result)
|
||||
return SeleniumWrapper(result, self.timeout, self.silent)
|
||||
else:
|
||||
return result
|
||||
except TimeoutException:
|
||||
template = ("Waited for element to appear for {sec} seconds, ",
|
||||
"but {type}:{target} didn't appear.")
|
||||
msg = "".join(template).format(sec=timeout, type=type, target=target)
|
||||
raise NoSuchElementException(msg)
|
||||
if self.silent:
|
||||
return None
|
||||
else:
|
||||
template = ("Waited for element to appear for {sec} seconds, ",
|
||||
"but {type}:{target} didn't appear.")
|
||||
msg = "".join(template).format(sec=timeout, type=type, target=target)
|
||||
raise NoSuchElementException(msg)
|
||||
|
||||
def xpath(self, target, eager=False, timeout=None):
|
||||
return self.waitfor("xpath", target, eager, timeout)
|
||||
@@ -373,7 +440,9 @@ class SeleniumWrapper(object):
|
||||
return self.xpath(xpath, eager, timeout)
|
||||
|
||||
def button(self, value, eager=False, timeout=None):
|
||||
return self.xpath(".//input[@type='submit' or @type='button' and @value='{0}']".format(value), eager, timeout)
|
||||
return self.xpath(
|
||||
".//input[@type='submit' or @type='button' and @value='{0}']"
|
||||
"|.//button[text()='{0}']".format(value), eager, timeout)
|
||||
|
||||
def checkbox(self, eager=False, timeout=None, **attributes):
|
||||
attributes["type"] = "checkbox"
|
||||
@@ -399,11 +468,13 @@ class SeleniumWrapper(object):
|
||||
|
||||
|
||||
class SeleniumContainerWrapper(object):
|
||||
def __init__(self, iterable):
|
||||
def __init__(self, iterable, timeout=5, silent=False):
|
||||
if not isinstance(iterable, collections.Sequence):
|
||||
msg = "2nd argument should be an instance of collections.Sequence. given {0}".format(type(iterable))
|
||||
raise TypeError(msg)
|
||||
self._iterable = iterable
|
||||
self._timeout = timeout
|
||||
self._silent = silent
|
||||
|
||||
@_chainreact
|
||||
def __getattr__(self, name):
|
||||
@@ -413,7 +484,7 @@ class SeleniumContainerWrapper(object):
|
||||
def __getitem__(self, key):
|
||||
obj = self._iterable[key]
|
||||
if _is_wrappable(obj):
|
||||
return SeleniumWrapper(obj)
|
||||
return SeleniumWrapper(obj, self._timeout, self._silent)
|
||||
return obj
|
||||
|
||||
def __len__(self):
|
||||
@@ -430,12 +501,12 @@ class SeleniumContainerWrapper(object):
|
||||
def sample(self, size):
|
||||
picked = random.sample(self._iterable, size)
|
||||
if isinstance(picked, collections.Sequence):
|
||||
return SeleniumContainerWrapper(picked)
|
||||
return SeleniumContainerWrapper(picked, self._timeout, self._silent)
|
||||
return picked
|
||||
|
||||
def choice(self):
|
||||
picked = random.choice(self._iterable)
|
||||
if _is_wrappable(picked):
|
||||
return SeleniumWrapper(picked)
|
||||
return SeleniumWrapper(picked, self._timeout, self._silent)
|
||||
else:
|
||||
return picked
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import sys
|
||||
|
||||
sys.path.append("./../src")
|
||||
if sys.version < '2.7':
|
||||
import unittest2 as unittest
|
||||
@@ -6,13 +7,12 @@ else:
|
||||
import unittest
|
||||
import collections
|
||||
import mock
|
||||
import selenium
|
||||
from selenium.webdriver.remote.webdriver import WebDriver
|
||||
from selenium.webdriver.remote.webelement import WebElement
|
||||
from seleniumwrapper.wrapper import SeleniumWrapper, SeleniumContainerWrapper
|
||||
|
||||
class TestSeleniumContainerWrapper(unittest.TestCase):
|
||||
|
||||
class TestSeleniumContainerWrapper(unittest.TestCase):
|
||||
def test_container_raise_if_given_argument_is_not_an_instance_of_Sequence(self):
|
||||
containment = 1
|
||||
self.assertNotIsInstance(containment, collections.Sequence)
|
||||
@@ -27,9 +27,9 @@ class TestSeleniumContainerWrapper(unittest.TestCase):
|
||||
container = SeleniumContainerWrapper([])
|
||||
container.append(1)
|
||||
container.append(1)
|
||||
self.assertEquals(container.count(1), 2)
|
||||
self.assertEquals(container.pop(), 1)
|
||||
self.assertEquals(container.count(1), 1)
|
||||
self.assertEqual(container.count(1), 2)
|
||||
self.assertEqual(container.pop(), 1)
|
||||
self.assertEqual(container.count(1), 1)
|
||||
|
||||
def test_container_should_return_wrapped_object_if_possible(self):
|
||||
mock1 = mock.Mock(WebDriver)
|
||||
@@ -65,14 +65,14 @@ class TestSeleniumContainerWrapper(unittest.TestCase):
|
||||
mock2 = mock.Mock(WebElement)
|
||||
iterable = [mock1, mock2]
|
||||
container = SeleniumContainerWrapper(iterable)
|
||||
self.assertEquals(len(container), 2)
|
||||
self.assertEqual(len(container), 2)
|
||||
|
||||
def test_container_has_size_property(self):
|
||||
mock1 = mock.Mock(WebDriver)
|
||||
mock2 = mock.Mock(WebElement)
|
||||
iterable = [mock1, mock2]
|
||||
container = SeleniumContainerWrapper(iterable)
|
||||
self.assertEquals(container.size, 2)
|
||||
self.assertEqual(container.size, 2)
|
||||
|
||||
def test_container_support__contains__protocol(self):
|
||||
mock1 = mock.Mock(WebDriver)
|
||||
@@ -93,7 +93,7 @@ class TestSeleniumContainerWrapper(unittest.TestCase):
|
||||
container = SeleniumContainerWrapper(iterable)
|
||||
sampled = container.sample(5)
|
||||
self.assertTrue(isinstance(sampled, SeleniumContainerWrapper))
|
||||
self.assertEquals(len(sampled), 5)
|
||||
self.assertEqual(len(sampled), 5)
|
||||
for sample in sampled:
|
||||
self.assertTrue(sample in container)
|
||||
|
||||
@@ -104,11 +104,21 @@ class TestSeleniumContainerWrapper(unittest.TestCase):
|
||||
self.assertTrue(isinstance(picked, SeleniumWrapper))
|
||||
self.assertTrue(picked in container)
|
||||
|
||||
def test_contained_object_inherits_option_properties_from_container(self):
|
||||
iterable = [mock.Mock(WebElement) for i in range(5)]
|
||||
container = SeleniumContainerWrapper(iterable, 1, True)
|
||||
for contained in container:
|
||||
self.assertEqual(contained.timeout, 1)
|
||||
self.assertTrue(contained.silent)
|
||||
self.assertEqual(container[-1].timeout, 1)
|
||||
self.assertTrue(container[-1].silent)
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTests(unittest.makeSuite(TestSeleniumContainerWrapper))
|
||||
return suite
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
s = suite()
|
||||
unittest.TextTestRunner(verbosity=2).run(s)
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
import sys
|
||||
|
||||
sys.path.append("./../src")
|
||||
if sys.version < '2.7':
|
||||
import unittest2 as unittest
|
||||
else:
|
||||
import unittest
|
||||
try:
|
||||
import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
import mock
|
||||
import StringIO
|
||||
import seleniumwrapper
|
||||
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
|
||||
from selenium.webdriver.remote.webdriver import WebDriver
|
||||
from selenium.webdriver.remote.webelement import WebElement
|
||||
from seleniumwrapper.wrapper import SeleniumWrapper
|
||||
from seleniumwrapper.wrapper import SeleniumContainerWrapper
|
||||
from selenium.common.exceptions import NoSuchElementException, WebDriverException, ElementNotVisibleException
|
||||
from selenium.common.exceptions import (
|
||||
NoSuchElementException,WebDriverException, ElementNotVisibleException, TimeoutException
|
||||
)
|
||||
|
||||
|
||||
class TestSeleniumWrapperFactory(unittest.TestCase):
|
||||
|
||||
def test_factory_functions_raise_typeerror_if_argument_is_not_a_string(self):
|
||||
self.assertRaises(TypeError, seleniumwrapper.create, 1)
|
||||
self.assertRaises(TypeError, seleniumwrapper.connect, 1, "http://somethings:9999/wd/hub")
|
||||
@@ -32,15 +38,15 @@ class TestSeleniumWrapperFactory(unittest.TestCase):
|
||||
m = p.start()
|
||||
p2 = mock.patch("seleniumwrapper.wrapper.SeleniumWrapper")
|
||||
m2 = p2.start()
|
||||
seleniumwrapper.connect("android", "http://localhost:4444/wd/hub", {"hoge":"hoge"})
|
||||
seleniumwrapper.connect("android", "http://localhost:4444/wd/hub", {"hoge": "hoge"})
|
||||
dic = DesiredCapabilities.ANDROID
|
||||
dic["hoge"] = "hoge"
|
||||
m.assert_called_once_with('http://localhost:4444/wd/hub', dic)
|
||||
p2.stop()
|
||||
p.stop()
|
||||
|
||||
class TestSeleniumWrapper(unittest.TestCase):
|
||||
|
||||
class TestSeleniumWrapper(unittest.TestCase):
|
||||
def test_init_raise_if_driver_is_not_a_webdriver_object(self):
|
||||
self.assertRaises(TypeError, SeleniumWrapper, 'hoge')
|
||||
|
||||
@@ -52,7 +58,7 @@ class TestSeleniumWrapper(unittest.TestCase):
|
||||
mocked_driver = mock.Mock(WebDriver)
|
||||
mocked_driver.hoge = lambda d: d
|
||||
wrapper = SeleniumWrapper(mocked_driver)
|
||||
self.assertEquals(wrapper.hoge(1), 1)
|
||||
self.assertEqual(wrapper.hoge(1), 1)
|
||||
|
||||
def test_wrapper_should_raise_AttributeError_if_wrapped_driver_also_dont_have_attribute_with_given_name(self):
|
||||
mocked_driver = mock.Mock(WebDriver)
|
||||
@@ -73,28 +79,33 @@ class TestSeleniumWrapper(unittest.TestCase):
|
||||
mocked_driver = mock.Mock(WebDriver)
|
||||
mocked_driver.find_element_by_id = lambda target: target
|
||||
wrapper = SeleniumWrapper(mocked_driver)
|
||||
self.assertEquals(wrapper.waitfor('id', 'hoge'), 'hoge')
|
||||
self.assertEqual(wrapper.waitfor('id', 'hoge'), 'hoge')
|
||||
|
||||
def test_wrapper_should_handle_attr_access_even_if_attr_is_descriptor(self):
|
||||
mocked_element = mock.Mock(WebElement)
|
||||
|
||||
class Hoge(WebDriver):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
@property
|
||||
def hoge(self):
|
||||
return mocked_element
|
||||
|
||||
@property
|
||||
def num(self):
|
||||
return 100
|
||||
|
||||
mocked_driver = Hoge()
|
||||
wrapper = SeleniumWrapper(mocked_driver)
|
||||
self.assertEquals(wrapper.num, 100)
|
||||
self.assertEqual(wrapper.num, 100)
|
||||
self.assertTrue(isinstance(wrapper.hoge, SeleniumWrapper), wrapper.hoge)
|
||||
|
||||
def test_click_should_raise_if_element_is_not_stopping_for_time_seconds(self):
|
||||
class Hoge(object):
|
||||
def __init__(self):
|
||||
self.num = 0
|
||||
|
||||
def __getitem__(self, num):
|
||||
self.num += 1
|
||||
return self.num
|
||||
@@ -102,41 +113,58 @@ class TestSeleniumWrapper(unittest.TestCase):
|
||||
mocked_element = mock.Mock(WebElement)
|
||||
mocked_element.location = Hoge()
|
||||
wrapper = SeleniumWrapper(mocked_element)
|
||||
self.assertRaises(WebDriverException, wrapper.click, **{'timeout':0.5})
|
||||
self.assertRaises(WebDriverException, wrapper.click, **{'timeout': 0.5})
|
||||
|
||||
def test_click_should_raise_if_element_is_not_clickable_for_timeout_seconds(self):
|
||||
def dummy():
|
||||
raise WebDriverException("hoge:fuga:huhuhu")
|
||||
|
||||
mocked_element = mock.Mock(WebElement)
|
||||
mocked_element.click = dummy
|
||||
mocked_element.value_of_css_property.return_value = 0
|
||||
mocked_element.location = {"x":0, "y":0}
|
||||
mocked_element.location = {"x": 0, "y": 0}
|
||||
wrapper = SeleniumWrapper(mocked_element)
|
||||
self.assertRaises(WebDriverException, wrapper.click, **{'timeout':0.5})
|
||||
self.assertRaises(WebDriverException, wrapper.click, **{'timeout': 0.5})
|
||||
|
||||
def test_click_should_raise_if_element_is_not_displayed_for_timeout_seconds(self):
|
||||
mocked_element = mock.Mock(WebElement)
|
||||
mocked_element.is_displayed = lambda : False
|
||||
mocked_element.is_displayed = lambda: False
|
||||
mocked_element.value_of_css_property.return_value = 0
|
||||
mocked_element.location = {"x":0, "y":0}
|
||||
mocked_element.location = {"x": 0, "y": 0}
|
||||
wrapper = SeleniumWrapper(mocked_element)
|
||||
self.assertRaises(ElementNotVisibleException, wrapper.click, **{'timeout':0.5})
|
||||
self.assertRaises(ElementNotVisibleException, wrapper.click, **{'timeout': 0.5})
|
||||
|
||||
def test_click_should_raise_if_other_exception_is_thrown(self):
|
||||
def dummy():
|
||||
raise TypeError()
|
||||
|
||||
mocked_element = mock.Mock(WebElement)
|
||||
mocked_element.click = dummy
|
||||
wrapper = SeleniumWrapper(mocked_element)
|
||||
self.assertRaises(TypeError, wrapper.click, **{'timeout':0.5})
|
||||
self.assertRaises(TypeError, wrapper.click, **{'timeout': 0.5})
|
||||
|
||||
def test_unwrap_return_its_wrapped_object(self):
|
||||
mocked_element = mock.Mock(WebElement)
|
||||
wrapper = SeleniumWrapper(mocked_element)
|
||||
self.assertIsInstance(wrapper.unwrap, WebElement)
|
||||
|
||||
class TestSeleniumWrapperAliases(unittest.TestCase):
|
||||
def test_execute_script_should_return_None_if_null_was_returned(self):
|
||||
mocked_driver = mock.Mock(WebDriver)
|
||||
mocked_driver.execute_script.return_value = None
|
||||
driver = SeleniumWrapper(mocked_driver)
|
||||
obj = driver.execute_script('return null')
|
||||
self.assertIsNone(obj)
|
||||
|
||||
def test_wrapper_returns_None_in_silent_mode(self):
|
||||
mocked_driver = mock.Mock(WebDriver)
|
||||
mocked_driver.find_element_by_id.side_effect = TimeoutException
|
||||
driver = SeleniumWrapper(mocked_driver)
|
||||
self.assertRaises(NoSuchElementException, driver.by_id, 'hoge')
|
||||
driver.silent = True
|
||||
self.assertIsNone(driver.by_id('hoge'))
|
||||
|
||||
|
||||
class TestSeleniumWrapperAliases(unittest.TestCase):
|
||||
def setUp(self):
|
||||
mocky = mock.Mock(WebDriver)
|
||||
self.mock = mocky
|
||||
@@ -144,12 +172,13 @@ class TestSeleniumWrapperAliases(unittest.TestCase):
|
||||
def test_waitfor_raise_if_find_element_return_falsy_value(self):
|
||||
self.mock.find_element_by_xpath.return_value = None
|
||||
wrapper = SeleniumWrapper(self.mock)
|
||||
self.assertRaises(NoSuchElementException, wrapper.waitfor, *['xpath', 'dummy'], **{'timeout':0.1})
|
||||
self.assertRaises(NoSuchElementException, wrapper.waitfor, *['xpath', 'dummy'], **{'timeout': 0.1})
|
||||
|
||||
def test_waitfor_raise_if_find_elements_return_falsy_value(self):
|
||||
self.mock.find_elements_by_xpath.return_value = []
|
||||
wrapper = SeleniumWrapper(self.mock)
|
||||
self.assertRaises(NoSuchElementException, wrapper.waitfor, *['xpath', 'dummy'], **{'eager':True, 'timeout':0.1})
|
||||
self.assertRaises(NoSuchElementException, wrapper.waitfor, *['xpath', 'dummy'],
|
||||
**{'eager': True, 'timeout': 0.1})
|
||||
|
||||
def test_waitfor_wraps_its_return_value_if_it_is_wrappable(self):
|
||||
mock_elem = mock.Mock(WebElement)
|
||||
@@ -203,37 +232,12 @@ class TestSeleniumWrapperAliases(unittest.TestCase):
|
||||
wrapper = SeleniumWrapper(wrapped_elem)
|
||||
self.assertIsInstance(wrapper.parent, SeleniumWrapper)
|
||||
|
||||
class TestSeleniumWrapperJavascriptSupport(unittest.TestCase):
|
||||
|
||||
class TestSeleniumWrapperJavascriptSupport(unittest.TestCase):
|
||||
def setUp(self):
|
||||
mocky = mock.Mock(WebDriver)
|
||||
self.mock = mocky
|
||||
|
||||
def test_load_js_raise_if_given_argument_is_not_both_file_like_obj_or_path_to_file(self):
|
||||
wrapper = SeleniumWrapper(self.mock)
|
||||
self.assertRaises(AttributeError, wrapper.load_js, "/path/not/exists")
|
||||
self.assertRaises(AttributeError, wrapper.load_js, 1)
|
||||
|
||||
def test_load_js_load_string_from_StringIO_because_it_respond_to_read_method(self):
|
||||
f = StringIO.StringIO('hoge')
|
||||
wrapper = SeleniumWrapper(self.mock)
|
||||
wrapper.load_js(f)
|
||||
self.mock.execute_script.assert_called_once_with('hoge')
|
||||
|
||||
def test_script_returns_if_something_is_returned_by_execute_script(self):
|
||||
self.mock.execute_script.return_value = [mock.Mock(WebElement)]
|
||||
wrapper = SeleniumWrapper(self.mock)
|
||||
self.assertIsInstance(wrapper.script('fuga'), SeleniumContainerWrapper)
|
||||
self.mock.execute_script.return_value = mock.Mock(WebElement)
|
||||
self.assertIsInstance(wrapper.script('fuga'), SeleniumWrapper)
|
||||
self.mock.execute_script.return_value = None
|
||||
self.assertIsNone(wrapper.script('fuga'))
|
||||
|
||||
def test_jquery_raise_if_nothing_found(self):
|
||||
self.mock.execute_script.return_value = None
|
||||
wrapper = SeleniumWrapper(self.mock)
|
||||
self.assertRaises(NoSuchElementException, wrapper.jquery, 'hoge')
|
||||
|
||||
def test_scroll_methods_raise_if_wrapped_is_not_webdriver(self):
|
||||
wrapper = SeleniumWrapper(mock.Mock(WebElement))
|
||||
self.assertRaises(AttributeError, wrapper.scroll_to, *[10, 10])
|
||||
@@ -252,6 +256,26 @@ class TestSeleniumWrapperJavascriptSupport(unittest.TestCase):
|
||||
mock.call.execute_script("try{$('#hoge') && $('#hoge')[0].scrollIntoView(true)}catch(e){}")]
|
||||
self.mock.assert_has_calls(calls)
|
||||
|
||||
class TestSeleniumWrapperOptions(unittest.TestCase):
|
||||
def setUp(self):
|
||||
mocky = mock.Mock(WebDriver)
|
||||
self.mock = mocky
|
||||
|
||||
def test_timeout_property_allows_int_and_float(self):
|
||||
wrapper = SeleniumWrapper(self.mock)
|
||||
wrapper.timeout = 0.1
|
||||
self.assertEqual(wrapper.timeout, 0.1)
|
||||
wrapper.timeout = 1
|
||||
self.assertEqual(wrapper.timeout, 1)
|
||||
|
||||
def test_silent_property_raise_AttributeError_if_none_bool_given(self):
|
||||
wrapper = SeleniumWrapper(self.mock)
|
||||
try:
|
||||
wrapper.silent = 1
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTests(unittest.makeSuite(TestSeleniumWrapperAliases))
|
||||
@@ -259,6 +283,7 @@ def suite():
|
||||
suite.addTests(unittest.makeSuite(TestSeleniumWrapperJavascriptSupport))
|
||||
return suite
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
s = suite()
|
||||
unittest.TextTestRunner(verbosity=2).run(s)
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
[tox]
|
||||
envlist = py26,py27,py32,py33,py34
|
||||
|
||||
[commondeps]
|
||||
deps =
|
||||
nose
|
||||
mock
|
||||
selenium
|
||||
|
||||
[testenv:py26]
|
||||
basepython = python2.6
|
||||
deps =
|
||||
{[commondeps]deps}
|
||||
unittest2
|
||||
commands = nosetests
|
||||
|
||||
[testenv:py27]
|
||||
basepython = python2.7
|
||||
deps = {[commondeps]deps}
|
||||
commands = nosetests
|
||||
|
||||
[testenv:py32]
|
||||
basepython = python3.2
|
||||
deps = {[commondeps]deps}
|
||||
commands = nosetests
|
||||
|
||||
[testenv:py33]
|
||||
basepython = python3.3
|
||||
deps = {[commondeps]deps}
|
||||
commands = nosetests
|
||||
|
||||
[testenv:py34]
|
||||
basepython = python3.4
|
||||
deps = {[commondeps]deps}
|
||||
commands = nosetests
|
||||
Reference in New Issue
Block a user