from django.contrib.auth import get_user_model from django.db import IntegrityError from django.test import TestCase from django.urls import reverse from favorites.models import Favorite from items.models import Category, Item, ItemImage, Subcategory User = get_user_model() class FavoritePageTests(TestCase): def setUp(self): self.user = User.objects.create_user( username="marina", email="marina@example.com", password="StrongPassword123", is_active=True, ) self.plumbing = Category.objects.create(name="Сантехника", slug="plumbing") self.sinks = Subcategory.objects.create(name="Мойки", slug="sinks", category=self.plumbing) self.taps = Subcategory.objects.create(name="Смесители", slug="taps", category=self.plumbing) self.sink = Item.objects.create( name="Кухонная мойка", slug="kitchen-sink", category=self.plumbing, subcategory=self.sinks, description="Искусственный камень", price="1600.00", is_available=True, ) self.tap = Item.objects.create( name="Смеситель Mono", slug="mono-tap", category=self.plumbing, subcategory=self.taps, description="Однорычажный смеситель", price="320.00", is_available=False, ) def test_favorites_page_redirects_unauthenticated_users(self): response = self.client.get(reverse("favorites:index")) self.assertEqual(response.status_code, 302) self.assertIn(reverse("users:login"), response["Location"]) def test_favorites_page_shows_empty_state(self): self.client.force_login(self.user) response = self.client.get(reverse("favorites:index")) self.assertEqual(response.status_code, 200) self.assertContains(response, "В избранном пока нет товаров.") def test_favorites_page_shows_items_in_tile_grid(self): self.client.force_login(self.user) ItemImage.objects.create( item=self.sink, image="items/sink-primary.jpg", alt="Главное фото мойки", sort_order=0, is_primary=True, ) Favorite.objects.create(user=self.user, item=self.tap) Favorite.objects.create(user=self.user, item=self.sink) response = self.client.get(reverse("favorites:index")) self.assertEqual(response.status_code, 200) self.assertContains(response, "Избранное") self.assertContains(response, "Кухонная мойка") self.assertContains(response, "Смеситель Mono") self.assertContains(response, "/media/items/sink-primary.jpg") self.assertContains(response, 'href="/catalog/plumbing/kitchen-sink/"', html=False) self.assertContains(response, 'href="/catalog/plumbing/mono-tap/"', html=False) self.assertContains(response, "Удалить из избранного") def test_toggle_endpoint_adds_and_removes_favorite(self): self.client.force_login(self.user) add_response = self.client.post( reverse("favorites:toggle"), data={"item_id": self.sink.pk, "next": reverse("favorites:index")}, ) self.assertRedirects(add_response, reverse("favorites:index")) self.assertTrue(Favorite.objects.filter(user=self.user, item=self.sink).exists()) remove_response = self.client.post( reverse("favorites:toggle"), data={"item_id": self.sink.pk, "next": reverse("favorites:index")}, ) self.assertRedirects(remove_response, reverse("favorites:index")) self.assertFalse(Favorite.objects.filter(user=self.user, item=self.sink).exists()) def test_toggle_endpoint_returns_json_for_ajax_requests(self): self.client.force_login(self.user) response = self.client.post( reverse("favorites:toggle"), data={"item_id": self.sink.pk, "next": reverse("favorites:index")}, HTTP_X_REQUESTED_WITH="XMLHttpRequest", HTTP_ACCEPT="application/json", ) self.assertEqual(response.status_code, 200) self.assertEqual(response["Content-Type"], "application/json") self.assertEqual(response.json()["item_id"], self.sink.pk) self.assertTrue(response.json()["is_favorite"]) self.assertEqual(response.json()["favorite_count"], 1) self.assertTrue(Favorite.objects.filter(user=self.user, item=self.sink).exists()) def test_favorite_pair_is_unique_per_user_and_item(self): Favorite.objects.create(user=self.user, item=self.sink) with self.assertRaises(IntegrityError): Favorite.objects.create(user=self.user, item=self.sink)