summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2016-08-01 09:38:23 +0100
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-08-01 09:38:35 +0100
commitaa2d94542336f359a1205520e844c1bcff53712b (patch)
tree0e09d8049ec4e2e486026764173d6ea6ee4ccfac /bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
parent5b61fa04a335a4fdefd435dc25d4bac41ee21e39 (diff)
downloadpoky-aa2d94542336f359a1205520e844c1bcff53712b.tar.gz
bitbake: lib/toaster: Fix missing new files from previous commits
(Bitbake rev: f77e6f21a2cc57a3fcb5970437e55cfae39849a3) Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake/lib/toaster/tests/browser/selenium_helpers_base.py')
-rw-r--r--bitbake/lib/toaster/tests/browser/selenium_helpers_base.py218
1 files changed, 218 insertions, 0 deletions
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 0000000000..14e9c15648
--- /dev/null
+++ b/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
@@ -0,0 +1,218 @@
1#! /usr/bin/env python
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# BitBake Toaster Implementation
6#
7# Copyright (C) 2013-2016 Intel Corporation
8#
9# This program is free software; you can redistribute it and/or modify
10# it under the terms of the GNU General Public License version 2 as
11# published by the Free Software Foundation.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along
19# with this program; if not, write to the Free Software Foundation, Inc.,
20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21#
22# The Wait class and some of SeleniumDriverHelper and SeleniumTestCase are
23# modified from Patchwork, released under the same licence terms as Toaster:
24# https://github.com/dlespiau/patchwork/blob/master/patchwork/tests.browser.py
25
26"""
27Helper methods for creating Toaster Selenium tests which run within
28the context of Django unit tests.
29"""
30
31import os
32import time
33import unittest
34
35from django.contrib.staticfiles.testing import StaticLiveServerTestCase
36from selenium import webdriver
37from selenium.webdriver.support.ui import WebDriverWait
38from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
39from selenium.common.exceptions import NoSuchElementException, \
40 StaleElementReferenceException, TimeoutException
41
42def create_selenium_driver(browser='chrome'):
43 # set default browser string based on env (if available)
44 env_browser = os.environ.get('TOASTER_TESTS_BROWSER')
45 if env_browser:
46 browser = env_browser
47
48 if browser == 'chrome':
49 return webdriver.Chrome(
50 service_args=["--verbose", "--log-path=selenium.log"]
51 )
52 elif browser == 'firefox':
53 return webdriver.Firefox()
54 elif browser == 'marionette':
55 capabilities = DesiredCapabilities.FIREFOX
56 capabilities['marionette'] = True
57 return webdriver.Firefox(capabilities=capabilities)
58 elif browser == 'ie':
59 return webdriver.Ie()
60 elif browser == 'phantomjs':
61 return webdriver.PhantomJS()
62 else:
63 msg = 'Selenium driver for browser %s is not available' % browser
64 raise RuntimeError(msg)
65
66class Wait(WebDriverWait):
67 """
68 Subclass of WebDriverWait with predetermined timeout and poll
69 frequency. Also deals with a wider variety of exceptions.
70 """
71 _TIMEOUT = 10
72 _POLL_FREQUENCY = 0.5
73
74 def __init__(self, driver):
75 super(Wait, self).__init__(driver, self._TIMEOUT, self._POLL_FREQUENCY)
76
77 def until(self, method, message=''):
78 """
79 Calls the method provided with the driver as an argument until the
80 return value is not False.
81 """
82
83 end_time = time.time() + self._timeout
84 while True:
85 try:
86 value = method(self._driver)
87 if value:
88 return value
89 except NoSuchElementException:
90 pass
91 except StaleElementReferenceException:
92 pass
93
94 time.sleep(self._poll)
95 if time.time() > end_time:
96 break
97
98 raise TimeoutException(message)
99
100 def until_not(self, method, message=''):
101 """
102 Calls the method provided with the driver as an argument until the
103 return value is False.
104 """
105
106 end_time = time.time() + self._timeout
107 while True:
108 try:
109 value = method(self._driver)
110 if not value:
111 return value
112 except NoSuchElementException:
113 return True
114 except StaleElementReferenceException:
115 pass
116
117 time.sleep(self._poll)
118 if time.time() > end_time:
119 break
120
121 raise TimeoutException(message)
122
123class SeleniumTestCaseBase(unittest.TestCase):
124 """
125 NB StaticLiveServerTestCase is used as the base test case so that
126 static files are served correctly in a Selenium test run context; see
127 https://docs.djangoproject.com/en/1.9/ref/contrib/staticfiles/#specialized-test-case-to-support-live-testing
128 """
129
130 @classmethod
131 def setUpClass(cls):
132 """ Create a webdriver driver at the class level """
133
134 super(SeleniumTestCaseBase, cls).setUpClass()
135
136 # instantiate the Selenium webdriver once for all the test methods
137 # in this test case
138 cls.driver = create_selenium_driver()
139 cls.driver.maximize_window()
140
141 @classmethod
142 def tearDownClass(cls):
143 """ Clean up webdriver driver """
144
145 cls.driver.quit()
146 super(SeleniumTestCaseBase, cls).tearDownClass()
147
148 def get(self, url):
149 """
150 Selenium requires absolute URLs, so convert Django URLs returned
151 by resolve() or similar to absolute ones and get using the
152 webdriver instance.
153
154 url: a relative URL
155 """
156 abs_url = '%s%s' % (self.live_server_url, url)
157 self.driver.get(abs_url)
158
159 def find(self, selector):
160 """ Find single element by CSS selector """
161 return self.driver.find_element_by_css_selector(selector)
162
163 def find_all(self, selector):
164 """ Find all elements matching CSS selector """
165 return self.driver.find_elements_by_css_selector(selector)
166
167 def element_exists(self, selector):
168 """
169 Return True if one element matching selector exists,
170 False otherwise
171 """
172 return len(self.find_all(selector)) == 1
173
174 def focused_element(self):
175 """ Return the element which currently has focus on the page """
176 return self.driver.switch_to.active_element
177
178 def wait_until_present(self, selector):
179 """ Wait until element matching CSS selector is on the page """
180 is_present = lambda driver: self.find(selector)
181 msg = 'An element matching "%s" should be on the page' % selector
182 element = Wait(self.driver).until(is_present, msg)
183 return element
184
185 def wait_until_visible(self, selector):
186 """ Wait until element matching CSS selector is visible on the page """
187 is_visible = lambda driver: self.find(selector).is_displayed()
188 msg = 'An element matching "%s" should be visible' % selector
189 Wait(self.driver).until(is_visible, msg)
190 return self.find(selector)
191
192 def wait_until_focused(self, selector):
193 """ Wait until element matching CSS selector has focus """
194 is_focused = \
195 lambda driver: self.find(selector) == self.focused_element()
196 msg = 'An element matching "%s" should be focused' % selector
197 Wait(self.driver).until(is_focused, msg)
198 return self.find(selector)
199
200 def enter_text(self, selector, value):
201 """ Insert text into element matching selector """
202 # note that keyup events don't occur until the element is clicked
203 # (in the case of <input type="text"...>, for example), so simulate
204 # user clicking the element before inserting text into it
205 field = self.click(selector)
206
207 field.send_keys(value)
208 return field
209
210 def click(self, selector):
211 """ Click on element which matches CSS selector """
212 element = self.wait_until_visible(selector)
213 element.click()
214 return element
215
216 def get_page_source(self):
217 """ Get raw HTML for the current page """
218 return self.driver.page_source