Skip to content

Commit

Permalink
Bugfixes, and various adjustments.
Browse files Browse the repository at this point in the history
- Bugfixes on issue #9 and issue #11
- Refactors form and select elements into its own module
- Fix and add more unit tests
- Add acceptance tests for fixed issues
  • Loading branch information
rickypc committed Mar 27, 2016
1 parent 7d8f471 commit bc88213
Show file tree
Hide file tree
Showing 24 changed files with 1,164 additions and 230 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
@@ -1,3 +1,11 @@
0.9.0 (2016.03.26)
==================

* Bugfixes on issue #9 and issue #11
* Refactors form and select elements into its own module
* Fix and add more unit tests
* Add acceptance tests for fixed issues

0.8.3 (2016.03.18)
==================

Expand Down
2 changes: 1 addition & 1 deletion doc/ExtendedSelenium2Library.html

Large diffs are not rendered by default.

100 changes: 10 additions & 90 deletions src/ExtendedSelenium2Library/__init__.py
Expand Up @@ -25,7 +25,9 @@
from Selenium2Library import Selenium2Library
from ExtendedSelenium2Library.decorators import inherit_docs
from ExtendedSelenium2Library.keywords import ExtendedElementKeywords
from ExtendedSelenium2Library.keywords import ExtendedFormElementKeywords
from ExtendedSelenium2Library.keywords import ExtendedJavascriptKeywords
from ExtendedSelenium2Library.keywords import ExtendedSelectElementKeywords
from ExtendedSelenium2Library.keywords import ExtendedWaitingKeywords
from ExtendedSelenium2Library.version import get_version

Expand All @@ -35,7 +37,8 @@
# pylint: disable=too-many-ancestors
@inherit_docs
class ExtendedSelenium2Library(Selenium2Library, ExtendedElementKeywords,
ExtendedJavascriptKeywords, ExtendedWaitingKeywords):
ExtendedFormElementKeywords, ExtendedJavascriptKeywords,
ExtendedSelectElementKeywords, ExtendedWaitingKeywords):
# pylint: disable=line-too-long
"""ExtendedSelenium2Library is a [http://goo.gl/boVQia|Selenium2 (WebDriver)]
web testing library with [https://goo.gl/Kzz8Y3|AngularJS] support and
Expand Down Expand Up @@ -168,31 +171,26 @@ def __init__(self, implicit_wait=15.0, **kwargs):
self._builtin = BuiltIn()
Selenium2Library.__init__(self, implicit_wait=implicit_wait, **kwargs)
ExtendedElementKeywords.__init__(self)
ExtendedFormElementKeywords.__init__(self)
ExtendedJavascriptKeywords.__init__(self)
ExtendedSelectElementKeywords.__init__(self)
ExtendedWaitingKeywords.__init__(self)
self._implicit_wait_in_secs = float(implicit_wait) if implicit_wait is not None else 15.0
self._page_ready_keyword_list = []
# pylint: disable=protected-access
self._table_element_finder._element_finder = self._element_finder

# pylint: disable=arguments-differ
# pylint: disable=missing-docstring
def click_button(self, locator, skip_ready=False):
element = self._scroll_into_view_on_internet_explorer(locator)
super(ExtendedSelenium2Library, self).click_button(element)
if not skip_ready:
self._wait_until_page_ready()

def get_browser_logs(self):
"""Returns the Javascript console logs from the browser.
"""Returns the Javascript console logs from the browser. (Non Internet Explorer only).
Please see [https://goo.gl/S7yvqR|Logging Preferences JSON object] to set
how verbose the logging should be. (Default 'SEVERE')
Examples:
| Get Browser Logs |
"""
return self._current_browser().get_log('browser')
# IEDriverServer doesn't have log implementation yet
return [] if self._is_internet_explorer() else self._current_browser().get_log('browser')

def get_location(self):
# AngularJS support
Expand All @@ -207,6 +205,7 @@ def get_location(self):
response = self._current_browser().get_current_url()
return response

# pylint: disable=arguments-differ
# pylint: disable=too-many-arguments
def open_browser(self, url, browser='firefox', alias=None, remote_url=False,
desired_capabilities=None, ff_profile_dir=None, skip_ready=False):
Expand Down Expand Up @@ -237,82 +236,3 @@ def remove_page_ready_keyword(self, keyword_name):
| Remove Page Ready Keyword | My Keyword |
"""
self._page_ready_keyword_list.remove(keyword_name)

def select_all_from_list(self, locator):
element = self._element_find(locator, True, True, 'select')
super(ExtendedSelenium2Library, self).select_all_from_list(element)
self._element_trigger_change(locator)

def select_checkbox(self, locator):
self._info("Selecting checkbox '%s'." % locator)
element = self._get_checkbox(locator)
if not element.is_selected():
self._select_checkbox_or_radio_button(locator)

def select_from_list(self, locator, *items):
element = self._element_find(locator, True, True, 'select')
super(ExtendedSelenium2Library, self).select_from_list(element, *items)
self._element_trigger_change(locator)

def select_from_list_by_index(self, locator, *indexes):
element = self._element_find(locator, True, True, 'select')
super(ExtendedSelenium2Library, self).select_from_list_by_index(element, *indexes)
self._element_trigger_change(locator)

def select_from_list_by_label(self, locator, *labels):
element = self._element_find(locator, True, True, 'select')
super(ExtendedSelenium2Library, self).select_from_list_by_label(element, *labels)
self._element_trigger_change(locator)

def select_from_list_by_value(self, locator, *values):
element = self._element_find(locator, True, True, 'select')
super(ExtendedSelenium2Library, self).select_from_list_by_value(element, *values)
self._element_trigger_change(locator)

def select_radio_button(self, group_name, value):
self._info("Selecting '%s' from radio button '%s'." % (value, group_name))
element = self._get_radio_button_with_value(group_name, value)
if not element.is_selected():
self._select_checkbox_or_radio_button('css=input[name="%s"][value="%s"]' %
(group_name, value))

def submit_form(self, locator=None, skip_ready=False):
element = self._scroll_into_view_on_internet_explorer(locator)
super(ExtendedSelenium2Library, self).submit_form(element)
if not skip_ready:
self._wait_until_page_ready()

def _element_trigger_change(self, locator):
"""Trigger change event on target element when AngularJS is ready."""
self._wait_until_page_ready(locator,
skip_stale_check=True,
prefix='var cb=arguments[arguments.length-1];'
'var el=arguments[0];if(window.angular){',
handler='function(){$(el).trigger(\'change\').'
'trigger(\'focusout\');cb(true)}')

def _input_text_into_text_field(self, locator, text, skip_ready=False):
"""Send keys to text field with AngularJS synchronization."""
element = self._element_find(locator, True, True)
if element is None:
raise AssertionError("Element '%s' not found." % locator)
element.clear()
element.send_keys(text)
if not skip_ready:
self._wait_until_page_ready(locator,
skip_stale_check=True,
prefix='var cb=arguments[arguments.length-1];'
'var el=arguments[0];if(window.angular){',
handler='function(){$(el).trigger(\'change\').'
'trigger(\'focusout\');cb(true)}')

def _select_checkbox_or_radio_button(self, locator):
"""Select checkbox or radio button with AngularJS support."""
self._wait_until_page_ready(locator,
skip_stale_check=True,
prefix='var cb=arguments[arguments.length-1];'
'var el=arguments[0];if(window.angular){',
handler='function(){angular.element(el).'
'prop(\'checked\',true).triggerHandler(\'click\');'
'cb(true)}',
suffix='}else{el.click();cb(false)}')
4 changes: 4 additions & 0 deletions src/ExtendedSelenium2Library/keywords/__init__.py
Expand Up @@ -22,11 +22,15 @@
"""

from ExtendedSelenium2Library.keywords.extendedelement import ExtendedElementKeywords
from ExtendedSelenium2Library.keywords.extendedformelement import ExtendedFormElementKeywords
from ExtendedSelenium2Library.keywords.extendedjavascript import ExtendedJavascriptKeywords
from ExtendedSelenium2Library.keywords.extendedselectelement import ExtendedSelectElementKeywords
from ExtendedSelenium2Library.keywords.extendedwaiting import ExtendedWaitingKeywords

__all__ = [
'ExtendedElementKeywords',
'ExtendedFormElementKeywords',
'ExtendedJavascriptKeywords',
'ExtendedSelectElementKeywords',
'ExtendedWaitingKeywords',
]
85 changes: 53 additions & 32 deletions src/ExtendedSelenium2Library/keywords/extendedelement.py
Expand Up @@ -21,19 +21,23 @@
Extended Selenium2 Library - a web testing library with AngularJS support.
"""

from robot.api import logger
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.remote.webelement import WebElement
from Selenium2Library.keywords import _ElementKeywords
from ExtendedSelenium2Library.locators import ExtendedElementFinder


class ExtendedElementKeywords(_ElementKeywords):
"""ExtendedElementKeywords are web element related execution in the requested browser."""
"""ExtendedElementKeywords are web element execution in the requested browser."""

def __init__(self):
super(ExtendedElementKeywords, self).__init__()
self._element_finder = ExtendedElementFinder()

# pylint: disable=arguments-differ
def click_element(self, locator, skip_ready=False):
"""Click element identified by ``locator``.
"""Clicks an element identified by ``locator``.
Arguments:
- ``locator``: The locator to find requested element. Key attributes for
Expand All @@ -45,14 +49,15 @@ def click_element(self, locator, skip_ready=False):
| Click Element | css=div.class |
| Click Element | css=div.class | True |
"""
element = self._scroll_into_view_on_internet_explorer(locator)
super(ExtendedElementKeywords, self).click_element(element)
# pylint: disable=no-member
self._info("Clicking element '%s'." % locator)
self._get_element_and_scroll_into_view_on_iexplore(locator).click()
if not skip_ready:
# pylint: disable=no-member
self._wait_until_page_ready()

def click_element_at_coordinates(self, locator, xoffset, yoffset, skip_ready=False):
"""Click element identified by ``locator`` at x/y coordinates of the element.
"""Clicks an element identified by ``locator`` at x/y coordinates of the element.
Cursor is moved at the center of the element and x/y coordinates are
calculated from that point.
Expand All @@ -68,15 +73,19 @@ def click_element_at_coordinates(self, locator, xoffset, yoffset, skip_ready=Fal
| Click Element At Coordinates | css=div.class | 0 | 0 |
| Click Element At Coordinates | css=div.class | 0 | 0 | True |
"""
element = self._scroll_into_view_on_internet_explorer(locator)
super(ExtendedElementKeywords, self). \
click_element_at_coordinates(element, xoffset, yoffset)
# pylint: disable=no-member
self._info("Clicking element '%s' in coordinates '%s', '%s'." %
(locator, xoffset, yoffset))
element = self._get_element_and_scroll_into_view_on_iexplore(locator)
# pylint: disable=no-member
ActionChains(self._current_browser()).move_to_element(element). \
move_by_offset(xoffset, yoffset).click().perform()
if not skip_ready:
# pylint: disable=no-member
self._wait_until_page_ready()

def click_image(self, locator, skip_ready=False):
"""Click an image identified by ``locator``.
"""Clicks an image identified by ``locator``.
Arguments:
- ``locator``: The locator to find requested image. Key attributes for
Expand All @@ -85,17 +94,22 @@ def click_image(self, locator, skip_ready=False):
- ``skip_ready``: A boolean flag to skip the wait for page ready. (Default False)
Examples:
| Click Image | css=div.class |
| Click Image | css=div.class | True |
| Click Image | css=img.class |
| Click Image | css=img.class | True |
"""
element = self._scroll_into_view_on_internet_explorer(locator)
super(ExtendedElementKeywords, self).click_image(element)
# pylint: disable=no-member
self._info("Clicking image '%s'." % locator)
element = self._get_element_and_scroll_into_view_on_iexplore(locator, False, 'image')
if element is None:
# A form may have an image as it's submit trigger.
element = self._get_element_and_scroll_into_view_on_iexplore(locator, True, 'input')
element.click()
if not skip_ready:
# pylint: disable=no-member
self._wait_until_page_ready()

def click_link(self, locator, skip_ready=False):
"""Click a link identified by ``locator``.
"""Clicks a link identified by ``locator``.
Arguments:
- ``locator``: The locator to find requested link. Key attributes for
Expand All @@ -104,17 +118,18 @@ def click_link(self, locator, skip_ready=False):
- ``skip_ready``: A boolean flag to skip the wait for page ready. (Default False)
Examples:
| Click Link | css=div.class |
| Click Link | css=div.class | True |
| Click Link | css=a.class |
| Click Link | css=a.class | True |
"""
element = self._scroll_into_view_on_internet_explorer(locator)
super(ExtendedElementKeywords, self).click_link(element)
# pylint: disable=no-member
self._info("Clicking link '%s'." % locator)
self._get_element_and_scroll_into_view_on_iexplore(locator, tag='a').click()
if not skip_ready:
# pylint: disable=no-member
self._wait_until_page_ready()

def double_click_element(self, locator, skip_ready=False):
"""Double click element identified by ``locator``.
"""Double clicks an element identified by ``locator``.
Arguments:
- ``locator``: The locator to find requested element. Key attributes for
Expand All @@ -126,8 +141,11 @@ def double_click_element(self, locator, skip_ready=False):
| Double Click Element | css=div.class |
| Double Click Element | css=div.class | True |
"""
element = self._scroll_into_view_on_internet_explorer(locator)
super(ExtendedElementKeywords, self).double_click_element(element)
# pylint: disable=no-member
self._info("Double clicking element '%s'." % locator)
element = self._get_element_and_scroll_into_view_on_iexplore(locator)
# pylint: disable=no-member
ActionChains(self._current_browser()).double_click(element).perform()
if not skip_ready:
# pylint: disable=no-member
self._wait_until_page_ready()
Expand Down Expand Up @@ -187,7 +205,7 @@ def is_element_visible(self, locator):
return self._is_visible(locator)

def scroll_element_into_view(self, locator):
"""Scroll element from given ``locator`` into view.
"""Scrolls an element from given ``locator`` into view.
Arguments:
- ``locator``: The locator to find requested element. Key attributes for
Expand All @@ -197,9 +215,11 @@ def scroll_element_into_view(self, locator):
Examples:
| Scroll Element Into View | css=div.class |
"""
element = self._element_find(locator, True, True)
if element is None:
raise AssertionError("Element '%s' not found." % locator)
if isinstance(locator, WebElement):
element = locator
else:
logger.info("Scrolling element '%s' into view." % locator)
element = self._element_find(locator, True, True)
script = 'arguments[0].scrollIntoView()'
# pylint: disable=no-member
self._current_browser().execute_script(script, element)
Expand All @@ -210,15 +230,16 @@ def _get_browser_name(self):
# pylint: disable=no-member
return self._current_browser().capabilities['browserName'].strip().lower()

def _get_element_and_scroll_into_view_on_iexplore(self, locator, required=True, tag=None):
"""Scrolls a target element into view. (Internet Explorer only)."""
element = self._element_find(locator, True, required, tag)
if element and self._is_internet_explorer():
self.scroll_element_into_view(element)
return element

def _is_internet_explorer(self, browser_name=None):
"""Returns true if current browser is Internet Explorer."""
if not browser_name:
browser_name = self._get_browser_name()
browser_name = browser_name.replace(' ', '')
return browser_name == 'internetexplorer' or browser_name == 'ie'

def _scroll_into_view_on_internet_explorer(self, locator):
"""Scroll target element into view. (Internet Explorer only)."""
element = self._element_find(locator, True, True)
if self._is_internet_explorer():
self.scroll_element_into_view(element)
return element

0 comments on commit bc88213

Please sign in to comment.