Skip to content

Commit

Permalink
Merge pull request #42 from Telefonica/fix/wait_until
Browse files Browse the repository at this point in the history
Fix wait_until methods when the element has parent
  • Loading branch information
rgonalo authored Nov 17, 2016
2 parents af4453d + 7a034bd commit 199ed1f
Show file tree
Hide file tree
Showing 5 changed files with 222 additions and 37 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ v1.1.3
- New config property 'binary' in [Firefox] section to configure the firefox binary path
- Allow to configure visual baseline directory in ConfigFiles class (default: output/visualtests/baseline)
- Delete IE and Edge cookies after tests
- Fix wait_until_element_visible and wait_until_element_not_visible methods when the page element has a parent element

v1.1.2
------
Expand Down
132 changes: 132 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
APP = toolium
VERSION ?= $(shell cat VERSION)
RELEASE ?= $(shell git log --pretty=oneline | wc -l | tr -d ' ')
ARCH = noarch
PACKAGE = $(APP)-$(VERSION)-$(RELEASE).$(ARCH).rpm
ROOT = $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
MKD2PDF ?= $(shell which markdown-pdf)
VIRTUALENV ?= virtualenv
TEST = tests
SPHINXBUILD = sphinx-build
SPHINXSOURCEDIR = docs
SPHINXBUILDDIR = docs/build

ifeq ($(OS),Windows_NT)
BIN = Scripts
LIB = Lib
TGZ_EXT = zip
PYTHON ?= $(shell which python).exe
PYTHON_EXE ?= $(shell where python | head -n1)
else
BIN = bin
LIB = lib/python2.7
TGZ_EXT = tar.gz
PYTHON ?= $(shell which python2.7)
PYTHON_EXE = python2.7
endif

TMP=$(ROOT)/tmp
VENV_PREFIX = $(TMP)/.venv
VENV = $(VENV_PREFIX)/$(APP)
REQ = requirements.txt

TESTREQ = requirements_dev.txt

UNIT_TEST_ARGS=--nocapture --with-xunit --xunit-file=$(ROOT)/dist/nosetest.xml
COVERAGE_ARGS=--with-coverage --cover-erase --cover-package=$(APP) \
--cover-branches --cover-xml \
--cover-xml-file=$(ROOT)/dist/coverage.xml

all: default

default:
@echo
@echo "Welcome to '$(APP)' software package:"
@echo
@echo "usage: make <command>"
@echo
@echo "commands:"
@echo " clean - Remove generated files and directories"
@echo " venv - Create and update virtual environments"
@echo " install - Install application"
@echo " sdist - Build a tar.gz software distribution of the package"
# @echo " rpm - Create $(PACKAGE) rpm"
@echo " egg - Create python egg"
@echo " unittest - Execute unit tests"
@echo " doc - Build sphinx documentation"
@echo " coverage - Execute unittests and code coverage"
@echo

init:
mkdir -p $(ROOT)/dist
# mkdir -p $(TMP)/rpmbuild/SOURCES
# mkdir -p $(TMP)/rpmbuild/BUILD
# mkdir -p $(TMP)/rpmbuild/RPMS

sdist: init venv
@echo ">>> Creating source distribution..."
$(VENV)/$(BIN)/python setup.py sdist
@echo ">>> OK. TGZ generated in $(ROOT)/dist"
@echo

disabled-rpm: init sdist
@echo ">>> Creating RPM package..."
cp $(ROOT)/dist/$(APP)-$(VERSION).${TGZ_EXT} $(TMP)/rpmbuild/SOURCES
rpmbuild -bb $(APP).spec \
--define "version $(VERSION)" \
--define "release $(RELEASE)" \
--define "arch $(ARCH)" \
--define "_target_os linux" \
--define "_topdir $(TMP)/rpmbuild" \
--define "buildroot $(TMP)/rpmbuild/BUILDROOT" \
--define "__python $(PYTHON)" \
--define "python_sitelib $(VENV)/$(LIB)/site-packages" \
--define "_sysconfdir /etc" \
--define "_bindir /usr/bin" \
--nodeps \
--buildroot=$(TMP)/rpmbuild/BUILDROOT

cp $(TMP)/rpmbuild/RPMS/$(ARCH)/$(PACKAGE) $(ROOT)/dist
@echo ">>> OK. RPM generated in $(ROOT)/dist"
@echo

venv: $(VENV)

$(VENV): $(REQ) $(TESTREQ)
mkdir -p $@; \
export GIT_SSL_NO_VERIFY=true; \
$(VIRTUALENV) --no-site-packages --distribute -p $(PYTHON) $@; \
$@/$(BIN)/pip install --upgrade -r $(REQ); \
$@/$(BIN)/pip install --upgrade -r $(TESTREQ); \

unittest: init venv
$(VENV)/$(BIN)/nosetests $(UNIT_TEST_ARGS)

coverage: init venv
$(VENV)/$(BIN)/nosetests $(COVERAGE_ARGS) $(UNIT_TEST_ARGS)
@echo ">>> OK. Coverage reports generated in $(ROOT)/dist"

# Just for development purposes. It uses your active python2.7
# Remember to update your requirements if needed
egg:
$(PYTHON_EXE) setup.py bdist_egg

# Just for development purposes. It uses your active python2.7
# Remember to update your requirements if needed
install:
$(PYTHON_EXE) setup.py install

doc: venv
@echo ">>> Cleaning sphinx doc files..."
rm -rf $(SPHINXBUILDDIR)/html
@echo ">>> Generating doc files..."
$(VENV)/$(BIN)/$(SPHINXBUILD) -b html $(SPHINXSOURCEDIR) $(SPHINXBUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(SPHINXBUILDDIR)/html."

clean:
@echo ">>> Cleaning temporal files..."
rm -rf $(TMP) dist/ *.egg-info/ build/
@echo

.PHONY: all clean venv install sdist egg unittest doc coverage
14 changes: 8 additions & 6 deletions toolium/pageelements/page_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ def web_element(self):
try:
self._find_web_element()
except NoSuchElementException as exception:
msg = "Page element of type '{}' with locator {} not found".format(type(self).__name__, self.locator)
parent_msg = " and parent locator '{}'".format(self.parent) if self.parent else ''
msg = "Page element of type '{}' with locator {}{} not found".format(type(self).__name__, self.locator,
parent_msg)
self.logger.error(msg)
exception.msg += "\n {}".format(msg)
raise exception
Expand Down Expand Up @@ -92,10 +94,11 @@ def wait_until_visible(self, timeout=10):
:returns: page element instance
"""
try:
self._web_element = self.utils.wait_until_element_visible(self.locator, timeout)
self.utils.wait_until_element_visible(self, timeout)
except TimeoutException as exception:
msg = "Page element of type '{}' with locator {} not found or is not visible after {} seconds".format(
type(self).__name__, self.locator, timeout)
parent_msg = " and parent locator '{}'".format(self.parent, timeout) if self.parent else ''
msg = "Page element of type '{}' with locator {}{} not found or is not visible after {} seconds".format(
type(self).__name__, self.locator, parent_msg, timeout)
self.logger.error(msg)
exception.msg += "\n {}".format(msg)
raise exception
Expand All @@ -108,8 +111,7 @@ def wait_until_not_visible(self, timeout=10):
:returns: page element instance
"""
try:
web_element = self.utils.wait_until_element_not_visible(self.locator, timeout)
self._web_element = web_element if web_element else None
self.utils.wait_until_element_not_visible(self, timeout)
except TimeoutException as exception:
msg = "Page element of type '{}' with locator {} is still visible after {} seconds".format(
type(self).__name__, self.locator, timeout)
Expand Down
1 change: 0 additions & 1 deletion toolium/test/pageelements/test_page_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ def test_wait_until_visible(driver_wrapper):
page_element = RegisterPageObject(driver_wrapper).username
element = page_element.wait_until_visible()

assert element._web_element == mock_element
assert element == page_element


Expand Down
111 changes: 81 additions & 30 deletions toolium/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

import requests
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException, TimeoutException

Expand Down Expand Up @@ -118,35 +117,46 @@ def discard_logcat_logs(self):
except Exception:
pass

def wait_until_element_visible(self, locator, timeout=10):
"""Search element by locator and wait until it is visible
def _expected_condition_find_element(self, element):
"""Tries to find the element, but does not thrown an exception if the element is not found
:param locator: locator element
:param timeout: max time to wait
:returns: the element if it is visible
:param element: PageElement or element locator as a tuple (locator_type, locator_value) to be found
:returns: the web element if it has been found or False
:rtype: selenium.webdriver.remote.webelement.WebElement or appium.webdriver.webelement.WebElement
"""
return WebDriverWait(self.driver_wrapper.driver, timeout).until(
expected_conditions.visibility_of_element_located(locator))
from toolium.pageelements.page_element import PageElement
web_element = False
try:
if isinstance(element, PageElement):
# Use _find_web_element() instead of web_element to avoid logging error message
element._find_web_element()
web_element = element._web_element
elif isinstance(element, tuple):
web_element = self.driver_wrapper.driver.find_element(*element)
except NoSuchElementException:
pass
return web_element

def wait_until_element_not_visible(self, locator, timeout=10):
"""Search element by locator and wait until it is not visible
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
:param locator: locator element
:param timeout: max time to wait
:returns: the element if it exists but is not visible or False
: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
:rtype: selenium.webdriver.remote.webelement.WebElement or appium.webdriver.webelement.WebElement
"""
# Remove implicit wait
self.driver_wrapper.driver.implicitly_wait(0)
# Wait for invisibility
element = WebDriverWait(self.driver_wrapper.driver, timeout).until(
expected_conditions.invisibility_of_element_located(locator))
# Restore implicit wait from properties
self.set_implicit_wait()
return element
web_element = self._expected_condition_find_element(element)
return web_element if web_element and web_element.is_displayed() else 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
def get_first_element(self, elements):
: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
"""
web_element = self._expected_condition_find_element(element)
return True if not web_element or web_element.is_displayed() == False else False

def _expected_condition_find_first_element(self, elements):
"""Try to find sequentially the elements of the list and return the first element found
:param elements: list of PageElements or element locators as a tuple (locator_type, locator_value) to be found
Expand All @@ -168,6 +178,54 @@ def get_first_element(self, elements):
pass
return element_found

def _wait_until(self, condition_method, condition_input, timeout=10):
"""
Common method to wait until condition met
:param condition_method: method to check the condition
:param condition_input: parameter that will be passed to the condition method
:param timeout: max time to wait
:returns: condition method response
"""
# Remove implicit wait
self.driver_wrapper.driver.implicitly_wait(0)
# Wait for condition
condition_response = WebDriverWait(self.driver_wrapper.driver, timeout).until(
lambda s: condition_method(condition_input))
# Restore implicit wait from properties
self.set_implicit_wait()
return condition_response

def wait_until_element_present(self, element, timeout=10):
"""Search element and wait until it is found
: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 present or False
:rtype: selenium.webdriver.remote.webelement.WebElement or appium.webdriver.webelement.WebElement
"""
return self._wait_until(self._expected_condition_find_element, element, timeout)

def wait_until_element_visible(self, element, timeout=10):
"""Search element and wait until it is visible
: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 visible or False
:rtype: selenium.webdriver.remote.webelement.WebElement or appium.webdriver.webelement.WebElement
"""
return self._wait_until(self._expected_condition_find_element_visible, element, timeout)

def wait_until_element_not_visible(self, element, timeout=10):
"""Search element and wait until it is not visible
: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 exists but is not visible or False
:rtype: selenium.webdriver.remote.webelement.WebElement or appium.webdriver.webelement.WebElement
"""
return self._wait_until(self._expected_condition_find_element_not_visible, element, timeout)

def wait_until_first_element_is_found(self, elements, timeout=10):
"""Search list of elements and wait until one of them is found
Expand All @@ -177,20 +235,13 @@ def wait_until_first_element_is_found(self, elements, timeout=10):
:returns: first element found
:rtype: toolium.pageelements.PageElement or tuple
"""
# Remove implicit wait
self.driver_wrapper.driver.implicitly_wait(0)
# Wait for elements
try:
element = WebDriverWait(self.driver_wrapper.driver, timeout).until(
lambda s: self.get_first_element(elements))
return self._wait_until(self._expected_condition_find_first_element, elements, timeout)
except TimeoutException as exception:
msg = "None of the page elements has been found after {} seconds".format(timeout)
self.logger.error(msg)
exception.msg += "\n {}".format(msg)
raise exception
# Restore implicit wait from properties
self.set_implicit_wait()
return element

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

0 comments on commit 199ed1f

Please sign in to comment.