diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 027fe4e1..de3f1942 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,6 +73,8 @@ jobs: SAMPLE_APP=1 ./runtests.py coverage run runtests.py --parallel coverage combine + env: + SELENIUM_HEADLESS: 1 - name: Upload Coverage run: coveralls --service=github diff --git a/openwisp_notifications/static/openwisp-notifications/js/notifications.js b/openwisp_notifications/static/openwisp-notifications/js/notifications.js index 6311f38a..16fa3312 100644 --- a/openwisp_notifications/static/openwisp-notifications/js/notifications.js +++ b/openwisp_notifications/static/openwisp-notifications/js/notifications.js @@ -195,8 +195,9 @@ function notificationWidget($) { } function notificationListItem(elem) { - let klass, - datetime = dateTimeStampToDateTimeLocaleString(new Date(elem.timestamp)); + let klass; + const datetime = dateTimeStampToDateTimeLocaleString(new Date(elem.timestamp)), + target_url = new URL(elem.target_url); if (!notificationReadStatus.has(elem.id)) { if (elem.unread) { @@ -207,8 +208,23 @@ function notificationWidget($) { } klass = notificationReadStatus.get(elem.id); + // Used to convert absolute URLs in notification messages to relative paths + function convertMessageWithRelativeURL(htmlString) { + const parser = new DOMParser(), + doc = parser.parseFromString(htmlString, 'text/html'), + links = doc.querySelectorAll('a'); + links.forEach((link) => { + let url = link.getAttribute('href'); + if (url) { + url = new URL(url); + link.setAttribute('href', url.pathname); + } + }); + return doc.body.innerHTML; + } + return `
+ data-location="${target_url.pathname}" role="link" tabindex="0">
@@ -217,7 +233,7 @@ function notificationWidget($) {
${datetime}
- ${elem.message} + ${convertMessageWithRelativeURL(elem.message)}
`; } diff --git a/openwisp_notifications/tests/test_widget.py b/openwisp_notifications/tests/test_widget.py new file mode 100644 index 00000000..0fc011ca --- /dev/null +++ b/openwisp_notifications/tests/test_widget.py @@ -0,0 +1,56 @@ +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.ui import WebDriverWait + +from openwisp_notifications.swapper import load_model +from openwisp_notifications.utils import _get_object_link +from openwisp_users.tests.utils import TestOrganizationMixin +from openwisp_utils.test_selenium_mixins import SeleniumTestMixin + +Notification = load_model('Notification') + + +class TestWidget( + SeleniumTestMixin, + TestOrganizationMixin, + StaticLiveServerTestCase, +): + serve_static = True + + def setUp(self): + self.admin = self._create_admin( + username=self.admin_username, password=self.admin_password + ) + + def test_notification_relative_link(self): + self.login() + operator = super()._create_operator() + data = dict( + email_subject='Test Email subject', + url='http://localhost:8000/admin/', + ) + notification = Notification.objects.create( + actor=self.admin, + recipient=self.admin, + description='Test Notification Description', + verb='Test Notification', + action_object=operator, + target=operator, + data=data, + ) + self.web_driver.implicitly_wait(10) + WebDriverWait(self.web_driver, 10).until( + EC.visibility_of_element_located((By.ID, 'openwisp_notifications')) + ) + self.web_driver.find_element(By.ID, 'openwisp_notifications').click() + WebDriverWait(self.web_driver, 10).until( + EC.visibility_of_element_located((By.CLASS_NAME, 'ow-notification-elem')) + ) + notification_elem = self.web_driver.find_element( + By.CLASS_NAME, 'ow-notification-elem' + ) + data_location_value = notification_elem.get_attribute('data-location') + self.assertEqual( + data_location_value, _get_object_link(notification, 'target', False) + ) diff --git a/requirements-test.txt b/requirements-test.txt index 1eacb225..57b38551 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,4 +1,4 @@ -openwisp-utils[qa] @ https://github.com/openwisp/openwisp-utils/tarball/master +openwisp-utils[qa,selenium] @ https://github.com/openwisp/openwisp-utils/tarball/master django-cors-headers~=4.0.0 django-redis~=5.2.0 channels_redis~=4.1.0