287 lines
No EOL
13 KiB
Python
287 lines
No EOL
13 KiB
Python
from django.test import TestCase, Client
|
|
from django.template import Template, Context
|
|
from datetime import timedelta
|
|
|
|
from django.urls import reverse
|
|
from django.utils import timezone
|
|
|
|
from accounts.models import CustomUser, FriendCode
|
|
from cards.models import Card, Deck, DeckNameTranslation, CardNameTranslation
|
|
from trades.models import TradeOffer, TradeOfferHaveCard, TradeOfferWantCard
|
|
from cards.templatetags import card_badge, card_multiselect
|
|
|
|
class CardsModelsTestCase(TestCase):
|
|
def setUp(self):
|
|
self.deck = Deck.objects.create(
|
|
name="Test Deck", hex_color="#FFFFFF", cardset="A"
|
|
)
|
|
self.card = Card.objects.create(
|
|
name="Test Card",
|
|
cardset="A",
|
|
cardnum=1,
|
|
style="color: blue;",
|
|
rarity_icon="★",
|
|
rarity_level=1
|
|
)
|
|
# Establish many-to-many relationship.
|
|
self.card.decks.add(self.deck)
|
|
|
|
def test_card_str(self):
|
|
expected = f"{self.card.name} {self.card.rarity_icon} {self.card.cardset}"
|
|
self.assertEqual(str(self.card), expected)
|
|
|
|
def test_deck_str(self):
|
|
self.assertEqual(str(self.deck), self.deck.name)
|
|
|
|
def test_deck_name_translation_str(self):
|
|
deck_translation = DeckNameTranslation.objects.create(
|
|
name="Deck Translated", deck=self.deck, language="en"
|
|
)
|
|
self.assertEqual(str(deck_translation), "Deck Translated")
|
|
|
|
def test_card_name_translation_str(self):
|
|
card_translation = CardNameTranslation.objects.create(
|
|
name="Card Translated", card=self.card, language="en"
|
|
)
|
|
self.assertEqual(str(card_translation), "Card Translated")
|
|
|
|
class CardTemplatetagsTestCase(TestCase):
|
|
def setUp(self):
|
|
# Create a dummy card to use in template tag tests.
|
|
self.card = Card.objects.create(
|
|
name="Template Test Card",
|
|
cardset="B",
|
|
cardnum=2,
|
|
style="background: green;",
|
|
rarity_icon="☆",
|
|
rarity_level=2
|
|
)
|
|
|
|
def test_card_badge_inclusion_tag(self):
|
|
"""Test the card_badge inclusion tag renders correctly."""
|
|
template_str = '{% load card_badge %}{% card_badge card quantity=3 %}'
|
|
t = Template(template_str)
|
|
c = Context({"card": self.card})
|
|
rendered = t.render(c)
|
|
# Check that the rendered HTML contains the card name, quantity, and rarity.
|
|
self.assertIn(self.card.name, rendered)
|
|
self.assertIn("3", rendered)
|
|
self.assertIn(self.card.rarity_icon, rendered)
|
|
|
|
def test_card_badge_inline_filter(self):
|
|
"""Test the card_badge_inline filter returns safe HTML with correct data."""
|
|
template_str = '{% load card_badge %}{{ card|card_badge_inline:5 }}'
|
|
t = Template(template_str)
|
|
c = Context({"card": self.card})
|
|
rendered = t.render(c)
|
|
self.assertIn(self.card.name, rendered)
|
|
self.assertIn("5", rendered)
|
|
self.assertIn(self.card.rarity_icon, rendered)
|
|
|
|
def test_card_multiselect_tag_no_selected_values(self):
|
|
"""Test card_multiselect tag with no selected values."""
|
|
context = card_multiselect.card_multiselect(
|
|
field_name="cards",
|
|
label="Select Cards",
|
|
placeholder="Choose a card",
|
|
cards=[self.card],
|
|
selected_values=None,
|
|
)
|
|
self.assertEqual(context["field_name"], "cards")
|
|
self.assertEqual(context["label"], "Select Cards")
|
|
self.assertEqual(context["placeholder"], "Choose a card")
|
|
# When no cards are preselected, each card should have default attributes.
|
|
for card in context["cards"]:
|
|
self.assertFalse(getattr(card, "selected", False))
|
|
self.assertEqual(getattr(card, "selected_quantity", 1), 1)
|
|
self.assertEqual(context["selected_values"], [])
|
|
|
|
def test_card_multiselect_tag_with_selected_values(self):
|
|
"""Test card_multiselect tag with preselected values (testing both with and without explicit quantity)."""
|
|
# Create a second card.
|
|
card2 = Card.objects.create(
|
|
name="Another Card",
|
|
cardset="B",
|
|
cardnum=3,
|
|
style="background: blue;",
|
|
rarity_icon="★",
|
|
rarity_level=2,
|
|
)
|
|
selected_values = [f"{self.card.pk}:4", f"{card2.pk}"]
|
|
context = card_multiselect.card_multiselect(
|
|
field_name="cards",
|
|
label="Select Cards",
|
|
placeholder="Choose a card",
|
|
cards=[self.card, card2],
|
|
selected_values=selected_values,
|
|
)
|
|
# Verify that self.card is marked as selected with quantity "4" and card2 with default quantity 1.
|
|
for card in context["cards"]:
|
|
if card.pk == self.card.pk:
|
|
self.assertTrue(getattr(card, "selected", False))
|
|
self.assertEqual(getattr(card, "selected_quantity", 1), "4")
|
|
elif card.pk == card2.pk:
|
|
self.assertTrue(getattr(card, "selected", False))
|
|
self.assertEqual(getattr(card, "selected_quantity", 1), 1)
|
|
else:
|
|
self.fail("Unexpected card in the multiselect context.")
|
|
self.assertCountEqual(
|
|
context["selected_values"], [str(self.card.pk), str(card2.pk)]
|
|
)
|
|
|
|
def test_card_multiselect_default_cards_when_none_provided(self):
|
|
"""Test that card_multiselect defaults to Card.objects.all() when no cards are provided."""
|
|
# Capture all cards from the database.
|
|
default_cards = list(Card.objects.all())
|
|
context = card_multiselect.card_multiselect(
|
|
field_name="cards",
|
|
label="Select Cards",
|
|
placeholder="Choose a card",
|
|
cards=None,
|
|
selected_values=[],
|
|
)
|
|
# Verify that the context's cards match those in the database.
|
|
self.assertEqual(list(context["cards"]), default_cards)
|
|
|
|
class CardsViewsTestCase(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
# Create a test user and friend code for trade offers.
|
|
self.user = CustomUser.objects.create_user(
|
|
username="testuser", password="secret", email="test@example.com"
|
|
)
|
|
self.friendcode = FriendCode.objects.create(
|
|
user=self.user, friend_code="1234-5678-9012", in_game_name="TestPlayer"
|
|
)
|
|
# Create a test card.
|
|
self.card = Card.objects.create(
|
|
name="Test Card",
|
|
cardset="A",
|
|
cardnum=1,
|
|
style="background: red;",
|
|
rarity_icon="★",
|
|
rarity_level=1
|
|
)
|
|
|
|
def test_card_detail_view_context(self):
|
|
"""Test that the card detail view includes correct trade offer counts in context."""
|
|
# Create a trade offer where the card appears as a "have" card.
|
|
trade_offer_have = TradeOffer.objects.create(initiated_by=self.friendcode)
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=trade_offer_have, card=self.card, quantity=2
|
|
)
|
|
|
|
# Create a trade offer where the card appears as a "want" card.
|
|
trade_offer_want = TradeOffer.objects.create(initiated_by=self.friendcode)
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=trade_offer_want, card=self.card, quantity=3
|
|
)
|
|
|
|
url = reverse("cards:card_detail", kwargs={"pk": self.card.pk})
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 200)
|
|
# Verify that the card instance is in context.
|
|
self.assertEqual(response.context["card"], self.card)
|
|
# Verify that the counts are correctly computed.
|
|
self.assertEqual(response.context.get("trade_offer_have_count"), 1)
|
|
self.assertEqual(response.context.get("trade_offer_want_count"), 1)
|
|
|
|
def test_card_detail_view_404(self):
|
|
"""Test that the card detail view returns a 404 for a non-existent card."""
|
|
url = reverse("cards:card_detail", kwargs={"pk": 99999})
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 404)
|
|
|
|
def create_trade_offer_for_have(self, updated_delta_minutes=0):
|
|
"""
|
|
Helper method to create a trade offer for the 'have' side with a custom updated_at.
|
|
"""
|
|
offer = TradeOffer.objects.create(initiated_by=self.friendcode)
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=offer, card=self.card, quantity=1
|
|
)
|
|
# Adjust updated_at so that ordering can be tested.
|
|
new_time = timezone.now() + timedelta(minutes=updated_delta_minutes)
|
|
TradeOffer.objects.filter(pk=offer.pk).update(updated_at=new_time)
|
|
offer.refresh_from_db()
|
|
return offer
|
|
|
|
def create_trade_offer_for_want(self, updated_delta_minutes=0):
|
|
"""
|
|
Helper method to create a trade offer for the 'want' side with a custom updated_at.
|
|
"""
|
|
offer = TradeOffer.objects.create(initiated_by=self.friendcode)
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=offer, card=self.card, quantity=1
|
|
)
|
|
new_time = timezone.now() + timedelta(minutes=updated_delta_minutes)
|
|
TradeOffer.objects.filter(pk=offer.pk).update(updated_at=new_time)
|
|
offer.refresh_from_db()
|
|
return offer
|
|
|
|
def test_trade_offer_have_list_view_pagination_and_ordering(self):
|
|
"""Test the have list view for correct pagination and ordering."""
|
|
# Create three trade offers with distinct updated_at times.
|
|
offer1 = self.create_trade_offer_for_have(updated_delta_minutes=1)
|
|
offer2 = self.create_trade_offer_for_have(updated_delta_minutes=2)
|
|
offer3 = self.create_trade_offer_for_have(updated_delta_minutes=3)
|
|
|
|
url = reverse("cards:card_trade_offer_have_list", kwargs={"pk": self.card.pk})
|
|
|
|
# Test default ordering ("newest" which orders descending by updated_at).
|
|
response = self.client.get(url, {"order": "newest"})
|
|
self.assertEqual(response.status_code, 200)
|
|
trade_offers = response.context.get("trade_offers")
|
|
self.assertEqual(response.context.get("side"), "have")
|
|
# With paginate_by=2, the first page should have 2 offers.
|
|
self.assertEqual(len(trade_offers), 2)
|
|
# The first offer should be the newest (offer3).
|
|
self.assertEqual(trade_offers[0].pk, offer3.pk)
|
|
self.assertEqual(trade_offers[1].pk, offer2.pk)
|
|
|
|
# Test pagination: second page should contain the remaining offer.
|
|
response_page2 = self.client.get(url, {"order": "newest", "page": 2})
|
|
self.assertEqual(response_page2.status_code, 200)
|
|
trade_offers_page2 = response_page2.context.get("trade_offers")
|
|
self.assertEqual(len(trade_offers_page2), 1)
|
|
self.assertEqual(trade_offers_page2[0].pk, offer1.pk)
|
|
|
|
# Test "oldest" ordering (ascending by updated_at).
|
|
response_oldest = self.client.get(url, {"order": "oldest"})
|
|
self.assertEqual(response_oldest.status_code, 200)
|
|
trade_offers_oldest = response_oldest.context.get("trade_offers")
|
|
self.assertEqual(len(trade_offers_oldest), 2)
|
|
self.assertEqual(trade_offers_oldest[0].pk, offer1.pk)
|
|
self.assertEqual(trade_offers_oldest[1].pk, offer2.pk)
|
|
|
|
def test_trade_offer_want_list_view_pagination_and_ordering(self):
|
|
"""Test the want list view for correct pagination and ordering."""
|
|
offer1 = self.create_trade_offer_for_want(updated_delta_minutes=1)
|
|
offer2 = self.create_trade_offer_for_want(updated_delta_minutes=2)
|
|
offer3 = self.create_trade_offer_for_want(updated_delta_minutes=3)
|
|
|
|
url = reverse("cards:card_trade_offer_want_list", kwargs={"pk": self.card.pk})
|
|
|
|
# Test order with "newest" first.
|
|
response = self.client.get(url, {"order": "newest"})
|
|
self.assertEqual(response.status_code, 200)
|
|
trade_offers = response.context.get("trade_offers")
|
|
self.assertEqual(response.context.get("side"), "want")
|
|
self.assertEqual(len(trade_offers), 2)
|
|
self.assertEqual(trade_offers[0].pk, offer3.pk)
|
|
self.assertEqual(trade_offers[1].pk, offer2.pk)
|
|
|
|
# Test pagination boundary on page 2.
|
|
response_page2 = self.client.get(url, {"order": "newest", "page": 2})
|
|
self.assertEqual(response_page2.status_code, 200)
|
|
trade_offers_page2 = response_page2.context.get("trade_offers")
|
|
self.assertEqual(len(trade_offers_page2), 1)
|
|
self.assertEqual(trade_offers_page2[0].pk, offer1.pk)
|
|
|
|
# Test ordering parameter for "oldest" ordering.
|
|
response_oldest = self.client.get(url, {"order": "oldest"})
|
|
self.assertEqual(response_oldest.status_code, 200)
|
|
trade_offers_oldest = response_oldest.context.get("trade_offers")
|
|
self.assertEqual(len(trade_offers_oldest), 2)
|
|
self.assertEqual(trade_offers_oldest[0].pk, offer1.pk)
|
|
self.assertEqual(trade_offers_oldest[1].pk, offer2.pk) |