HH/apps/observations/test_workflow_realignment.py
ismail 615b8467ef fix(review): observation dept_manager button gate + appreciation status guard
Two issues from the whole-branch review:

1. (Important) Observation detail's can_respond_to_department context var
   did not include is_department_manager, so even though Task 2 let dept
   managers pass the view's permission check, the 'Submit Response'
   button stayed hidden from them. Now the context var matches the view
   predicate. Regression test added.

2. (Minor) appreciation_list had no guard against now-invalid status
   query params (?status=acknowledged from an old bookmark would show
   an unexplained empty list). Unknown values are now silently reset
   to 'all statuses'.
2026-07-20 22:38:12 +03:00

110 lines
4.7 KiB
Python

"""Tests for the observation workflow realignment."""
from django.contrib.auth.models import Group
import pytest
from django.test import TestCase
from django.urls import reverse
from apps.accounts.models import User
from apps.organizations.models import Department, Hospital
from apps.observations.models import Observation
def _ensure_group(name):
"""Get or create a role group (pytest runs with --nomigrations, so seeded
groups may not exist in the test DB)."""
grp, _ = Group.objects.get_or_create(name=name)
return grp
@pytest.mark.django_db
class TestObservationDepartmentResponsePermission(TestCase):
"""A department manager of the assigned department can respond.
Uses self.client (full middleware incl. django.contrib.messages) — the
view calls messages.error() on the permission-denied path. The project's
root conftest.py disables ManifestStaticFilesStorage for all tests.
"""
def setUp(self):
self.hospital = Hospital.objects.create(name="Test Hospital", code="TH02")
self.dept = Department.objects.create(name="Dept A", hospital=self.hospital, code="OA")
self.other_dept = Department.objects.create(name="Dept B", hospital=self.hospital, code="OB")
_ensure_group("Department Manager")
self.dept_manager = User.objects.create_user(
username="odmgr", email="odmgr@test", password="x", department=self.dept
)
self.dept_manager.groups.add(Group.objects.get(name="Department Manager"))
self.other_manager = User.objects.create_user(
username="oother", email="oo@test", password="x", department=self.other_dept
)
self.other_manager.groups.add(Group.objects.get(name="Department Manager"))
self.observation = Observation.objects.create(
description="Test observation description here",
hospital=self.hospital,
assigned_department=self.dept,
sent_to_department=True,
status="in_progress",
)
def test_dept_manager_of_assigned_dept_can_access_response_view(self):
"""GET to observation_department_response succeeds (200) for dept manager of assigned dept."""
self.client.force_login(self.dept_manager)
response = self.client.get(
reverse("observations:observation_department_response", kwargs={"pk": self.observation.pk})
)
assert response.status_code == 200, \
f"dept_manager of assigned dept should be allowed, got {response.status_code}"
def test_dept_manager_of_other_dept_cannot_access(self):
"""Dept manager of a non-assigned department is denied (302 redirect)."""
self.client.force_login(self.other_manager)
response = self.client.get(
reverse("observations:observation_department_response", kwargs={"pk": self.observation.pk})
)
assert response.status_code == 302, \
f"dept_manager of other dept should be redirected (denied), got {response.status_code}"
@pytest.mark.django_db
class TestObservationDetailRespondButtonGate(TestCase):
"""The 'Submit Response' button must be visible to dept_manager of the
assigned department — not just pass the view's permission check.
Locks in the fix for the Important issue found in whole-branch review:
Task 2 added dept_manager to the view predicate but the template context
var `can_respond_to_department` was missed, so the button stayed hidden.
"""
def setUp(self):
self.hospital = Hospital.objects.create(name="Test Hospital Gate", code="TH04")
self.dept = Department.objects.create(name="Dept Gate", hospital=self.hospital, code="GT")
_ensure_group("Department Manager")
self.dept_manager = User.objects.create_user(
username="gdmgr", email="gdmgr@test", password="x", department=self.dept
)
self.dept_manager.groups.add(Group.objects.get(name="Department Manager"))
self.observation = Observation.objects.create(
description="Gate test observation",
hospital=self.hospital,
assigned_department=self.dept,
sent_to_department=True,
department_responded_at=None,
status="in_progress",
)
def test_dept_manager_sees_respond_button(self):
"""The department detail page renders the respond control for dept managers."""
self.client.force_login(self.dept_manager)
response = self.client.get(
reverse("observations:observation_detail", kwargs={"pk": self.observation.pk})
)
assert response.status_code == 200
assert response.context["can_respond_to_department"] is True, \
"dept_manager of assigned dept must see can_respond_to_department=True"