2026-03-26 15:39:31 +03:30
|
|
|
from copy import deepcopy
|
2026-04-02 23:25:39 +03:30
|
|
|
from unittest.mock import patch
|
2026-03-26 15:39:31 +03:30
|
|
|
|
2026-04-02 23:25:39 +03:30
|
|
|
from django.contrib.auth import get_user_model
|
|
|
|
|
from django.test import TestCase
|
|
|
|
|
from rest_framework.test import APIRequestFactory, force_authenticate
|
2026-03-26 15:39:31 +03:30
|
|
|
|
2026-04-02 23:25:39 +03:30
|
|
|
from farm_hub.models import FarmHub, FarmType
|
2026-03-26 15:39:31 +03:30
|
|
|
|
2026-04-02 23:25:39 +03:30
|
|
|
from .mock_data import DEFAULT_CONFIG
|
|
|
|
|
from .models import FarmDashboardConfig
|
|
|
|
|
from .views import FarmDashboardCardsView, FarmDashboardConfigView
|
2026-03-26 15:39:31 +03:30
|
|
|
|
2026-04-02 23:25:39 +03:30
|
|
|
|
|
|
|
|
class DashboardBaseTestCase(TestCase):
|
2026-03-26 15:39:31 +03:30
|
|
|
def setUp(self):
|
|
|
|
|
self.factory = APIRequestFactory()
|
2026-04-02 23:25:39 +03:30
|
|
|
self.user = get_user_model().objects.create_user(
|
|
|
|
|
username="farmer",
|
|
|
|
|
password="secret123",
|
|
|
|
|
email="farmer@example.com",
|
|
|
|
|
phone_number="09120000000",
|
|
|
|
|
)
|
|
|
|
|
self.other_user = get_user_model().objects.create_user(
|
|
|
|
|
username="other-farmer",
|
|
|
|
|
password="secret123",
|
|
|
|
|
email="other@example.com",
|
|
|
|
|
phone_number="09120000001",
|
|
|
|
|
)
|
|
|
|
|
self.farm_type = FarmType.objects.create(name="زراعی")
|
|
|
|
|
self.farm = FarmHub.objects.create(owner=self.user, farm_type=self.farm_type, name="Farm 1")
|
|
|
|
|
self.other_farm = FarmHub.objects.create(owner=self.other_user, farm_type=self.farm_type, name="Farm 2")
|
2026-03-26 15:39:31 +03:30
|
|
|
|
|
|
|
|
|
2026-04-02 23:25:39 +03:30
|
|
|
class FarmDashboardConfigViewTests(DashboardBaseTestCase):
|
|
|
|
|
def test_get_returns_default_config_and_persists_it(self):
|
|
|
|
|
request = self.factory.get(f"/api/farm-dashboard-config/?farm_uuid={self.farm.farm_uuid}")
|
|
|
|
|
force_authenticate(request, user=self.user)
|
2026-03-26 15:39:31 +03:30
|
|
|
response = FarmDashboardConfigView.as_view()(request)
|
|
|
|
|
|
2026-04-02 23:25:39 +03:30
|
|
|
expected = deepcopy(DEFAULT_CONFIG)
|
|
|
|
|
expected["farm_uuid"] = str(self.farm.farm_uuid)
|
|
|
|
|
|
2026-03-26 15:39:31 +03:30
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
self.assertEqual(response.data["code"], 200)
|
|
|
|
|
self.assertEqual(response.data["msg"], "OK")
|
2026-04-02 23:25:39 +03:30
|
|
|
self.assertEqual(response.data["data"], expected)
|
|
|
|
|
self.assertTrue(FarmDashboardConfig.objects.filter(farm=self.farm).exists())
|
|
|
|
|
|
|
|
|
|
def test_get_requires_farm_uuid(self):
|
|
|
|
|
request = self.factory.get("/api/farm-dashboard-config/")
|
|
|
|
|
force_authenticate(request, user=self.user)
|
|
|
|
|
response = FarmDashboardConfigView.as_view()(request)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 400)
|
|
|
|
|
self.assertEqual(response.data["farm_uuid"][0], "This field is required.")
|
|
|
|
|
|
|
|
|
|
def test_get_rejects_foreign_farm_uuid(self):
|
|
|
|
|
request = self.factory.get(f"/api/farm-dashboard-config/?farm_uuid={self.other_farm.farm_uuid}")
|
|
|
|
|
force_authenticate(request, user=self.user)
|
|
|
|
|
response = FarmDashboardConfigView.as_view()(request)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 400)
|
|
|
|
|
self.assertEqual(response.data["farm_uuid"][0], "Farm not found.")
|
2026-03-26 15:39:31 +03:30
|
|
|
|
|
|
|
|
def test_patch_partial_update_returns_full_final_config(self):
|
|
|
|
|
request = self.factory.patch(
|
|
|
|
|
"/api/farm-dashboard-config/",
|
2026-04-02 23:25:39 +03:30
|
|
|
{
|
|
|
|
|
"farm_uuid": str(self.farm.farm_uuid),
|
|
|
|
|
"disabled_card_ids": ["farmWeatherCard"],
|
|
|
|
|
},
|
2026-03-26 15:39:31 +03:30
|
|
|
format="json",
|
|
|
|
|
)
|
2026-04-02 23:25:39 +03:30
|
|
|
force_authenticate(request, user=self.user)
|
2026-03-26 15:39:31 +03:30
|
|
|
response = FarmDashboardConfigView.as_view()(request)
|
|
|
|
|
|
|
|
|
|
expected = deepcopy(DEFAULT_CONFIG)
|
2026-04-02 23:25:39 +03:30
|
|
|
expected["farm_uuid"] = str(self.farm.farm_uuid)
|
2026-03-26 15:39:31 +03:30
|
|
|
expected["disabled_card_ids"] = ["farmWeatherCard"]
|
|
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
self.assertEqual(response.data["data"], expected)
|
2026-04-02 23:25:39 +03:30
|
|
|
self.assertEqual(
|
|
|
|
|
FarmDashboardConfig.objects.get(farm=self.farm).disabled_card_ids,
|
|
|
|
|
["farmWeatherCard"],
|
|
|
|
|
)
|
2026-03-26 15:39:31 +03:30
|
|
|
|
|
|
|
|
def test_patch_only_drag_flag_still_returns_full_config(self):
|
|
|
|
|
request = self.factory.patch(
|
|
|
|
|
"/api/farm-dashboard-config/",
|
2026-04-02 23:25:39 +03:30
|
|
|
{
|
|
|
|
|
"farm_uuid": str(self.farm.farm_uuid),
|
|
|
|
|
"enable_drag_reorder": False,
|
|
|
|
|
},
|
2026-03-26 15:39:31 +03:30
|
|
|
format="json",
|
|
|
|
|
)
|
2026-04-02 23:25:39 +03:30
|
|
|
force_authenticate(request, user=self.user)
|
2026-03-26 15:39:31 +03:30
|
|
|
response = FarmDashboardConfigView.as_view()(request)
|
|
|
|
|
|
|
|
|
|
expected = deepcopy(DEFAULT_CONFIG)
|
2026-04-02 23:25:39 +03:30
|
|
|
expected["farm_uuid"] = str(self.farm.farm_uuid)
|
2026-03-26 15:39:31 +03:30
|
|
|
expected["enable_drag_reorder"] = False
|
|
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
self.assertEqual(response.data["data"], expected)
|
|
|
|
|
self.assertIn("disabled_card_ids", response.data["data"])
|
|
|
|
|
self.assertIn("row_order", response.data["data"])
|
|
|
|
|
|
|
|
|
|
def test_patch_rejects_invalid_row_order(self):
|
|
|
|
|
request = self.factory.patch(
|
|
|
|
|
"/api/farm-dashboard-config/",
|
2026-04-02 23:25:39 +03:30
|
|
|
{
|
|
|
|
|
"farm_uuid": str(self.farm.farm_uuid),
|
|
|
|
|
"row_order": ["overviewKpis"],
|
|
|
|
|
},
|
2026-03-26 15:39:31 +03:30
|
|
|
format="json",
|
|
|
|
|
)
|
2026-04-02 23:25:39 +03:30
|
|
|
force_authenticate(request, user=self.user)
|
2026-03-26 15:39:31 +03:30
|
|
|
response = FarmDashboardConfigView.as_view()(request)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 400)
|
|
|
|
|
self.assertIn("row_order", response.data)
|
2026-04-02 23:25:39 +03:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class FarmDashboardCardsViewTests(DashboardBaseTestCase):
|
|
|
|
|
@patch("dashboard.views.external_api_request")
|
|
|
|
|
def test_get_forwards_farm_uuid_to_external_api(self, mock_external_api_request):
|
|
|
|
|
mock_external_api_request.return_value.data = {"status": "success", "data": {}}
|
|
|
|
|
mock_external_api_request.return_value.status_code = 200
|
|
|
|
|
|
|
|
|
|
request = self.factory.get(f"/api/farm-dashboard/?farm_uuid={self.farm.farm_uuid}")
|
|
|
|
|
force_authenticate(request, user=self.user)
|
|
|
|
|
|
|
|
|
|
response = FarmDashboardCardsView.as_view()(request)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
|
mock_external_api_request.assert_called_once_with(
|
|
|
|
|
"ai",
|
|
|
|
|
"/dashboard-data/status",
|
|
|
|
|
method="GET",
|
|
|
|
|
query={"farm_uuid": str(self.farm.farm_uuid)},
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def test_get_requires_farm_uuid(self):
|
|
|
|
|
request = self.factory.get("/api/farm-dashboard/")
|
|
|
|
|
force_authenticate(request, user=self.user)
|
|
|
|
|
|
|
|
|
|
response = FarmDashboardCardsView.as_view()(request)
|
|
|
|
|
|
|
|
|
|
self.assertEqual(response.status_code, 400)
|
|
|
|
|
self.assertEqual(response.data["farm_uuid"][0], "This field is required.")
|