Thanks. Added to toaster-next and sent upstream to bitbake-devel.
Elliot On 14 July 2016 at 16:56, Aníbal Limón <[email protected]> wrote: > In order to reuse selenium helper outside django environment, > add a new module with base class SeleniumTestCaseBase only > with inherit of unittest.TestCase for reuse selenium helper > in functional testing of Toaster outside django environment. > > Add class SeleniumTestCase with multiple inherit of > StaticLiveServerTestCase and SeleniumTestCaseBase for don't > broke things. > > Signed-off-by: Aníbal Limón <[email protected]> > --- > .../lib/toaster/tests/browser/selenium_helpers.py | 187 > +----------------- > .../toaster/tests/browser/selenium_helpers_base.py | 216 > +++++++++++++++++++++ > 2 files changed, 221 insertions(+), 182 deletions(-) > create mode 100644 > bitbake/lib/toaster/tests/browser/selenium_helpers_base.py > > diff --git a/bitbake/lib/toaster/tests/browser/selenium_helpers.py > b/bitbake/lib/toaster/tests/browser/selenium_helpers.py > index ef07858..ddb43fd 100644 > --- a/bitbake/lib/toaster/tests/browser/selenium_helpers.py > +++ b/bitbake/lib/toaster/tests/browser/selenium_helpers.py > @@ -23,195 +23,18 @@ > # modified from Patchwork, released under the same licence terms as > Toaster: > # > https://github.com/dlespiau/patchwork/blob/master/patchwork/tests.browser.py > > +from django.contrib.staticfiles.testing import StaticLiveServerTestCase > +from tests.browser.selenium_helpers_base import SeleniumTestCaseBase > + > """ > Helper methods for creating Toaster Selenium tests which run within > the context of Django unit tests. > """ > > -import os > -import time > - > -from django.contrib.staticfiles.testing import StaticLiveServerTestCase > -from selenium import webdriver > -from selenium.webdriver.support.ui import WebDriverWait > -from selenium.webdriver.common.desired_capabilities import > DesiredCapabilities > -from selenium.common.exceptions import NoSuchElementException, \ > - StaleElementReferenceException, TimeoutException > - > -def create_selenium_driver(browser='chrome'): > - # set default browser string based on env (if available) > - env_browser = os.environ.get('TOASTER_TESTS_BROWSER') > - if env_browser: > - browser = env_browser > - > - if browser == 'chrome': > - return webdriver.Chrome( > - service_args=["--verbose", "--log-path=selenium.log"] > - ) > - elif browser == 'firefox': > - return webdriver.Firefox() > - elif browser == 'marionette': > - capabilities = DesiredCapabilities.FIREFOX > - capabilities['marionette'] = True > - return webdriver.Firefox(capabilities=capabilities) > - elif browser == 'ie': > - return webdriver.Ie() > - elif browser == 'phantomjs': > - return webdriver.PhantomJS() > - else: > - msg = 'Selenium driver for browser %s is not available' % browser > - raise RuntimeError(msg) > - > -class Wait(WebDriverWait): > - """ > - Subclass of WebDriverWait with predetermined timeout and poll > - frequency. Also deals with a wider variety of exceptions. > - """ > - _TIMEOUT = 10 > - _POLL_FREQUENCY = 0.5 > - > - def __init__(self, driver): > - super(Wait, self).__init__(driver, self._TIMEOUT, > self._POLL_FREQUENCY) > - > - def until(self, method, message=''): > - """ > - Calls the method provided with the driver as an argument until the > - return value is not False. > - """ > - > - end_time = time.time() + self._timeout > - while True: > - try: > - value = method(self._driver) > - if value: > - return value > - except NoSuchElementException: > - pass > - except StaleElementReferenceException: > - pass > - > - time.sleep(self._poll) > - if time.time() > end_time: > - break > - > - raise TimeoutException(message) > - > - def until_not(self, method, message=''): > - """ > - Calls the method provided with the driver as an argument until the > - return value is False. > - """ > - > - end_time = time.time() + self._timeout > - while True: > - try: > - value = method(self._driver) > - if not value: > - return value > - except NoSuchElementException: > - return True > - except StaleElementReferenceException: > - pass > - > - time.sleep(self._poll) > - if time.time() > end_time: > - break > - > - raise TimeoutException(message) > - > -class SeleniumTestCase(StaticLiveServerTestCase): > +class SeleniumTestCase(SeleniumTestCaseBase, StaticLiveServerTestCase): > """ > NB StaticLiveServerTestCase is used as the base test case so that > static files are served correctly in a Selenium test run context; see > > https://docs.djangoproject.com/en/1.9/ref/contrib/staticfiles/#specialized-test-case-to-support-live-testing > """ > - > - @classmethod > - def setUpClass(cls): > - """ Create a webdriver driver at the class level """ > - > - super(SeleniumTestCase, cls).setUpClass() > - > - # instantiate the Selenium webdriver once for all the test methods > - # in this test case > - cls.driver = create_selenium_driver() > - cls.driver.maximize_window() > - > - @classmethod > - def tearDownClass(cls): > - """ Clean up webdriver driver """ > - > - cls.driver.quit() > - super(SeleniumTestCase, cls).tearDownClass() > - > - def get(self, url): > - """ > - Selenium requires absolute URLs, so convert Django URLs returned > - by resolve() or similar to absolute ones and get using the > - webdriver instance. > - > - url: a relative URL > - """ > - abs_url = '%s%s' % (self.live_server_url, url) > - self.driver.get(abs_url) > - > - def find(self, selector): > - """ Find single element by CSS selector """ > - return self.driver.find_element_by_css_selector(selector) > - > - def find_all(self, selector): > - """ Find all elements matching CSS selector """ > - return self.driver.find_elements_by_css_selector(selector) > - > - def element_exists(self, selector): > - """ > - Return True if one element matching selector exists, > - False otherwise > - """ > - return len(self.find_all(selector)) == 1 > - > - def focused_element(self): > - """ Return the element which currently has focus on the page """ > - return self.driver.switch_to.active_element > - > - def wait_until_present(self, selector): > - """ Wait until element matching CSS selector is on the page """ > - is_present = lambda driver: self.find(selector) > - msg = 'An element matching "%s" should be on the page' % selector > - element = Wait(self.driver).until(is_present, msg) > - return element > - > - def wait_until_visible(self, selector): > - """ Wait until element matching CSS selector is visible on the > page """ > - is_visible = lambda driver: self.find(selector).is_displayed() > - msg = 'An element matching "%s" should be visible' % selector > - Wait(self.driver).until(is_visible, msg) > - return self.find(selector) > - > - def wait_until_focused(self, selector): > - """ Wait until element matching CSS selector has focus """ > - is_focused = \ > - lambda driver: self.find(selector) == self.focused_element() > - msg = 'An element matching "%s" should be focused' % selector > - Wait(self.driver).until(is_focused, msg) > - return self.find(selector) > - > - def enter_text(self, selector, value): > - """ Insert text into element matching selector """ > - # note that keyup events don't occur until the element is clicked > - # (in the case of <input type="text"...>, for example), so > simulate > - # user clicking the element before inserting text into it > - field = self.click(selector) > - > - field.send_keys(value) > - return field > - > - def click(self, selector): > - """ Click on element which matches CSS selector """ > - element = self.wait_until_visible(selector) > - element.click() > - return element > - > - def get_page_source(self): > - """ Get raw HTML for the current page """ > - return self.driver.page_source > + pass > diff --git a/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py > b/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py > new file mode 100644 > index 0000000..c4161d7 > --- /dev/null > +++ b/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py > @@ -0,0 +1,216 @@ > +#! /usr/bin/env python > +# ex:ts=4:sw=4:sts=4:et > +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- > +# > +# BitBake Toaster Implementation > +# > +# Copyright (C) 2013-2016 Intel Corporation > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License version 2 as > +# published by the Free Software Foundation. > +# > +# 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 General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License along > +# with this program; if not, write to the Free Software Foundation, Inc., > +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > +# > +# The Wait class and some of SeleniumDriverHelper and SeleniumTestCase are > +# modified from Patchwork, released under the same licence terms as > Toaster: > +# > https://github.com/dlespiau/patchwork/blob/master/patchwork/tests.browser.py > + > +""" > +Base helper methods for creating Toaster Selenium tests. > +""" > + > +import os > +import time > +import unittest > + > +from selenium import webdriver > +from selenium.webdriver.support.ui import WebDriverWait > +from selenium.webdriver.common.desired_capabilities import > DesiredCapabilities > +from selenium.common.exceptions import NoSuchElementException, \ > + StaleElementReferenceException, TimeoutException > + > +def create_selenium_driver(browser='chrome'): > + # set default browser string based on env (if available) > + env_browser = os.environ.get('TOASTER_TESTS_BROWSER') > + if env_browser: > + browser = env_browser > + > + if browser == 'chrome': > + return webdriver.Chrome( > + service_args=["--verbose", "--log-path=selenium.log"] > + ) > + elif browser == 'firefox': > + return webdriver.Firefox() > + elif browser == 'marionette': > + capabilities = DesiredCapabilities.FIREFOX > + capabilities['marionette'] = True > + return webdriver.Firefox(capabilities=capabilities) > + elif browser == 'ie': > + return webdriver.Ie() > + elif browser == 'phantomjs': > + return webdriver.PhantomJS() > + else: > + msg = 'Selenium driver for browser %s is not available' % browser > + raise RuntimeError(msg) > + > +class Wait(WebDriverWait): > + """ > + Subclass of WebDriverWait with predetermined timeout and poll > + frequency. Also deals with a wider variety of exceptions. > + """ > + _TIMEOUT = 10 > + _POLL_FREQUENCY = 0.5 > + > + def __init__(self, driver): > + super(Wait, self).__init__(driver, self._TIMEOUT, > self._POLL_FREQUENCY) > + > + def until(self, method, message=''): > + """ > + Calls the method provided with the driver as an argument until the > + return value is not False. > + """ > + > + end_time = time.time() + self._timeout > + while True: > + try: > + value = method(self._driver) > + if value: > + return value > + except NoSuchElementException: > + pass > + except StaleElementReferenceException: > + pass > + > + time.sleep(self._poll) > + if time.time() > end_time: > + break > + > + raise TimeoutException(message) > + > + def until_not(self, method, message=''): > + """ > + Calls the method provided with the driver as an argument until the > + return value is False. > + """ > + > + end_time = time.time() + self._timeout > + while True: > + try: > + value = method(self._driver) > + if not value: > + return value > + except NoSuchElementException: > + return True > + except StaleElementReferenceException: > + pass > + > + time.sleep(self._poll) > + if time.time() > end_time: > + break > + > + raise TimeoutException(message) > + > +class SeleniumTestCaseBase(unittest.TestCase): > + """ > + NB StaticLiveServerTestCase is used as the base test case so that > + static files are served correctly in a Selenium test run context; see > + > https://docs.djangoproject.com/en/1.9/ref/contrib/staticfiles/#specialized-test-case-to-support-live-testing > + """ > + > + @classmethod > + def setUpClass(cls): > + """ Create a webdriver driver at the class level """ > + > + super(SeleniumTestCaseBase, cls).setUpClass() > + > + # instantiate the Selenium webdriver once for all the test methods > + # in this test case > + cls.driver = create_selenium_driver() > + cls.driver.maximize_window() > + > + @classmethod > + def tearDownClass(cls): > + """ Clean up webdriver driver """ > + > + cls.driver.quit() > + super(SeleniumTestCaseBase, cls).tearDownClass() > + > + def get(self, url): > + """ > + Selenium requires absolute URLs, so convert Django URLs returned > + by resolve() or similar to absolute ones and get using the > + webdriver instance. > + > + url: a relative URL > + """ > + abs_url = '%s%s' % (self.live_server_url, url) > + self.driver.get(abs_url) > + > + def find(self, selector): > + """ Find single element by CSS selector """ > + return self.driver.find_element_by_css_selector(selector) > + > + def find_all(self, selector): > + """ Find all elements matching CSS selector """ > + return self.driver.find_elements_by_css_selector(selector) > + > + def element_exists(self, selector): > + """ > + Return True if one element matching selector exists, > + False otherwise > + """ > + return len(self.find_all(selector)) == 1 > + > + def focused_element(self): > + """ Return the element which currently has focus on the page """ > + return self.driver.switch_to.active_element > + > + def wait_until_present(self, selector): > + """ Wait until element matching CSS selector is on the page """ > + is_present = lambda driver: self.find(selector) > + msg = 'An element matching "%s" should be on the page' % selector > + element = Wait(self.driver).until(is_present, msg) > + return element > + > + def wait_until_visible(self, selector): > + """ Wait until element matching CSS selector is visible on the > page """ > + is_visible = lambda driver: self.find(selector).is_displayed() > + msg = 'An element matching "%s" should be visible' % selector > + Wait(self.driver).until(is_visible, msg) > + return self.find(selector) > + > + def wait_until_focused(self, selector): > + """ Wait until element matching CSS selector has focus """ > + is_focused = \ > + lambda driver: self.find(selector) == self.focused_element() > + msg = 'An element matching "%s" should be focused' % selector > + Wait(self.driver).until(is_focused, msg) > + return self.find(selector) > + > + def enter_text(self, selector, value): > + """ Insert text into element matching selector """ > + # note that keyup events don't occur until the element is clicked > + # (in the case of <input type="text"...>, for example), so > simulate > + # user clicking the element before inserting text into it > + field = self.click(selector) > + > + field.send_keys(value) > + return field > + > + def click(self, selector): > + """ Click on element which matches CSS selector """ > + element = self.wait_until_visible(selector) > + element.click() > + return element > + > + def get_page_source(self): > + """ Get raw HTML for the current page """ > + return self.driver.page_source > -- > 2.1.4 > > -- Elliot Smith Software Engineer Intel Open Source Technology Centre
-- _______________________________________________ toaster mailing list [email protected] https://lists.yoctoproject.org/listinfo/toaster
