Skip to content

Commit c9d6286

Browse files
committed
Add navlet tests
1 parent 02e9f23 commit c9d6286

File tree

2 files changed

+137
-2
lines changed

2 files changed

+137
-2
lines changed

tests/integration/web/navlets_test.py

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
from unittest.mock import patch
1+
from unittest.mock import Mock, patch
22

33
import pytest
44
from django.test.client import RequestFactory
55
from django.urls import reverse
66

77
from nav.models.profiles import Account, AccountDashboard, AccountNavlet
8-
from nav.web.navlets import add_navlet, modify_navlet
8+
from nav.web.navlets import add_navlet, modify_navlet, Navlet
99

1010

1111
class TestAddUserNavletView:
@@ -103,6 +103,103 @@ def test_given_non_existing_navlet_then_return_error(self, client):
103103
assert b"This widget no longer exists" in response.content
104104

105105

106+
class TestNavletPost:
107+
"""Tests for the Navlet.post method."""
108+
109+
def test_when_no_form_supplied_it_should_return_400(self, admin_account, dashboard):
110+
request = RequestFactory().post('/fake-url')
111+
navlet = Navlet()
112+
navlet.request = request
113+
navlet.account_navlet = AccountNavlet(
114+
account=admin_account,
115+
dashboard=dashboard,
116+
navlet='nav.web.navlets.alert.AlertWidget',
117+
preferences={},
118+
)
119+
120+
response = navlet.post(request)
121+
assert response.status_code == 400
122+
assert b'No form supplied' in response.content
123+
124+
def test_given_valid_form_it_should_save_preferences(
125+
self, admin_account, dashboard
126+
):
127+
request = RequestFactory().post('/fake-url')
128+
navlet = Navlet()
129+
navlet.request = request
130+
navlet.account_navlet = AccountNavlet(
131+
account=admin_account,
132+
dashboard=dashboard,
133+
navlet='nav.web.navlets.alert.AlertWidget',
134+
preferences={},
135+
)
136+
137+
# Mock valid form
138+
mock_form = Mock()
139+
mock_form.is_valid.return_value = True
140+
mock_form.cleaned_data = {'test_pref': 'test_value'}
141+
142+
with patch.object(navlet, 'get') as mock_get:
143+
mock_get.return_value = Mock()
144+
navlet.post(request, form=mock_form)
145+
146+
assert navlet.account_navlet.preferences['test_pref'] == 'test_value'
147+
148+
def test_given_invalid_form_it_should_call_handle_error_response(
149+
self, admin_account, dashboard
150+
):
151+
request = RequestFactory().post('/fake-url')
152+
navlet = Navlet()
153+
navlet.request = request
154+
navlet.account_navlet = AccountNavlet(
155+
account=admin_account,
156+
dashboard=dashboard,
157+
navlet='nav.web.navlets.alert.AlertWidget',
158+
preferences={},
159+
)
160+
161+
# Mock invalid form
162+
mock_form = Mock()
163+
mock_form.is_valid.return_value = False
164+
165+
with patch.object(navlet, 'handle_error_response') as mock_handle_error:
166+
mock_handle_error.return_value = Mock()
167+
navlet.post(request, form=mock_form)
168+
mock_handle_error.assert_called_once()
169+
170+
171+
class TestNavletHandleErrorResponse:
172+
"""Tests for the Navlet.handle_error_response method."""
173+
174+
def test_should_render_form_errors_in_context(self):
175+
request = RequestFactory().post('/fake-url')
176+
navlet = Navlet()
177+
178+
# Mock form with errors
179+
mock_form = Mock()
180+
mock_form.errors = {
181+
'field1': ['Error message 1'],
182+
'field2': ['Error message 2'],
183+
}
184+
185+
with (
186+
patch('nav.web.navlets.render') as mock_render,
187+
patch.object(navlet, 'get_context_data') as mock_context,
188+
patch.object(navlet, 'get_template_names') as mock_template,
189+
):
190+
mock_render.return_value = Mock()
191+
mock_context.return_value = {}
192+
mock_template.return_value = 'test_template.html'
193+
194+
navlet.handle_error_response(request, mock_form)
195+
196+
# Verify render was called with errors flattened into context
197+
context = mock_render.call_args[0][2]
198+
assert 'errors' in context
199+
assert 'Error message 1' in context['errors']
200+
assert 'Error message 2' in context['errors']
201+
202+
106203
def _get_dashboard_url(dashboard: AccountDashboard):
107204
return reverse('add-user-navlet', args=[dashboard.id])
108205

tests/integration/widget_test.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,44 @@ def test_given_navlet_id_when_navlet_type_is_invalid_then_return_error_widget(
130130
assert navlet.title == "Error"
131131

132132

133+
def test_given_htmx_request_with_non_existent_navlet_id_then_return_htmx_error_response(
134+
client, admin_account
135+
):
136+
"""
137+
Tests that dispatcher returns HTMX error response for non-existent navlet ID
138+
on HTMX requests
139+
"""
140+
url = reverse('get-user-navlet', kwargs={'navlet_id': 999})
141+
response = client.get(url, HTTP_HX_REQUEST='true')
142+
143+
assert response.status_code == 200
144+
assert response.context['error_message'] == 'This widget does not exist'
145+
146+
147+
def test_given_htmx_request_with_unauthorized_navlet_then_return_htmx_error_response(
148+
client, admin_account, non_admin_account
149+
):
150+
"""
151+
Tests that dispatcher returns HTMX error response for unauthorized access
152+
on HTMX requests
153+
"""
154+
dashboard = AccountDashboard.objects.create(
155+
account=non_admin_account, name="Private Dashboard", is_shared=False
156+
)
157+
private_navlet = AccountNavlet.objects.create(
158+
navlet="nav.web.navlets.welcome.WelcomeNavlet",
159+
account=non_admin_account,
160+
dashboard=dashboard,
161+
)
162+
163+
# Admin account tries to access non_admin_account's private navlet via HTMX
164+
url = reverse('get-user-navlet', kwargs={'navlet_id': private_navlet.id})
165+
response = client.get(url, HTTP_HX_REQUEST='true')
166+
167+
assert response.status_code == 200
168+
assert response.context['error_message'] == 'Not authorized to view this widget'
169+
170+
133171
#
134172
# Fixtures
135173
#

0 commit comments

Comments
 (0)