33from selenium import webdriver
44from selenium .common .exceptions import TimeoutException
55from selenium .webdriver .common .by import By
6+ from selenium .webdriver .common .desired_capabilities import DesiredCapabilities
67from selenium .webdriver .firefox .options import Options
78from selenium .webdriver .support import expected_conditions as EC
89from selenium .webdriver .support .ui import WebDriverWait
@@ -17,10 +18,18 @@ class SeleniumTestMixin:
1718
1819 admin_username = 'admin'
1920 admin_password = 'password'
21+ browser = 'firefox'
2022
2123 @classmethod
2224 def setUpClass (cls ):
2325 super ().setUpClass ()
26+ if cls .browser == 'firefox' :
27+ cls .web_driver = cls .get_firefox_webdriver ()
28+ else :
29+ cls .web_driver = cls .get_chrome_webdriver ()
30+
31+ @classmethod
32+ def get_firefox_webdriver (cls ):
2433 options = Options ()
2534 options .page_load_strategy = 'eager'
2635 if os .environ .get ('SELENIUM_HEADLESS' , False ):
@@ -43,7 +52,7 @@ def setUpClass(cls):
4352 GECKO_LOG = os .environ .get ('GECKO_LOG' , None )
4453 if GECKO_LOG :
4554 kwargs ['service' ] = webdriver .FirefoxService (log_output = 'geckodriver.log' )
46- cls . web_driver = webdriver .Firefox (** kwargs )
55+ web_driver = webdriver .Firefox (** kwargs )
4756 # Firefox does not support the WebDriver.get_log API. To work around this,
4857 # we inject JavaScript into the page to override window.console within the
4958 # browser's JS runtime. This allows us to capture and retrieve console errors
@@ -55,7 +64,38 @@ def setUpClass(cls):
5564 "console_capture_extension" ,
5665 )
5766 )
58- cls .web_driver .install_addon (extension_path , temporary = True )
67+ web_driver .install_addon (extension_path , temporary = True )
68+ return web_driver
69+
70+ @classmethod
71+ def get_chrome_webdriver (cls ):
72+ chrome_options = webdriver .ChromeOptions ()
73+ chrome_options .page_load_strategy = 'eager'
74+ if os .environ .get ('SELENIUM_HEADLESS' , False ):
75+ chrome_options .add_argument ('--headless' )
76+ CHROME_BIN = os .environ .get ('CHROME_BIN' , None )
77+ if CHROME_BIN :
78+ chrome_options .binary_location = CHROME_BIN
79+ chrome_options .add_argument ('--window-size=1366,768' )
80+ chrome_options .add_argument ('--ignore-certificate-errors' )
81+ # When running Selenium tests with the "--parallel" flag,
82+ # each TestCase class requires its own browser instance.
83+ # If the same "remote-debugging-port" is used for all
84+ # TestCase classes, it leads to failed test cases.
85+ # Therefore, it is necessary to utilize different remote
86+ # debugging ports for each TestCase. To accomplish this,
87+ # we can leverage the randomized live test server port to
88+ # generate a unique port for each browser instance.
89+ chrome_options .add_argument (
90+ f'--remote-debugging-port={ cls .server_thread .port + 100 } '
91+ )
92+ capabilities = DesiredCapabilities .CHROME
93+ capabilities ['goog:loggingPrefs' ] = {'browser' : 'ALL' }
94+ chrome_options .set_capability ('cloud:options' , capabilities )
95+ web_driver = webdriver .Chrome (
96+ options = chrome_options ,
97+ )
98+ return web_driver
5999
60100 @classmethod
61101 def tearDownClass (cls ):
@@ -86,7 +126,9 @@ def open(self, url, driver=None, timeout=5):
86126 )
87127
88128 def get_browser_logs (self ):
89- return self .web_driver .execute_script ('return window._console_logs' )
129+ if self .browser == 'firefox' :
130+ return self .web_driver .execute_script ('return window._console_logs' )
131+ return self .web_driver .get_log ('browser' )
90132
91133 def login (self , username = None , password = None , driver = None ):
92134 """Log in to the admin dashboard.
0 commit comments