Skip to content

Commit 05b7065

Browse files
authored
Merge branch 'master' into dependabot/pip/selenium-gte-4.10-and-lt-4.30
2 parents 4449ee9 + 88b13ae commit 05b7065

File tree

3 files changed

+94
-47
lines changed

3 files changed

+94
-47
lines changed

openwisp_utils/admin_theme/static/admin/js/menu.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ const MenuTransitionTime = "0.1s";
1313
var wasActiveGroupOpen = false;
1414

1515
(function () {
16+
// popup page or other pages
17+
// where menu is not displayed
18+
if (!owMenu) {
19+
return;
20+
}
1621
setMenu();
1722
initGroupViewHandlers();
1823
initToggleMenuHandlers();

openwisp_utils/test_selenium_mixins.py

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from django.conf import settings
44
from selenium import webdriver
55
from selenium.webdriver.common.by import By
6-
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
6+
from selenium.webdriver.firefox.options import Options
77
from selenium.webdriver.support import expected_conditions as EC
88
from selenium.webdriver.support.ui import WebDriverWait
99

@@ -21,33 +21,27 @@ class SeleniumTestMixin:
2121
@classmethod
2222
def setUpClass(cls):
2323
super().setUpClass()
24-
25-
chrome_options = webdriver.ChromeOptions()
26-
chrome_options.page_load_strategy = 'eager'
24+
firefox_options = Options()
25+
firefox_options.page_load_strategy = 'eager'
2726
if getattr(settings, 'SELENIUM_HEADLESS', True):
28-
chrome_options.add_argument('--headless')
29-
CHROME_BIN = os.environ.get('CHROME_BIN', None)
30-
if CHROME_BIN:
31-
chrome_options.binary_location = CHROME_BIN
32-
chrome_options.add_argument('--window-size=1366,768')
33-
chrome_options.add_argument('--ignore-certificate-errors')
34-
# When running Selenium tests with the "--parallel" flag,
35-
# each TestCase class requires its own browser instance.
36-
# If the same "remote-debugging-port" is used for all
37-
# TestCase classes, it leads to failed test cases.
38-
# Therefore, it is necessary to utilize different remote
39-
# debugging ports for each TestCase. To accomplish this,
40-
# we can leverage the randomized live test server port to
41-
# generate a unique port for each browser instance.
42-
chrome_options.add_argument(
43-
f'--remote-debugging-port={cls.server_thread.port + 100}'
27+
firefox_options.add_argument('--headless')
28+
GECKO_BIN = os.environ.get('GECKO_BIN', None)
29+
if GECKO_BIN:
30+
firefox_options.binary_location = GECKO_BIN
31+
firefox_options.set_preference(
32+
'network.stricttransportsecurity.preloadlist', False
4433
)
45-
capabilities = DesiredCapabilities.CHROME
46-
capabilities['goog:loggingPrefs'] = {'browser': 'ALL'}
47-
chrome_options.set_capability('cloud:options', capabilities)
48-
cls.web_driver = webdriver.Chrome(
49-
options=chrome_options,
34+
# Enable detailed GeckoDriver logging
35+
firefox_options.set_capability(
36+
'moz:firefoxOptions', {'log': {'level': 'trace'}}
5037
)
38+
kwargs = dict(options=firefox_options)
39+
# Optional: Store logs in a file
40+
# Pass GECKO_LOG=1 when running tests
41+
GECKO_LOG = os.environ.get('GECKO_LOG', None)
42+
if GECKO_LOG:
43+
kwargs['service'] = webdriver.FirefoxService(log_output='geckodriver.log')
44+
cls.web_driver = webdriver.Firefox(**kwargs)
5145

5246
@classmethod
5347
def tearDownClass(cls):

tests/test_project/tests/test_selenium.py

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -158,27 +158,22 @@ def _test_menu_dropdown(self, is_narrow=False, is_medium=False):
158158
if is_narrow:
159159
# Do not test when menu is not visible
160160
return
161-
with self.subTest('Test menu dropdown when menu is close'):
161+
with self.subTest('Test menu dropdown when menu is closed'):
162162
self._close_menu()
163163
# Test mg_dropdown is not visible
164164
self.assertEqual(mg_dropdown.is_displayed(), False)
165165
self.assertEqual(mg_label.is_displayed(), False)
166166
self.assertEqual(mg_icon.is_displayed(), True)
167167
# Test mg dropdown gets visible on clicking mg head
168168
mg_head.click()
169-
is_visible = True
170169
try:
171170
WebDriverWait(self.web_driver, 2).until(
172171
EC.visibility_of_element_located(
173172
(By.CSS_SELECTOR, '#mg-dropdown-32')
174173
)
175174
)
176175
except TimeoutException:
177-
is_visible = False
178-
self.assertEqual(
179-
is_visible,
180-
True,
181-
)
176+
self.fail('drop down not visible')
182177
self.assertEqual(mg_dropdown_label.is_displayed(), True)
183178
# Test mg dropdown gets invisible on clicking mg head
184179
mg_head.click()
@@ -188,12 +183,16 @@ def _test_menu_dropdown(self, is_narrow=False, is_medium=False):
188183
main_content.click()
189184
self.assertEqual(mg_dropdown.is_displayed(), False)
190185

191-
with self.subTest('Test visibilty of menu label when menu close'):
186+
with self.subTest('Test visibilty of menu label when menu is closed'):
192187
self._close_menu()
193188
actions = ActionChains(self.web_driver)
194189
actions.move_to_element(mg_head)
190+
# clicking twice forces the hover action
191+
# to work consistently, without this it may
192+
# yield inconsistent results in automated tests
193+
actions.click(mg_head)
194+
actions.click(mg_head)
195195
actions.perform()
196-
is_visible = True
197196
try:
198197
WebDriverWait(self.web_driver, 2).until(
199198
EC.visibility_of_element_located(
@@ -204,8 +203,7 @@ def _test_menu_dropdown(self, is_narrow=False, is_medium=False):
204203
)
205204
)
206205
except TimeoutException:
207-
is_visible = False
208-
self.assertEqual(is_visible, True)
206+
self.fail('label not visible')
209207
mg_head.click()
210208
actions.move_to_element(mg_head)
211209
actions.perform()
@@ -731,18 +729,47 @@ def test_autocomplete_shelf_filter(self):
731729
),
732730
self.web_driver.page_source,
733731
)
734-
self.web_driver.find_element(By.CSS_SELECTOR, filter_css_selector).click()
735-
self.web_driver.find_element(By.CSS_SELECTOR, '.select2-container--open')
736-
WebDriverWait(self.web_driver, 10).until(
737-
EC.presence_of_element_located(
738-
(By.XPATH, f'//*[contains(text(), "{horror_shelf.name}")]')
732+
try:
733+
WebDriverWait(self.web_driver, 2).until(
734+
EC.presence_of_element_located((By.CSS_SELECTOR, filter_css_selector))
739735
)
740-
)
736+
except TimeoutException:
737+
self.fail(f'{filter_css_selector} not available as expected')
738+
else:
739+
self.web_driver.find_element(By.CSS_SELECTOR, filter_css_selector).click()
740+
try:
741+
WebDriverWait(self.web_driver, 2).until(
742+
EC.presence_of_element_located(
743+
(By.CSS_SELECTOR, '.select2-container--open')
744+
)
745+
)
746+
except TimeoutException:
747+
self.fail('select2 widget did not open as expected')
748+
try:
749+
WebDriverWait(self.web_driver, 2).until(
750+
EC.presence_of_element_located(
751+
(By.XPATH, f'//*[contains(text(), "{horror_shelf.name}")]')
752+
)
753+
)
754+
except TimeoutException:
755+
self.fail(f'"{horror_shelf.name}" not found')
741756
self.assertIn(horror_shelf.name, self.web_driver.page_source)
742757
self.assertIn(factual_shelf.name, self.web_driver.page_source)
743-
self.web_driver.find_element(By.XPATH, filter_option_xpath).click()
758+
try:
759+
WebDriverWait(self.web_driver, 2).until(
760+
EC.presence_of_element_located((By.XPATH, filter_option_xpath))
761+
)
762+
except TimeoutException:
763+
self.fail(f'"{filter_option_xpath}" not found')
764+
else:
765+
self.web_driver.find_element(By.XPATH, filter_option_xpath).click()
744766
self.assertIn(str(factual_shelf.id), self.web_driver.current_url)
745-
self.web_driver.find_element(By.CSS_SELECTOR, filter_css_selector)
767+
try:
768+
WebDriverWait(self.web_driver, 2).until(
769+
EC.presence_of_element_located((By.CSS_SELECTOR, filter_css_selector))
770+
)
771+
except TimeoutException:
772+
self.fail(f'"{filter_css_selector}" not found')
746773
self.assertNotIn(horror_shelf.name, self.web_driver.page_source)
747774
self.assertIn(factual_shelf.name, self.web_driver.page_source)
748775
with self.assertRaises(NoSuchElementException):
@@ -778,11 +805,32 @@ def test_autocomplete_owner_filter(self):
778805
),
779806
self.web_driver.page_source,
780807
)
781-
self.web_driver.find_element(By.CSS_SELECTOR, filter_css_selector).click()
782-
self.web_driver.find_element(By.CSS_SELECTOR, '.select2-container--open')
808+
try:
809+
WebDriverWait(self.web_driver, 2).until(
810+
EC.presence_of_element_located((By.CSS_SELECTOR, filter_css_selector))
811+
)
812+
except TimeoutException:
813+
self.fail(f'{filter_css_selector} not available as expected')
814+
else:
815+
self.web_driver.find_element(By.CSS_SELECTOR, filter_css_selector).click()
816+
try:
817+
WebDriverWait(self.web_driver, 2).until(
818+
EC.presence_of_element_located(
819+
(By.CSS_SELECTOR, '.select2-container--open')
820+
)
821+
)
822+
except TimeoutException:
823+
self.fail('select2 widget did not open as expected')
783824
self.assertIn(self.admin.username, self.web_driver.page_source)
784825
self.assertIn(user.username, self.web_driver.page_source)
785-
self.web_driver.find_element(By.XPATH, filter_null_option_xpath).click()
826+
try:
827+
WebDriverWait(self.web_driver, 2).until(
828+
EC.presence_of_element_located((By.XPATH, filter_null_option_xpath))
829+
)
830+
except TimeoutException:
831+
self.fail(f'{filter_null_option_xpath} not available as expected')
832+
else:
833+
self.web_driver.find_element(By.XPATH, filter_null_option_xpath).click()
786834
self._get_filter_button().click()
787835
self.assertIn('owner_id__isnull=true', self.web_driver.current_url)
788836
with self.assertRaises(NoSuchElementException):

0 commit comments

Comments
 (0)