from django.test import TestCase, override_settings from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError from favorites.models import Favorite from items.models import Category, Color, Item, ItemImage, Subcategory from orders.models import Cart, CartItem @override_settings(MEDIA_URL="/media/") class CatalogViewTests(TestCase): def setUp(self): self.plumbing = Category.objects.create(name="Сантехника", slug="plumbing") self.decor = Category.objects.create(name="Декор", slug="decor") self.sinks = Subcategory.objects.create(name="Мойки", slug="sinks", category=self.plumbing) self.taps = Subcategory.objects.create(name="Смесители", slug="taps", category=self.plumbing) self.decor_lights = Subcategory.objects.create(name="Подсветка", slug="lights", category=self.decor) self.sink = Item.objects.create( name="Кухонная мойка", slug="kitchen-sink", category=self.plumbing, subcategory=self.sinks, description="Искусственный камень, врезная на столешницу", price="1600.00", is_available=True, ) self.mirror = Item.objects.create( name="Зеркало Terra", slug="terra-mirror", category=self.decor, subcategory=self.decor_lights, description="Холодная подсветка, фронтальная", price="200.00", is_available=False, ) def test_catalog_page_shows_items_from_all_categories(self): response = self.client.get("/catalog/") self.assertEqual(response.status_code, 200) self.assertContains(response, "Кухонная мойка") self.assertContains(response, "Зеркало Terra") def test_category_page_shows_only_selected_category_items(self): response = self.client.get("/catalog/plumbing/") self.assertEqual(response.status_code, 200) self.assertContains(response, "Кухонная мойка") self.assertNotContains(response, "Зеркало Terra") def test_category_page_shows_only_selected_category_subcategories(self): response = self.client.get("/catalog/plumbing/") self.assertEqual(response.status_code, 200) self.assertContains(response, "Мойки") self.assertContains(response, "Смесители") self.assertNotContains(response, 'href="/catalog/decor/?subcategory=lights"') def test_subcategory_page_shows_only_selected_subcategory_items(self): Item.objects.create( name="Смеситель Mono", slug="mono-tap", category=self.plumbing, subcategory=self.taps, description="Однорычажный смеситель", price="320.00", is_available=True, ) response = self.client.get("/catalog/plumbing/?subcategory=sinks") self.assertEqual(response.status_code, 200) self.assertContains(response, "Кухонная мойка") self.assertNotContains(response, "Смеситель Mono") def test_catalog_search_filters_items_by_name(self): response = self.client.get("/catalog/", {"q": "мойка"}) self.assertEqual(response.status_code, 200) self.assertContains(response, "Кухонная мойка") self.assertNotContains(response, "Зеркало Terra") def test_catalog_search_is_case_insensitive(self): response = self.client.get("/catalog/", {"q": "МОЙКА"}) self.assertEqual(response.status_code, 200) self.assertContains(response, "Кухонная мойка") self.assertNotContains(response, "Зеркало Terra") def test_category_search_filters_items_within_selected_category(self): Item.objects.create( name="Смеситель Terra", slug="terra-tap", category=self.plumbing, subcategory=self.taps, description="Смеситель для ванной", price="450.00", is_available=True, ) response = self.client.get("/catalog/plumbing/", {"q": "terra"}) self.assertEqual(response.status_code, 200) self.assertContains(response, "Смеситель Terra") self.assertNotContains(response, "Зеркало Terra") def test_subcategory_search_filters_items_within_selected_subcategory(self): Item.objects.create( name="Terra Смеситель", slug="terra-tap", category=self.plumbing, subcategory=self.taps, description="Смеситель для раковины", price="450.00", is_available=True, ) Item.objects.create( name="Terra Мойка", slug="terra-sink", category=self.plumbing, subcategory=self.sinks, description="Кухонная мойка", price="900.00", is_available=True, ) response = self.client.get("/catalog/plumbing/", {"subcategory": "sinks", "q": "terra"}) self.assertEqual(response.status_code, 200) self.assertContains(response, "Terra Мойка") self.assertNotContains(response, "Terra Смеситель") def test_min_price_filters_items(self): response = self.client.get("/catalog/", {"min_price": "300"}) self.assertEqual(response.status_code, 200) self.assertContains(response, "Кухонная мойка") self.assertNotContains(response, "Зеркало Terra") def test_max_price_filters_items(self): response = self.client.get("/catalog/", {"max_price": "300"}) self.assertEqual(response.status_code, 200) self.assertContains(response, "Зеркало Terra") self.assertNotContains(response, "Кухонная мойка") def test_price_range_filters_items(self): Item.objects.create( name="Смеситель Mono", slug="mono-tap", category=self.plumbing, subcategory=self.taps, description="Однорычажный смеситель", price="320.00", is_available=True, ) response = self.client.get("/catalog/", {"min_price": "300", "max_price": "500"}) self.assertEqual(response.status_code, 200) self.assertContains(response, "Смеситель Mono") self.assertNotContains(response, "Кухонная мойка") self.assertNotContains(response, "Зеркало Terra") def test_header_search_redirects_to_selected_category_url(self): response = self.client.get( "/catalog/", {"category": "category:plumbing", "q": "terra", "min_price": "100", "max_price": "500"}, ) self.assertRedirects(response, "/catalog/plumbing/?q=terra&min_price=100&max_price=500") def test_header_search_redirects_to_selected_subcategory_url(self): response = self.client.get( "/catalog/", {"category": "subcategory:plumbing:sinks", "q": "terra", "min_price": "100", "max_price": "500"}, ) self.assertRedirects( response, "/catalog/plumbing/?subcategory=sinks&q=terra&min_price=100&max_price=500", ) def test_unknown_subcategory_returns_404(self): response = self.client.get("/catalog/plumbing/?subcategory=unknown") self.assertEqual(response.status_code, 404) def test_subcategory_from_another_category_returns_404(self): response = self.client.get("/catalog/plumbing/?subcategory=lights") self.assertEqual(response.status_code, 404) def test_unknown_category_returns_404(self): response = self.client.get("/catalog/unknown/") self.assertEqual(response.status_code, 404) def test_sidebar_shows_all_categories_and_all_items_link(self): response = self.client.get("/catalog/") self.assertContains(response, "Все товары") self.assertContains(response, "Сантехника") self.assertContains(response, "Декор") def test_sidebar_links_preserve_active_search_and_price_filters(self): response = self.client.get("/catalog/plumbing/", {"q": "terra", "min_price": "100", "max_price": "500"}) self.assertContains(response, 'href="/catalog/?q=terra&min_price=100&max_price=500"') self.assertContains(response, 'href="/catalog/plumbing/?q=terra&min_price=100&max_price=500"') self.assertContains( response, 'href="/catalog/plumbing/?subcategory=sinks&q=terra&min_price=100&max_price=500"', ) def test_catalog_forms_repeat_active_search_and_price_values(self): response = self.client.get( "/catalog/plumbing/", {"subcategory": "sinks", "q": "terra", "min_price": "100", "max_price": "500"}, ) self.assertContains(response, 'name="q" value="terra"', html=False) self.assertContains(response, 'name="min_price" value="100"', html=False) self.assertContains(response, 'name="max_price" value="500"', html=False) def test_catalog_price_filter_renders_range_slider(self): response = self.client.get("/catalog/") self.assertContains(response, 'data-price-slider', html=False) self.assertContains(response, 'type="range"', count=2, html=False) self.assertContains(response, 'min="200"', html=False) self.assertContains(response, 'max="1600"', html=False) self.assertContains(response, 'src="/static/js/catalog-price-slider.js"', html=False) def test_item_card_uses_primary_image(self): ItemImage.objects.create( item=self.sink, image="items/secondary.jpg", sort_order=0, is_primary=False, ) ItemImage.objects.create( item=self.sink, image="items/primary.jpg", sort_order=10, is_primary=True, ) response = self.client.get("/catalog/") self.assertContains(response, "/media/items/primary.jpg") self.assertNotContains(response, "/media/items/secondary.jpg") def test_item_card_shows_subcategory(self): response = self.client.get("/catalog/") self.assertContains(response, "Сантехника / Мойки") def test_item_card_uses_first_ordered_image_without_primary(self): ItemImage.objects.create( item=self.sink, image="items/second.jpg", sort_order=20, is_primary=False, ) ItemImage.objects.create( item=self.sink, image="items/first.jpg", sort_order=10, is_primary=False, ) response = self.client.get("/catalog/") self.assertContains(response, "/media/items/first.jpg") self.assertNotContains(response, "/media/items/second.jpg") def test_catalog_item_card_links_to_detail_page(self): response = self.client.get("/catalog/") self.assertContains(response, 'href="/catalog/plumbing/kitchen-sink/"') self.assertContains( response, '