From 9b7a6e5556325b95908456286db0dc759306a4f2 Mon Sep 17 00:00:00 2001 From: Alexandre Vincent Date: Tue, 2 Jun 2026 16:04:25 +0200 Subject: [PATCH 1/4] [tests] Confirm template cannot be extended with current loaders order --- openwisp_notifications/tests/test_admin.py | 22 +++++++++++++++++++ .../templates/admin/base_site.html | 5 +++++ .../templates/admin/change_form.html | 5 +++++ .../sample_notifications/tests/test_django.py | 13 +++++++++++ 4 files changed, 45 insertions(+) create mode 100644 tests/openwisp2/sample_notifications/templates/admin/base_site.html create mode 100644 tests/openwisp2/sample_notifications/templates/admin/change_form.html diff --git a/openwisp_notifications/tests/test_admin.py b/openwisp_notifications/tests/test_admin.py index aab6caf3..efd19fa4 100644 --- a/openwisp_notifications/tests/test_admin.py +++ b/openwisp_notifications/tests/test_admin.py @@ -188,6 +188,28 @@ def test_notification_preferences_button_staff_user(self): response = self.client.get(user_admin_page) self.assertNotContains(response, expected_html, html=True) + def test_base_site_template(self): + response = self.client.get(self._url) + self.assertContains(response, "openwisp-notifications/css/loader.css") + self.assertContains(response, "openwisp-notifications/css/notifications.css") + self.assertContains(response, "openwisp-notifications/js/notifications.js") + self.assertContains( + response, "openwisp-notifications/js/vendor/reconnecting-websocket.min.js" + ) + self.assertContains(response, 'id="openwisp_notifications"') + + def test_change_form_template(self): + org = self._get_org() + url = reverse( + f"admin:{self.users_app_label}_organization_change", args=(org.pk,) + ) + response = self.client.get(url) + self.assertContains(response, "owIsChangeForm = true") + self.assertContains( + response, f"const owNotifyAppLabel = '{self.users_app_label}'" + ) + self.assertContains(response, "owNotifyModelName = 'organization'") + class TestOrganizationNotificationsSettingsAdmin(BaseTestAdmin): app_label = "openwisp_notifications" diff --git a/tests/openwisp2/sample_notifications/templates/admin/base_site.html b/tests/openwisp2/sample_notifications/templates/admin/base_site.html new file mode 100644 index 00000000..de62b4bb --- /dev/null +++ b/tests/openwisp2/sample_notifications/templates/admin/base_site.html @@ -0,0 +1,5 @@ +{% extends "admin/base_site.html" %} +{% block user-tools %} + {{ block.super }} +
+{% endblock %} diff --git a/tests/openwisp2/sample_notifications/templates/admin/change_form.html b/tests/openwisp2/sample_notifications/templates/admin/change_form.html new file mode 100644 index 00000000..d389c019 --- /dev/null +++ b/tests/openwisp2/sample_notifications/templates/admin/change_form.html @@ -0,0 +1,5 @@ +{% extends "admin/change_form.html" %} +{% block admin_change_form_document_ready %} + {{ block.super }} +
+{% endblock %} diff --git a/tests/openwisp2/sample_notifications/tests/test_django.py b/tests/openwisp2/sample_notifications/tests/test_django.py index 8ebdca95..0eceab8b 100644 --- a/tests/openwisp2/sample_notifications/tests/test_django.py +++ b/tests/openwisp2/sample_notifications/tests/test_django.py @@ -3,6 +3,7 @@ from django.apps.registry import apps from django.contrib.contenttypes.models import ContentType from django.core.cache import cache +from django.urls import reverse from openwisp_notifications.swapper import load_model, swapper_load_model from openwisp_notifications.tests.test_admin import TestAdmin as BaseTestAdmin @@ -45,6 +46,18 @@ class TestAdmin(BaseTestAdmin): app_label = "sample_notifications" + def test_base_site_template(self): + response = self.client.get(self._url) + self.assertContains(response, 'id="sample-notifications-base-site"') + + def test_change_form_template(self): + org = self._get_org() + url = reverse( + f"admin:{self.users_app_label}_organization_change", args=(org.pk,) + ) + response = self.client.get(url) + self.assertContains(response, 'id="sample-notifications-change-form"') + class TestAdminMedia(BaseTestAdminMedia): pass From 9b1e592aa1e7c8e436f753e99db0c761349b83f4 Mon Sep 17 00:00:00 2001 From: Alexandre Vincent Date: Tue, 2 Jun 2026 16:37:31 +0200 Subject: [PATCH 2/4] [change] Reorder templates loaders in test --- tests/openwisp2/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/openwisp2/settings.py b/tests/openwisp2/settings.py index f5a381d9..f06d6962 100644 --- a/tests/openwisp2/settings.py +++ b/tests/openwisp2/settings.py @@ -94,8 +94,8 @@ "OPTIONS": { "loaders": [ "django.template.loaders.filesystem.Loader", - "openwisp_utils.loaders.DependencyLoader", "django.template.loaders.app_directories.Loader", + "openwisp_utils.loaders.DependencyLoader", ], "context_processors": [ "django.template.context_processors.debug", From 414522f34f8c6cc2d88ebd15af829c1181dd8e73 Mon Sep 17 00:00:00 2001 From: Alexandre Vincent Date: Tue, 2 Jun 2026 17:43:42 +0200 Subject: [PATCH 3/4] [change] Namespace admin templates and fix sample app overrides --- .../templates/admin/base_site.html | 91 +------------------ .../templates/admin/change_form.html | 36 +------- .../openwisp_notifications/base_site.html | 90 ++++++++++++++++++ .../openwisp_notifications/change_form.html | 35 +++++++ .../templates/admin/base_site.html | 2 +- .../templates/admin/change_form.html | 2 +- tests/openwisp2/settings.py | 3 +- 7 files changed, 131 insertions(+), 128 deletions(-) create mode 100644 openwisp_notifications/templates/admin/openwisp_notifications/base_site.html create mode 100644 openwisp_notifications/templates/admin/openwisp_notifications/change_form.html diff --git a/openwisp_notifications/templates/admin/base_site.html b/openwisp_notifications/templates/admin/base_site.html index e4205407..9ce09069 100644 --- a/openwisp_notifications/templates/admin/base_site.html +++ b/openwisp_notifications/templates/admin/base_site.html @@ -1,90 +1 @@ -{% extends "admin/base_site.html" %} -{% load i18n static notification_tags %} - -{% block extrastyle %} - {{ block.super }} - {% if request|should_load_notifications_widget %} - - - {% endif %} -{% endblock extrastyle %} - -{% block extrahead %} - {{ block.super }} - {% if request|should_load_notifications_widget and not media.js and 'jquery' not in block.super %} - - - {% endif %} -{% endblock %} - -{% block user-tools %} - {{ block.super }} - {% if request|should_load_notifications_widget %} - - {% csrf_token %} -
-
-
- - {% trans 'Mark all as read' %} - - - {% trans 'Notification Preferences' %} - -
-
-
-
-
-

{% trans 'No new notification.' %}

-
-
- {% endif %} -{% endblock %} - -{% block footer %} - {{ block.super }} - {% if request|should_load_notifications_widget %} -
-
- × -
-

-
-
- - -
-
-
- - - - {% endif %} -{% endblock footer %} +{% extends 'admin/openwisp_notifications/base_site.html' %} diff --git a/openwisp_notifications/templates/admin/change_form.html b/openwisp_notifications/templates/admin/change_form.html index e76434d4..388a3c33 100644 --- a/openwisp_notifications/templates/admin/change_form.html +++ b/openwisp_notifications/templates/admin/change_form.html @@ -1,35 +1 @@ -{% extends 'admin/change_form.html' %} - -{% comment %} - This template is required to supply information regarding the displayed object - from Django's template context to JavaScript for proper functioning of object notification - widget. Following data is supplied: - 1. object's app_label - 2. object's model_name - 3. object's primary key -{% endcomment %} - -{% block admin_change_form_document_ready %} - {{ block.super }} - {% if change %} - - {% endif %} -{% endblock %} +{% extends 'admin/openwisp_notifications/change_form.html' %} diff --git a/openwisp_notifications/templates/admin/openwisp_notifications/base_site.html b/openwisp_notifications/templates/admin/openwisp_notifications/base_site.html new file mode 100644 index 00000000..e4205407 --- /dev/null +++ b/openwisp_notifications/templates/admin/openwisp_notifications/base_site.html @@ -0,0 +1,90 @@ +{% extends "admin/base_site.html" %} +{% load i18n static notification_tags %} + +{% block extrastyle %} + {{ block.super }} + {% if request|should_load_notifications_widget %} + + + {% endif %} +{% endblock extrastyle %} + +{% block extrahead %} + {{ block.super }} + {% if request|should_load_notifications_widget and not media.js and 'jquery' not in block.super %} + + + {% endif %} +{% endblock %} + +{% block user-tools %} + {{ block.super }} + {% if request|should_load_notifications_widget %} + + {% csrf_token %} +
+
+
+ + {% trans 'Mark all as read' %} + + + {% trans 'Notification Preferences' %} + +
+
+
+
+
+

{% trans 'No new notification.' %}

+
+
+ {% endif %} +{% endblock %} + +{% block footer %} + {{ block.super }} + {% if request|should_load_notifications_widget %} +
+
+ × +
+

+
+
+ + +
+
+
+ + + + {% endif %} +{% endblock footer %} diff --git a/openwisp_notifications/templates/admin/openwisp_notifications/change_form.html b/openwisp_notifications/templates/admin/openwisp_notifications/change_form.html new file mode 100644 index 00000000..e76434d4 --- /dev/null +++ b/openwisp_notifications/templates/admin/openwisp_notifications/change_form.html @@ -0,0 +1,35 @@ +{% extends 'admin/change_form.html' %} + +{% comment %} + This template is required to supply information regarding the displayed object + from Django's template context to JavaScript for proper functioning of object notification + widget. Following data is supplied: + 1. object's app_label + 2. object's model_name + 3. object's primary key +{% endcomment %} + +{% block admin_change_form_document_ready %} + {{ block.super }} + {% if change %} + + {% endif %} +{% endblock %} diff --git a/tests/openwisp2/sample_notifications/templates/admin/base_site.html b/tests/openwisp2/sample_notifications/templates/admin/base_site.html index de62b4bb..d3042c76 100644 --- a/tests/openwisp2/sample_notifications/templates/admin/base_site.html +++ b/tests/openwisp2/sample_notifications/templates/admin/base_site.html @@ -1,4 +1,4 @@ -{% extends "admin/base_site.html" %} +{% extends 'admin/openwisp_notifications/base_site.html' %} {% block user-tools %} {{ block.super }}
diff --git a/tests/openwisp2/sample_notifications/templates/admin/change_form.html b/tests/openwisp2/sample_notifications/templates/admin/change_form.html index d389c019..85717625 100644 --- a/tests/openwisp2/sample_notifications/templates/admin/change_form.html +++ b/tests/openwisp2/sample_notifications/templates/admin/change_form.html @@ -1,4 +1,4 @@ -{% extends "admin/change_form.html" %} +{% extends 'admin/openwisp_notifications/change_form.html' %} {% block admin_change_form_document_ready %} {{ block.super }}
diff --git a/tests/openwisp2/settings.py b/tests/openwisp2/settings.py index f06d6962..f992d33f 100644 --- a/tests/openwisp2/settings.py +++ b/tests/openwisp2/settings.py @@ -203,9 +203,10 @@ pass if os.environ.get("SAMPLE_APP", False): + notifications_index = INSTALLED_APPS.index("openwisp_notifications") + INSTALLED_APPS.insert(notifications_index, "openwisp2.sample_notifications") INSTALLED_APPS.remove("openwisp_notifications") EXTENDED_APPS = ["openwisp_notifications"] - INSTALLED_APPS.append("openwisp2.sample_notifications") OPENWISP_NOTIFICATIONS_NOTIFICATION_MODEL = "sample_notifications.Notification" OPENWISP_NOTIFICATIONS_NOTIFICATIONSETTING_MODEL = ( "sample_notifications.NotificationSetting" From a0282045ddd9fb45c48f7da9860a067ef7e49dce Mon Sep 17 00:00:00 2001 From: Alexandre Vincent Date: Thu, 4 Jun 2026 18:13:36 +0200 Subject: [PATCH 4/4] [change] Fix test_admin to resolve static path via static() --- openwisp_notifications/tests/test_admin.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/openwisp_notifications/tests/test_admin.py b/openwisp_notifications/tests/test_admin.py index efd19fa4..e431b5c5 100644 --- a/openwisp_notifications/tests/test_admin.py +++ b/openwisp_notifications/tests/test_admin.py @@ -6,6 +6,7 @@ from django.contrib.auth import get_user_model from django.core.cache import cache from django.forms.widgets import MediaOrderConflictWarning +from django.templatetags.static import static from django.test import TestCase, override_settings, tag from django.urls import reverse @@ -190,11 +191,16 @@ def test_notification_preferences_button_staff_user(self): def test_base_site_template(self): response = self.client.get(self._url) - self.assertContains(response, "openwisp-notifications/css/loader.css") - self.assertContains(response, "openwisp-notifications/css/notifications.css") - self.assertContains(response, "openwisp-notifications/js/notifications.js") + self.assertContains(response, static("openwisp-notifications/css/loader.css")) self.assertContains( - response, "openwisp-notifications/js/vendor/reconnecting-websocket.min.js" + response, static("openwisp-notifications/css/notifications.css") + ) + self.assertContains( + response, static("openwisp-notifications/js/notifications.js") + ) + self.assertContains( + response, + static("openwisp-notifications/js/vendor/reconnecting-websocket.min.js"), ) self.assertContains(response, 'id="openwisp_notifications"')