Files
santeh-ray/items/tests.py
Azimkin 27187c5e53
All checks were successful
Build and Push Docker Image / build (push) Successful in 30s
feat: add subcategory support for catalog and admin
- Introduced `Subcategory` model with migration and unique slug constraint per category
- Enabled subcategory assignment for items with validation to ensure category matching
- Updated catalog views to handle subcategories, filtering items accordingly
- Enhanced templates (`index.html`, `side-bar.html`, `item-list.html`, `detail.html`) to display subcategories
- Added dynamic subcategory dropdown in Django admin with category filtering
- Created JavaScript for admin subcategory handling and AJAX population
- Wrote comprehensive tests for subcategory functionality in views and admin
2026-04-26 22:53:45 +02:00

239 lines
8.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from django.test import TestCase, override_settings
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from items.models import Category, Item, ItemImage, Subcategory
@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, "Подсветка")
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_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_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/"')
def test_detail_page_shows_item_data(self):
ItemImage.objects.create(
item=self.sink,
image="items/sink-primary.jpg",
alt="Главное фото мойки",
sort_order=0,
is_primary=True,
)
response = self.client.get("/catalog/plumbing/kitchen-sink/")
self.assertEqual(response.status_code, 200)
self.assertContains(response, "Кухонная мойка")
self.assertContains(response, "Сантехника / Мойки")
self.assertContains(response, "Искусственный камень")
self.assertContains(response, "1600,00 руб.")
self.assertContains(response, "В наличии")
self.assertContains(response, "/media/items/sink-primary.jpg")
self.assertContains(response, "Главное фото мойки")
def test_detail_page_uses_primary_image_first(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/plumbing/kitchen-sink/")
self.assertContains(response, '<img src="/media/items/primary.jpg"', html=False)
def test_detail_page_unknown_item_returns_404(self):
response = self.client.get("/catalog/plumbing/unknown/")
self.assertEqual(response.status_code, 404)
def test_detail_page_wrong_category_returns_404(self):
response = self.client.get("/catalog/decor/kitchen-sink/")
self.assertEqual(response.status_code, 404)
def test_item_subcategory_must_belong_to_item_category(self):
item = Item(
name="Некорректный товар",
slug="invalid-item",
category=self.plumbing,
subcategory=self.decor_lights,
description="",
price="100.00",
is_available=True,
)
with self.assertRaises(ValidationError):
item.full_clean()
def test_admin_subcategories_endpoint_filters_by_category(self):
user = get_user_model().objects.create_superuser(
username="admin",
email="admin@example.com",
password="password",
)
self.client.force_login(user)
response = self.client.get(f"/admin/items/item/subcategories/?category_id={self.plumbing.id}")
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.json(),
{
"subcategories": [
{"id": self.sinks.id, "name": "Мойки"},
{"id": self.taps.id, "name": "Смесители"},
]
},
)
def test_admin_subcategories_endpoint_returns_empty_without_category(self):
user = get_user_model().objects.create_superuser(
username="admin",
email="admin@example.com",
password="password",
)
self.client.force_login(user)
response = self.client.get("/admin/items/item/subcategories/")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), {"subcategories": []})