Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ jobs:
pip install -U pip wheel setuptools
pip install -U -r requirements-test.txt
pip install -U -e .
pip install -UI --no-deps https://github.com/openwisp/openwisp-utils/tarball/browser-logs
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Remove this before merging

Suggested change
pip install -UI --no-deps https://github.com/openwisp/openwisp-utils/tarball/browser-logs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove this now.

pip install ${{ matrix.django-version }}

- name: QA checks
Expand Down
247 changes: 74 additions & 173 deletions openwisp_controller/config/tests/test_selenium.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,75 +16,42 @@

from openwisp_utils.test_selenium_mixins import SeleniumTestMixin

from ...tests.utils import DeviceAdminSeleniumTextMixin
from .utils import CreateConfigTemplateMixin, TestWireguardVpnMixin

Device = load_model('config', 'Device')


class SeleniumBaseMixin(CreateConfigTemplateMixin, SeleniumTestMixin):
def setUp(self):
self.admin = self._create_admin(
username=self.admin_username, password=self.admin_password
)


@tag('selenium_tests')
class TestDeviceAdmin(
SeleniumBaseMixin,
DeviceAdminSeleniumTextMixin,
CreateConfigTemplateMixin,
StaticLiveServerTestCase,
):
def tearDown(self):
# Accept unsaved changes alert to allow other tests to run
try:
self.web_driver.refresh()
except UnexpectedAlertPresentException:
alert = Alert(self.web_driver)
alert.accept()
else:
try:
WebDriverWait(self.web_driver, 1).until(EC.alert_is_present())
except TimeoutException:
pass
else:
alert = Alert(self.web_driver)
alert.accept()
self.web_driver.refresh()
WebDriverWait(self.web_driver, 2).until(
EC.visibility_of_element_located((By.XPATH, '//*[@id="site-name"]'))
)

def test_create_new_device(self):
required_template = self._create_template(name='Required', required=True)
default_template = self._create_template(name='Default', default=True)
org = self._get_org()
self.login()
self.open(reverse('admin:config_device_add'))
self.web_driver.find_element(by=By.NAME, value='name').send_keys(
'11:22:33:44:55:66'
)
self.web_driver.find_element(
self.find_element(by=By.NAME, value='name').send_keys('11:22:33:44:55:66')
self.find_element(
by=By.CSS_SELECTOR, value='#select2-id_organization-container'
).click()
WebDriverWait(self.web_driver, 2).until(
EC.invisibility_of_element_located(
(By.CSS_SELECTOR, '.select2-results__option.loading-results')
)
self.wait_for_invisibility(
By.CSS_SELECTOR, '.select2-results__option.loading-results'
)
self.web_driver.find_element(
by=By.CLASS_NAME, value='select2-search__field'
).send_keys(org.name)
WebDriverWait(self.web_driver, 2).until(
EC.invisibility_of_element_located(
(By.CSS_SELECTOR, '.select2-results__option.loading-results')
)
self.find_element(by=By.CLASS_NAME, value='select2-search__field').send_keys(
org.name
)
self.web_driver.find_element(
by=By.CLASS_NAME, value='select2-results__option'
).click()
self.web_driver.find_element(by=By.NAME, value='mac_address').send_keys(
self.wait_for_invisibility(
By.CSS_SELECTOR, '.select2-results__option.loading-results'
)
self.find_element(by=By.CLASS_NAME, value='select2-results__option').click()
self.find_element(by=By.NAME, value='mac_address').send_keys(
'11:22:33:44:55:66'
)
self.web_driver.find_element(
self.find_element(
by=By.XPATH, value='//*[@id="config-group"]/fieldset/div[2]/a'
).click()
try:
Expand All @@ -107,10 +74,10 @@ def test_create_new_device(self):
)
except TimeoutException:
self.fail('Relevant templates logic was not executed')
required_template_element = self.web_driver.find_element(
required_template_element = self.find_element(
by=By.XPATH, value=f'//*[@value="{required_template.id}"]'
)
default_template_element = self.web_driver.find_element(
default_template_element = self.find_element(
by=By.XPATH, value=f'//*[@value="{default_template.id}"]'
)
self.assertEqual(required_template_element.is_enabled(), False)
Expand All @@ -121,17 +88,10 @@ def test_create_new_device(self):
self.web_driver.execute_script(
'document.querySelector("#ow-user-tools").style.display="none"'
)
self.web_driver.find_element(by=By.NAME, value='_save').click()
try:
WebDriverWait(self.web_driver, 5).until(
EC.presence_of_element_located(
(By.CSS_SELECTOR, '.messagelist .success')
)
)
except TimeoutException:
self.fail('Device added success message timed out')
self.find_element(by=By.NAME, value='_save').click()
self.wait_for_presence(By.CSS_SELECTOR, '.messagelist .success')
self.assertEqual(
self.web_driver.find_elements(by=By.CLASS_NAME, value='success')[0].text,
self.find_elements(by=By.CLASS_NAME, value='success')[0].text,
'The Device “11:22:33:44:55:66” was added successfully.',
)

Expand All @@ -147,26 +107,12 @@ def test_device_preview_keyboard_shortcuts(self):
with self.subTest('press ALT + P and expect overlay to be shown'):
actions = ActionChains(self.web_driver)
actions.key_down(Keys.ALT).send_keys('p').key_up(Keys.ALT).perform()
try:
WebDriverWait(self.web_driver, 1).until(
EC.visibility_of_element_located(
(By.CSS_SELECTOR, '.djnjc-overlay:not(.loading)')
)
)
except TimeoutException:
self.fail('The preview overlay is unexpectedly not visible')
self.wait_for_visibility(By.CSS_SELECTOR, '.djnjc-overlay:not(.loading)')

with self.subTest('press ESC to close preview overlay'):
actions = ActionChains(self.web_driver)
actions.send_keys(Keys.ESCAPE).perform()
try:
WebDriverWait(self.web_driver, 1).until(
EC.invisibility_of_element_located(
(By.CSS_SELECTOR, '.djnjc-overlay:not(.loading)')
)
)
except TimeoutException:
self.fail('The preview overlay has not been closed as expected')
self.wait_for_invisibility(By.CSS_SELECTOR, '.djnjc-overlay:not(.loading)')

def test_unsaved_changes(self):
self.login()
Expand All @@ -183,19 +129,17 @@ def test_unsaved_changes(self):

with self.subTest('Alert should be displayed after making changes'):
# simulate hand gestures
self.web_driver.find_element(by=By.TAG_NAME, value='body').click()
self.web_driver.find_element(by=By.NAME, value='name').click()
self.find_element(by=By.TAG_NAME, value='body').click()
self.find_element(by=By.NAME, value='name').click()
# set name
self.web_driver.find_element(by=By.NAME, value='name').send_keys(
'new.device.name'
)
self.find_element(by=By.NAME, value='name').send_keys('new.device.name')
# simulate hand gestures
self.web_driver.find_element(by=By.TAG_NAME, value='body').click()
self.find_element(by=By.TAG_NAME, value='body').click()
self.web_driver.refresh()
try:
WebDriverWait(self.web_driver, 1).until(EC.alert_is_present())
WebDriverWait(self.web_driver, 5).until(EC.alert_is_present())
except TimeoutException:
for entry in self.web_driver.get_log('browser'):
for entry in self.get_browser_logs():
print(entry)
self.fail('Timed out wating for unsaved changes alert')
else:
Expand Down Expand Up @@ -234,35 +178,18 @@ def test_multiple_organization_templates(self):
)
wait = WebDriverWait(self.web_driver, 2)
# org2 templates should not be visible
try:
wait.until(
EC.invisibility_of_element_located(
(By.XPATH, f'//*[@value="{org2_required_template.id}"]')
)
)
wait.until(
EC.invisibility_of_element_located(
(By.XPATH, f'//*[@value="{org2_default_template.id}"]')
)
)
except (TimeoutException, StaleElementReferenceException):
self.fail('Template belonging to other organization found')

# org1 and shared templates should be visible
wait.until(
EC.visibility_of_any_elements_located(
(By.XPATH, f'//*[@value="{org1_required_template.id}"]')
)
self.wait_for_invisibility(
By.XPATH, f'//*[@value="{org2_required_template.id}"]'
)
wait.until(
EC.visibility_of_any_elements_located(
(By.XPATH, f'//*[@value="{org1_default_template.id}"]')
)
self.wait_for_invisibility(
By.XPATH, f'//*[@value="{org2_default_template.id}"]'
)
wait.until(
EC.visibility_of_any_elements_located(
(By.XPATH, f'//*[@value="{shared_required_template.id}"]')
)

# org1 and shared templates should be visible
self.wait_for_visibility(By.XPATH, f'//*[@value="{org1_required_template.id}"]')
self.wait_for_visibility(By.XPATH, f'//*[@value="{org1_default_template.id}"]')
self.wait_for_visibility(
By.XPATH, f'//*[@value="{shared_required_template.id}"]'
)

def test_change_config_backend(self):
Expand All @@ -273,20 +200,13 @@ def test_change_config_backend(self):
self.open(
reverse('admin:config_device_change', args=[device.id]) + '#config-group'
)
self.web_driver.find_element(by=By.XPATH, value=f'//*[@value="{template.id}"]')
self.find_element(by=By.XPATH, value=f'//*[@value="{template.id}"]')
# Change config backed to
config_backend_select = Select(
self.web_driver.find_element(by=By.NAME, value='config-0-backend')
self.find_element(by=By.NAME, value='config-0-backend')
)
config_backend_select.select_by_visible_text('OpenWISP Firmware 1.x')
try:
WebDriverWait(self.web_driver, 1).until(
EC.invisibility_of_element_located(
(By.XPATH, f'//*[@value="{template.id}"]')
)
)
except TimeoutException:
self.fail('Template for other config backend found')
self.wait_for_invisibility(By.XPATH, f'//*[@value="{template.id}"]')

def test_template_context_variables(self):
self._create_template(
Expand All @@ -312,7 +232,7 @@ def test_template_context_variables(self):
)
except TimeoutException:
self.fail('Timed out wating for configuration variabled to get loaded')
self.web_driver.find_element(
self.find_element(
by=By.XPATH, value='//*[@id="main-content"]/div[2]/a[3]'
).click()
try:
Expand All @@ -333,28 +253,22 @@ def test_force_delete_device_with_deactivating_config(self):

self.login()
self.open(reverse('admin:config_device_change', args=[device.id]))
self.web_driver.find_elements(
by=By.CSS_SELECTOR, value='input.deletelink[type="submit"]'
)[-1].click()
self.find_elements(by=By.CSS_SELECTOR, value='input.deletelink[type="submit"]')[
-1
].click()
device.refresh_from_db()
config.refresh_from_db()
self.assertEqual(device.is_deactivated(), True)
self.assertEqual(config.is_deactivating(), True)

self.open(reverse('admin:config_device_change', args=[device.id]))
self.web_driver.find_elements(by=By.CSS_SELECTOR, value='a.deletelink')[
-1
].click()
WebDriverWait(self.web_driver, 5).until(
EC.visibility_of_element_located(
(By.CSS_SELECTOR, '#deactivating-warning .messagelist .warning p')
)
self.find_elements(by=By.CSS_SELECTOR, value='a.deletelink')[-1].click()
self.wait_for_visibility(
By.CSS_SELECTOR, '#deactivating-warning .messagelist .warning p'
)
self.web_driver.find_element(by=By.CSS_SELECTOR, value='#warning-ack').click()
delete_confirm = WebDriverWait(self.web_driver, 2).until(
EC.visibility_of_element_located(
(By.CSS_SELECTOR, 'form[method="post"] input[type="submit"]')
)
self.find_element(by=By.CSS_SELECTOR, value='#warning-ack').click()
delete_confirm = self.find_element(
By.CSS_SELECTOR, 'form[method="post"] input[type="submit"]'
)
delete_confirm.click()
self.assertEqual(Device.objects.count(), 0)
Expand All @@ -375,66 +289,53 @@ def test_force_delete_multiple_devices_with_deactivating_config(self):

self.login()
self.open(reverse('admin:config_device_changelist'))
self.web_driver.find_element(by=By.CSS_SELECTOR, value='#action-toggle').click()
select = Select(self.web_driver.find_element(by=By.NAME, value='action'))
self.find_element(by=By.CSS_SELECTOR, value='#action-toggle').click()
select = Select(self.find_element(by=By.NAME, value='action'))
select.select_by_value('delete_selected')
self.web_driver.find_element(
self.find_element(
by=By.CSS_SELECTOR, value='button[type="submit"][name="index"][value="0"]'
).click()
WebDriverWait(self.web_driver, 5).until(
EC.visibility_of_element_located(
(By.CSS_SELECTOR, '#deactivating-warning .messagelist .warning p')
)
self.wait_for_visibility(
By.CSS_SELECTOR, '#deactivating-warning .messagelist .warning p'
)
self.web_driver.find_element(by=By.CSS_SELECTOR, value='#warning-ack').click()
delete_confirm = WebDriverWait(self.web_driver, 2).until(
EC.visibility_of_element_located(
(By.CSS_SELECTOR, 'form[method="post"] input[type="submit"]')
)
self.find_element(by=By.CSS_SELECTOR, value='#warning-ack').click()
delete_confirm = self.find_element(
By.CSS_SELECTOR, 'form[method="post"] input[type="submit"]'
)
delete_confirm.click()
self.assertEqual(Device.objects.count(), 0)


class TestVpnAdmin(SeleniumBaseMixin, TestWireguardVpnMixin, StaticLiveServerTestCase):
class TestVpnAdmin(
SeleniumTestMixin,
CreateConfigTemplateMixin,
TestWireguardVpnMixin,
StaticLiveServerTestCase,
):
def test_vpn_edit(self):
self.login()
device, vpn, template = self._create_wireguard_vpn_template()
self.open(reverse('admin:config_vpn_change', args=[vpn.id]))
with self.subTest('Ca and Cert should not be visible'):
el = self.web_driver.find_element(by=By.CLASS_NAME, value='field-ca')
el = self.find_element(by=By.CLASS_NAME, value='field-ca')
self.assertFalse(el.is_displayed())
el = self.web_driver.find_element(by=By.CLASS_NAME, value='field-cert')
el = self.find_element(by=By.CLASS_NAME, value='field-cert')
self.assertFalse(el.is_displayed())

with self.subTest('PrivateKey is shown in configuration preview'):
self.web_driver.find_element(
by=By.CSS_SELECTOR, value='.previewlink'
).click()
WebDriverWait(self.web_driver, 2).until(
EC.visibility_of_element_located(
(By.CSS_SELECTOR, '.djnjc-preformatted')
)
)
self.find_element(by=By.CSS_SELECTOR, value='.previewlink').click()
self.wait_for_visibility(By.CSS_SELECTOR, '.djnjc-preformatted')
self.assertIn(
f'PrivateKey = {vpn.private_key}',
self.web_driver.find_element(
by=By.CSS_SELECTOR, value='.djnjc-preformatted'
).text,
self.find_element(by=By.CSS_SELECTOR, value='.djnjc-preformatted').text,
)
# Close the configuration preview
self.web_driver.find_element(
by=By.CSS_SELECTOR, value='.djnjc-overlay a.close'
).click()
self.find_element(by=By.CSS_SELECTOR, value='.djnjc-overlay a.close').click()

with self.subTest('Changing VPN backend should hide webhook and authtoken'):
backend = Select(self.web_driver.find_element(by=By.ID, value='id_backend'))
backend = Select(self.find_element(by=By.ID, value='id_backend'))
backend.select_by_visible_text('OpenVPN')
el = self.web_driver.find_element(
by=By.CLASS_NAME, value='field-webhook_endpoint'
)
el = self.find_element(by=By.CLASS_NAME, value='field-webhook_endpoint')
self.assertFalse(el.is_displayed())
el = self.web_driver.find_element(
by=By.CLASS_NAME, value='field-auth_token'
)
el = self.find_element(by=By.CLASS_NAME, value='field-auth_token')
self.assertFalse(el.is_displayed())
Loading
Loading