summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
diff options
context:
space:
mode:
Diffstat (limited to 'bitbake/lib/toaster/tests/browser/selenium_helpers_base.py')
-rw-r--r--bitbake/lib/toaster/tests/browser/selenium_helpers_base.py76
1 files changed, 65 insertions, 11 deletions
diff --git a/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py b/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
index 644d45fe58..393be75496 100644
--- a/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
+++ b/bitbake/lib/toaster/tests/browser/selenium_helpers_base.py
@@ -19,11 +19,15 @@ import os
19import time 19import time
20import unittest 20import unittest
21 21
22import pytest
22from selenium import webdriver 23from selenium import webdriver
24from selenium.webdriver.support import expected_conditions as EC
23from selenium.webdriver.support.ui import WebDriverWait 25from selenium.webdriver.support.ui import WebDriverWait
26from selenium.webdriver.common.by import By
24from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 27from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
25from selenium.common.exceptions import NoSuchElementException, \ 28from selenium.common.exceptions import NoSuchElementException, \
26 StaleElementReferenceException, TimeoutException 29 StaleElementReferenceException, TimeoutException, \
30 SessionNotCreatedException
27 31
28def create_selenium_driver(cls,browser='chrome'): 32def create_selenium_driver(cls,browser='chrome'):
29 # set default browser string based on env (if available) 33 # set default browser string based on env (if available)
@@ -32,9 +36,32 @@ def create_selenium_driver(cls,browser='chrome'):
32 browser = env_browser 36 browser = env_browser
33 37
34 if browser == 'chrome': 38 if browser == 'chrome':
35 return webdriver.Chrome( 39 options = webdriver.ChromeOptions()
36 service_args=["--verbose", "--log-path=selenium.log"] 40 options.add_argument('--headless')
37 ) 41 options.add_argument('--disable-infobars')
42 options.add_argument('--disable-dev-shm-usage')
43 options.add_argument('--no-sandbox')
44 options.add_argument('--remote-debugging-port=9222')
45 try:
46 return webdriver.Chrome(options=options)
47 except SessionNotCreatedException as e:
48 exit_message = "Halting tests prematurely to avoid cascading errors."
49 # check if chrome / chromedriver exists
50 chrome_path = os.popen("find ~/.cache/selenium/chrome/ -name 'chrome' -type f -print -quit").read().strip()
51 if not chrome_path:
52 pytest.exit(f"Failed to install/find chrome.\n{exit_message}")
53 chromedriver_path = os.popen("find ~/.cache/selenium/chromedriver/ -name 'chromedriver' -type f -print -quit").read().strip()
54 if not chromedriver_path:
55 pytest.exit(f"Failed to install/find chromedriver.\n{exit_message}")
56 # check if depends on each are fulfilled
57 depends_chrome = os.popen(f"ldd {chrome_path} | grep 'not found'").read().strip()
58 if depends_chrome:
59 pytest.exit(f"Missing chrome dependencies.\n{depends_chrome}\n{exit_message}")
60 depends_chromedriver = os.popen(f"ldd {chromedriver_path} | grep 'not found'").read().strip()
61 if depends_chromedriver:
62 pytest.exit(f"Missing chromedriver dependencies.\n{depends_chromedriver}\n{exit_message}")
63 # print original error otherwise
64 pytest.exit(f"Failed to start chromedriver.\n{e}\n{exit_message}")
38 elif browser == 'firefox': 65 elif browser == 'firefox':
39 return webdriver.Firefox() 66 return webdriver.Firefox()
40 elif browser == 'marionette': 67 elif browser == 'marionette':
@@ -66,7 +93,9 @@ class Wait(WebDriverWait):
66 _TIMEOUT = 10 93 _TIMEOUT = 10
67 _POLL_FREQUENCY = 0.5 94 _POLL_FREQUENCY = 0.5
68 95
69 def __init__(self, driver): 96 def __init__(self, driver, timeout=_TIMEOUT, poll=_POLL_FREQUENCY):
97 self._TIMEOUT = timeout
98 self._POLL_FREQUENCY = poll
70 super(Wait, self).__init__(driver, self._TIMEOUT, self._POLL_FREQUENCY) 99 super(Wait, self).__init__(driver, self._TIMEOUT, self._POLL_FREQUENCY)
71 100
72 def until(self, method, message=''): 101 def until(self, method, message=''):
@@ -138,6 +167,8 @@ class SeleniumTestCaseBase(unittest.TestCase):
138 """ Clean up webdriver driver """ 167 """ Clean up webdriver driver """
139 168
140 cls.driver.quit() 169 cls.driver.quit()
170 # Allow driver resources to be properly freed before proceeding with further tests
171 time.sleep(5)
141 super(SeleniumTestCaseBase, cls).tearDownClass() 172 super(SeleniumTestCaseBase, cls).tearDownClass()
142 173
143 def get(self, url): 174 def get(self, url):
@@ -151,13 +182,20 @@ class SeleniumTestCaseBase(unittest.TestCase):
151 abs_url = '%s%s' % (self.live_server_url, url) 182 abs_url = '%s%s' % (self.live_server_url, url)
152 self.driver.get(abs_url) 183 self.driver.get(abs_url)
153 184
185 try: # Ensure page is loaded before proceeding
186 self.wait_until_visible("#global-nav", poll=3)
187 except NoSuchElementException:
188 self.driver.implicitly_wait(3)
189 except TimeoutException:
190 self.driver.implicitly_wait(3)
191
154 def find(self, selector): 192 def find(self, selector):
155 """ Find single element by CSS selector """ 193 """ Find single element by CSS selector """
156 return self.driver.find_element_by_css_selector(selector) 194 return self.driver.find_element(By.CSS_SELECTOR, selector)
157 195
158 def find_all(self, selector): 196 def find_all(self, selector):
159 """ Find all elements matching CSS selector """ 197 """ Find all elements matching CSS selector """
160 return self.driver.find_elements_by_css_selector(selector) 198 return self.driver.find_elements(By.CSS_SELECTOR, selector)
161 199
162 def element_exists(self, selector): 200 def element_exists(self, selector):
163 """ 201 """
@@ -170,18 +208,34 @@ class SeleniumTestCaseBase(unittest.TestCase):
170 """ Return the element which currently has focus on the page """ 208 """ Return the element which currently has focus on the page """
171 return self.driver.switch_to.active_element 209 return self.driver.switch_to.active_element
172 210
173 def wait_until_present(self, selector): 211 def wait_until_present(self, selector, poll=0.5):
174 """ Wait until element matching CSS selector is on the page """ 212 """ Wait until element matching CSS selector is on the page """
175 is_present = lambda driver: self.find(selector) 213 is_present = lambda driver: self.find(selector)
176 msg = 'An element matching "%s" should be on the page' % selector 214 msg = 'An element matching "%s" should be on the page' % selector
177 element = Wait(self.driver).until(is_present, msg) 215 element = Wait(self.driver, poll=poll).until(is_present, msg)
216 if poll > 2:
217 time.sleep(poll) # element need more delay to be present
178 return element 218 return element
179 219
180 def wait_until_visible(self, selector): 220 def wait_until_visible(self, selector, poll=1):
181 """ Wait until element matching CSS selector is visible on the page """ 221 """ Wait until element matching CSS selector is visible on the page """
182 is_visible = lambda driver: self.find(selector).is_displayed() 222 is_visible = lambda driver: self.find(selector).is_displayed()
183 msg = 'An element matching "%s" should be visible' % selector 223 msg = 'An element matching "%s" should be visible' % selector
184 Wait(self.driver).until(is_visible, msg) 224 Wait(self.driver, poll=poll).until(is_visible, msg)
225 time.sleep(poll) # wait for visibility to settle
226 return self.find(selector)
227
228 def wait_until_clickable(self, selector, poll=1):
229 """ Wait until element matching CSS selector is visible on the page """
230 WebDriverWait(
231 self.driver,
232 Wait._TIMEOUT,
233 poll_frequency=poll
234 ).until(
235 EC.element_to_be_clickable((By.ID, selector.removeprefix('#')
236 )
237 )
238 )
185 return self.find(selector) 239 return self.find(selector)
186 240
187 def wait_until_focused(self, selector): 241 def wait_until_focused(self, selector):