Permalink
Browse files

Minor Enhancements.

- Add `Fast Wait Until Page Contains` keyword
- Add unit tests for extended element finder
- Add auto generated documentation
- Add items to gitignore file
- Adjust image path in the README file
- Bump up version
  • Loading branch information...
1 parent 248e5b4 commit 280dd00aa4f01c20e5bd333cf6d2d04671252982 @rickypc committed Jul 11, 2016
View
@@ -1,6 +1,7 @@
# Byte-compiled / optimized / DLL files
__pycache__/
-*.py[cod]
-
*.egg-info
+*.py[cod]
+*.swp
+.coverage
dist
View
@@ -1,3 +1,12 @@
+0.9.1 (2016.07.10)
+==================
+
+- Add `Fast Wait Until Page Contains` keyword
+- Add unit tests for extended element finder
+- Add auto generated documentation
+- Add items to gitignore file
+- Adjust image path in the README file
+
0.9.0 (2016.03.26)
==================
View
@@ -220,9 +220,9 @@ Documentation and other similar content are provided under `Creative Commons Att
.. |License| image:: https://img.shields.io/pypi/l/robotframework-extendedselenium2library.svg
:target: http://goo.gl/LOMJeU
:alt: License
-.. |Similarity| image:: /assets/RF-Cucumber-01.jpg
+.. |Similarity| image:: https://raw.githubusercontent.com/rickypc/robotframework-extendedselenium2library/master/assets/RF-Cucumber-01.jpg
:alt: Framework Similarities
-.. |Onion| image:: /assets/RF-Cucumber-02.jpg
+.. |Onion| image:: https://raw.githubusercontent.com/rickypc/robotframework-extendedselenium2library/master/assets/RF-Cucumber-02.jpg
:alt: Onion Diagram
-.. |Actual| image:: /assets/RF-Cucumber-03.jpg
+.. |Actual| image:: https://raw.githubusercontent.com/rickypc/robotframework-extendedselenium2library/master/assets/RF-Cucumber-03.jpg
:alt: Actual Implementation
Oops, something went wrong.
@@ -62,6 +62,7 @@ class ExtendedSelenium2Library(Selenium2Library, ExtendedElementKeywords,
| `Element Attribute Should Not Contain` |
| `Execute Async Javascript With Replaced Variables` |
| `Execute Javascript With Replaced Variables` |
+ | `Fast Wait Until Page Contains` |
| `Get Browser Logs` |
| `Get Screen Size` |
| `Is Element Visible` |
@@ -38,6 +38,44 @@ class ExtendedWaitingKeywords(_WaitingKeywords):
def __init__(self):
super(ExtendedWaitingKeywords, self).__init__()
+ def fast_wait_until_page_contains(self, text, excludes=None, timeout=None, error=None):
+ """Waits until ``text`` appears on current page.
+
+ Fails if any item in the ``excludes`` list appears in the current page.
+
+ Fails if ``timeout`` expires before the ``text`` appears.
+ See introduction for more information about timeout and its default value.
+
+ Arguments:
+ - ``text``: The expected value.
+ - ``excludes``: An exclusion list to be use to speed up the wait. (Default None)
+ - ``timeout``: The maximum value to wait for ``text`` to appears.
+ See `introduction` for more information about ``timeout`` and
+ its default value.
+ - ``error``: The value that would be use to override the default error message.
+
+ See also `Wait Until Page Contains Element`, `Wait For Condition`,
+ `Wait Until Element Is Visible` and BuiltIn keyword `Wait Until Keyword Succeeds`.
+
+ Examples:
+ | Fast Wait Until Page Contains | text |
+ | @{excludes} = | Create List | a | b | c |
+ | Fast Wait Until Page Contains | text | ${excludes} |
+ """
+ # pylint: disable=no-member
+ timeout = self._get_timeout_value(timeout, self._timeout_in_secs)
+ if not error:
+ error = "Text '%s' did not appear in %s" %\
+ (text, self._format_timeout(timeout))
+ excludes = excludes if excludes is not None else ()
+ # pylint: disable=protected-access
+ excluded = next((exclude for exclude in excludes
+ if self._is_text_present(exclude)), False)
+ if excluded:
+ raise AssertionError("Exclude text '%s' appears on the page." % excluded)
+ WebDriverWait(self, timeout, self._inputs['poll_frequency']).\
+ until(lambda driver: driver._is_text_present(text), error)
+
def wait_for_async_condition(self, condition, timeout=None, error=None):
"""Waits until the given asynchronous ``condition`` is true or ``timeout`` expires.
@@ -154,21 +192,20 @@ def wait_until_angular_ready(self, timeout=None, error=None):
# pylint: disable=no-member
browser = self._current_browser()
browser.set_script_timeout(timeout)
+ # pylint: disable=bare-except
try:
WebDriverWait(browser, timeout, self._inputs['poll_frequency']).\
until(lambda driver: driver.execute_async_script(script), error)
except TimeoutException:
# prevent double wait
pass
- # pylint: disable=bare-except
except:
self._debug(exc_info()[0])
# still inflight, second chance. let the browser take a deep breath...
sleep(self._inputs['browser_breath_delay'])
try:
WebDriverWait(browser, timeout, self._inputs['poll_frequency']).\
until(lambda driver: driver.execute_async_script(script), error)
- # pylint: disable=bare-except
except:
# instead of halting the process because AngularJS is not ready
# in <TIMEOUT>, we try our luck...
@@ -21,7 +21,7 @@
Extended Selenium2 Library - a web testing library with AngularJS support.
"""
-VERSION = '0.9.0'
+VERSION = '0.9.1'
def get_version():
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Extended Selenium2 Library - a web testing library with AngularJS support.
+# Copyright (c) 2015, 2016 Richard Huang <rickypc@users.noreply.github.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Extended Selenium2 Library - a web testing library with AngularJS support.
+"""
+
+from sys import path
+path.append('src')
+import unittest
+import mock
+from ExtendedSelenium2Library.locators import ExtendedElementFinder
+from selenium.webdriver.remote.webelement import WebElement
+from Selenium2Library.locators import ElementFinder
+
+
+class ExtendedElementFinderTests(unittest.TestCase):
+ """Extended element finder keyword test class."""
+
+ def setUp(self):
+ """Instantiate the extended element finder class."""
+ self.default_strategies = ['binding', 'button', 'css', 'default', 'dom',
+ 'id', 'identifier', 'jquery', 'link', 'model',
+ 'name', 'options', 'partial binding',
+ 'partial button', 'partial link', 'scLocator',
+ 'sizzle', 'tag', 'xpath']
+ self.driver = mock.Mock()
+ self.driver.session_id = 'session'
+ self.finder = ExtendedElementFinder()
+ self.finder._filter_elements = mock.Mock()
+ self.finder._find_by_css_selector = mock.Mock()
+ self.finder.BUTTON_TEXT_WRAPPER = 'return buttons;%(handler)s'
+ self.finder.NG_BINDING_WRAPPER = 'return bindings;%(handler)s'
+ self.ng_prefixes = ['ng-', 'data-ng-', 'ng_', 'x-ng-', 'ng\\:']
+ self.web_element = WebElement(self.driver, 'element', False)
+ self.finder._filter_elements.return_value = self.web_element
+ self.finder._find_by_css_selector.return_value = self.web_element
+
+ def test_should_inherit_finder(self):
+ """Extended element finder instance should inherit Selenium2 element finder instances."""
+ self.assertIsInstance(self.finder, ElementFinder)
+
+ def test_should_inherit_attributes(self):
+ """Extended element finder instance should inherit its parent attributes."""
+ self.assertEqual(self.finder._default_strategies, self.default_strategies)
+ self.assertEqual(self.finder._ng_prefixes, self.ng_prefixes)
+
+ def test_should_find_by_button_text(self):
+ """Should find by button text."""
+ button_text = 'a-button'
+ constrains = 'constrains'
+ script = "return buttons;return text.replace(/^\s+|\s+$/g,'')==='%s'" % \
+ button_text
+ tag = 'tag'
+ self.finder._find_by_button_text(self.driver, button_text, tag, constrains)
+ self.driver.execute_script.assert_called_with(script)
+ self.finder._filter_elements.assert_called_with(self.driver.execute_script.return_value,
+ tag, constrains)
+
+ def test_should_find_by_button_text_partial(self):
+ """Should find by button partial text."""
+ button_text = 'a-button'
+ constrains = 'constrains'
+ script = "return buttons;return text.indexOf('%s')>-1" % \
+ button_text
+ tag = 'tag'
+ self.finder._find_by_button_text_partial(self.driver, button_text, tag, constrains)
+ self.driver.execute_script.assert_called_with(script)
+ self.finder._filter_elements.assert_called_with(self.driver.execute_script.return_value,
+ tag, constrains)
+
+ def test_should_find_by_ng_binding(self):
+ """Should find by exact binding name."""
+ binding_name = 'a-binding'
+ constrains = 'constrains'
+ script = ("return bindings;var matcher=new RegExp('({|\\s|^|\\|)'+'%s'."
+ "replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,'\\$&')"
+ "+'(}|\\s|$|\\|)');return matcher.test(name)") % \
+ binding_name
+ tag = 'tag'
+ self.finder._find_by_ng_binding(self.driver, binding_name, tag, constrains)
+ self.driver.execute_script.assert_called_with(script)
+ self.finder._filter_elements.assert_called_with(self.driver.execute_script.return_value,
+ tag, constrains)
+
+ def test_should_find_by_ng_binding_partial(self):
+ """Should find by partial binding name."""
+ binding_name = 'a-binding'
+ constrains = 'constrains'
+ script = "return bindings;return name.indexOf('%s')>-1" % \
+ binding_name
+ tag = 'tag'
+ self.finder._find_by_ng_binding_partial(self.driver, binding_name, tag, constrains)
+ self.driver.execute_script.assert_called_with(script)
+ self.finder._filter_elements.assert_called_with(self.driver.execute_script.return_value,
+ tag, constrains)
+
+ def test_should_find_by_ng_model(self):
+ """Should find by exact model name."""
+ constrains = 'constrains'
+ model_name = 'a-model'
+ stem = 'model="%s"' % model_name
+ joiner = '%s],[' % stem
+ criteria = '[' + joiner.join(self.ng_prefixes) + stem + ']'
+ tag = 'tag'
+ self.finder._find_by_ng_model(self.driver, model_name, tag, constrains)
+ self.finder._find_by_css_selector.assert_called_with(self.driver,
+ criteria, tag,
+ constrains)
+
+ def test_should_find_by_ng_options(self):
+ """Should find by exact descriptor."""
+ constrains = 'constrains'
+ descriptor = 'an-options'
+ stem = 'options="%s"' % descriptor
+ joiner = '%s] option,[' % stem
+ criteria = '[' + joiner.join(self.ng_prefixes) + stem + '] option'
+ tag = 'tag'
+ self.finder._find_by_ng_options(self.driver, descriptor, tag, constrains)
+ self.finder._find_by_css_selector.assert_called_with(self.driver,
+ criteria, tag,
+ constrains)

0 comments on commit 280dd00

Please sign in to comment.