11from django .contrib .staticfiles .testing import StaticLiveServerTestCase
22from django .test import tag
33from django .urls .base import reverse
4- from selenium .common .exceptions import (
5- StaleElementReferenceException ,
6- TimeoutException ,
7- UnexpectedAlertPresentException ,
8- )
4+ from selenium .common .exceptions import TimeoutException
95from selenium .webdriver .common .action_chains import ActionChains
106from selenium .webdriver .common .alert import Alert
117from selenium .webdriver .common .by import By
@@ -117,9 +113,10 @@ def test_device_preview_keyboard_shortcuts(self):
117113 def test_unsaved_changes (self ):
118114 self .login ()
119115 device = self ._create_config (organization = self ._get_org ()).device
120- self .open (reverse ('admin:config_device_change' , args = [device .id ]))
116+ path = reverse ('admin:config_device_change' , args = [device .id ])
117+ self .open (path )
121118 with self .subTest ('Alert should not be displayed without any change' ):
122- self .web_driver . refresh ( )
119+ self .open ( path )
123120 try :
124121 WebDriverWait (self .web_driver , 1 ).until (EC .alert_is_present ())
125122 except TimeoutException :
@@ -143,8 +140,7 @@ def test_unsaved_changes(self):
143140 print (entry )
144141 self .fail ('Timed out wating for unsaved changes alert' )
145142 else :
146- alert = Alert (self .web_driver )
147- alert .accept ()
143+ self .web_driver .switch_to .alert .accept ()
148144
149145 def test_multiple_organization_templates (self ):
150146 shared_required_template = self ._create_template (
@@ -176,7 +172,6 @@ def test_multiple_organization_templates(self):
176172 reverse ('admin:config_device_change' , args = [org1_device .id ])
177173 + '#config-group'
178174 )
179- wait = WebDriverWait (self .web_driver , 2 )
180175 # org2 templates should not be visible
181176 self .wait_for_invisibility (
182177 By .XPATH , f'//*[@value="{ org2_required_template .id } "]'
@@ -253,16 +248,27 @@ def test_force_delete_device_with_deactivating_config(self):
253248
254249 self .login ()
255250 self .open (reverse ('admin:config_device_change' , args = [device .id ]))
256- self .find_elements (by = By .CSS_SELECTOR , value = 'input.deletelink[type="submit"]' )[
257- - 1
258- ].click ()
251+ # The webpage has two "submit-row" sections, each containing a "Deactivate"
252+ # button. The first (top) "Deactivate" button is hidden, causing
253+ # `wait_for_visibility` to fail. To avoid this issue, we use
254+ # `wait_for='presence'` instead, ensuring we locat the elements regardless
255+ # of visibility. We then select the last (visible) button and click it.
256+ self .find_elements (
257+ by = By .CSS_SELECTOR ,
258+ value = 'input.deletelink[type="submit"]' ,
259+ wait_for = 'presence' ,
260+ )[- 1 ].click ()
259261 device .refresh_from_db ()
260262 config .refresh_from_db ()
261263 self .assertEqual (device .is_deactivated (), True )
262264 self .assertEqual (config .is_deactivating (), True )
263265
264266 self .open (reverse ('admin:config_device_change' , args = [device .id ]))
265- self .find_elements (by = By .CSS_SELECTOR , value = 'a.deletelink' )[- 1 ].click ()
267+ # Use `presence` instead of `visibility` for `wait_for`,
268+ # as the same issue described above applies here.
269+ self .find_elements (
270+ by = By .CSS_SELECTOR , value = 'a.deletelink' , wait_for = 'presence'
271+ )[- 1 ].click ()
266272 self .wait_for_visibility (
267273 By .CSS_SELECTOR , '#deactivating-warning .messagelist .warning p'
268274 )
@@ -306,6 +312,7 @@ def test_force_delete_multiple_devices_with_deactivating_config(self):
306312 self .assertEqual (Device .objects .count (), 0 )
307313
308314
315+ @tag ('selenium_tests' )
309316class TestVpnAdmin (
310317 SeleniumTestMixin ,
311318 CreateConfigTemplateMixin ,
0 commit comments