Skip to content

Commit

Permalink
Merge pull request #68 from Telefonica/feature/wait_clickable
Browse files Browse the repository at this point in the history
Feature/wait clickable
  • Loading branch information
rgonalo authored Mar 10, 2017
2 parents 82c1c6f + 6b43cce commit e35c538
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 7 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ Toolium Changelog
v1.2.3
------

*In development*
*Release date: 2017-03-10*

- Save *geckodriver.log* file in output folder
- Fix MagickEngine name error when using an old version of needle
- Add *wait_until_clickable* method to Utils and PageElement classes to search for an element and wait until it is
clickable

v1.2.2
------
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.2.3-dev
1.2.3
2 changes: 1 addition & 1 deletion docs/visual_testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ To achieve this goal, this tool follows these steps:
- It takes a screenshot of the current web page or mobile screen (a full screenshot or a single element).
- Then, if exists a previous capture with the same name, it compares both of them and shows their differences.
- If not, it saves the screenshot to be used as a base in later executions. Probably these images might be reviewed
manually to assure that can be used as expected result.
manually to assure that can be used as expected result.

As web pages and mobile applications look different when using different browsers, mobile devices, resolutions, etc.
Toolium provides you with a way of storing different base images, called baselines, through a configuration property
Expand Down
13 changes: 11 additions & 2 deletions toolium/pageelements/button_page_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
limitations under the License.
"""

from selenium.common.exceptions import StaleElementReferenceException
from toolium.pageelements.page_element import PageElement


Expand All @@ -26,12 +27,20 @@ def text(self):
:returns: element text value
"""
return self.web_element.text
try:
return self.web_element.text
except StaleElementReferenceException:
# Retry if element has changed
return self.web_element.text

def click(self):
"""Click the element
:returns: page element instance
"""
self.web_element.click()
try:
self.wait_until_clickable().web_element.click()
except StaleElementReferenceException:
# Retry if element has changed
self.web_element.click()
return self
16 changes: 16 additions & 0 deletions toolium/pageelements/page_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,22 @@ def wait_until_not_visible(self, timeout=10):
raise exception
return self

def wait_until_clickable(self, timeout=10):
"""Search element and wait until it is clickable
:param timeout: max time to wait
:returns: page element instance
"""
try:
self.utils.wait_until_element_clickable(self, timeout)
except TimeoutException as exception:
parent_msg = " and parent locator '{}'".format(self.parent) if self.parent else ''
msg = "Page element of type '%s' with locator %s%s not found or is not clickable after %s seconds"
self.logger.error(msg, type(self).__name__, self.locator, parent_msg, timeout)
exception.msg += "\n {}".format(msg % (type(self).__name__, self.locator, parent_msg, timeout))
raise exception
return self

def assert_screenshot(self, filename, threshold=0, exclude_elements=[], force=False):
"""Assert that a screenshot of the element is the same as a screenshot on disk, within a given threshold.
Expand Down
20 changes: 20 additions & 0 deletions toolium/test/pageelements/test_page_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,26 @@ def test_wait_until_not_visible_exception(driver_wrapper):
"visible after 10 seconds" in str(excinfo.value)


def test_wait_until_clickable(driver_wrapper):
driver_wrapper.utils.wait_until_element_clickable = mock.MagicMock(return_value=mock_element)

page_element = RegisterPageObject(driver_wrapper).username
element = page_element.wait_until_clickable()

assert element == page_element


def test_wait_until_clickable_exception(driver_wrapper):
driver_wrapper.utils.wait_until_element_clickable = mock.MagicMock()
driver_wrapper.utils.wait_until_element_clickable.side_effect = TimeoutException('Unknown')

page_element = RegisterPageObject(driver_wrapper).username
with pytest.raises(TimeoutException) as excinfo:
page_element.wait_until_clickable()
assert "Page element of type 'PageElement' with locator ('xpath', '//input[0]') not found or is not " \
"clickable after 10 seconds" in str(excinfo.value)


@mock.patch('toolium.visual_test.VisualTest.__init__', return_value=None)
@mock.patch('toolium.visual_test.VisualTest.assert_screenshot')
def test_assert_screenshot(visual_assert_screenshot, visual_init, driver_wrapper):
Expand Down
30 changes: 28 additions & 2 deletions toolium/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ def _expected_condition_find_element(self, element):
return web_element

def _expected_condition_find_element_visible(self, element):
"""Tries to find the element and checks that it is visible, but does not thrown an exception if the element is not found
"""Tries to find the element and checks that it is visible, but does not thrown an exception if the element is
not found
:param element: PageElement or element locator as a tuple (locator_type, locator_value) to be found
:returns: the web element if it is visible or False
Expand All @@ -153,7 +154,8 @@ def _expected_condition_find_element_visible(self, element):
return False

def _expected_condition_find_element_not_visible(self, element):
"""Tries to find the element and checks that it is visible, but does not thrown an exception if the element is not found
"""Tries to find the element and checks that it is visible, but does not thrown an exception if the element is
not found
:param element: PageElement or element locator as a tuple (locator_type, locator_value) to be found
:returns: True if the web element is not found or it is not visible
Expand Down Expand Up @@ -187,6 +189,20 @@ def _expected_condition_find_first_element(self, elements):
pass
return element_found

def _expected_condition_find_element_clickable(self, element):
"""Tries to find the element and checks that it is clickable, but does not thrown an exception if the element
is not found
:param element: PageElement or element locator as a tuple (locator_type, locator_value) to be found
:returns: the web element if it is clickable or False
:rtype: selenium.webdriver.remote.webelement.WebElement or appium.webdriver.webelement.WebElement
"""
web_element = self._expected_condition_find_element_visible(element)
try:
return web_element if web_element and web_element.is_enabled() else False
except StaleElementReferenceException:
return False

def _wait_until(self, condition_method, condition_input, timeout=10):
"""
Common method to wait until condition met
Expand Down Expand Up @@ -252,6 +268,16 @@ def wait_until_first_element_is_found(self, elements, timeout=10):
exception.msg += "\n {}".format(msg % timeout)
raise exception

def wait_until_element_clickable(self, element, timeout=10):
"""Search element and wait until it is clickable
:param element: PageElement or element locator as a tuple (locator_type, locator_value) to be found
:param timeout: max time to wait
:returns: the web element if it is clickable or False
:rtype: selenium.webdriver.remote.webelement.WebElement or appium.webdriver.webelement.WebElement
"""
return self._wait_until(self._expected_condition_find_element_clickable, element, timeout)

def get_remote_node(self):
"""Return the remote node that it's executing the actual test session
Expand Down

0 comments on commit e35c538

Please sign in to comment.