590 lines
21 KiB
Python
590 lines
21 KiB
Python
from django.test import TestCase, Client, RequestFactory
|
|
from django.urls import reverse
|
|
from django.contrib.auth import get_user_model
|
|
from cards.models import Card, Deck
|
|
from trades.models import TradeOffer, TradeOfferHaveCard, TradeOfferWantCard
|
|
from accounts.models import FriendCode
|
|
from home.views import HomePageView
|
|
import json
|
|
from collections import OrderedDict
|
|
from unittest.mock import patch, MagicMock
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
import importlib
|
|
|
|
User = get_user_model()
|
|
|
|
class HomePageViewTests(TestCase):
|
|
"""Test suite for the HomePageView."""
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
"""Set up data for all test methods."""
|
|
# Create a user
|
|
cls.user = User.objects.create_user(
|
|
username='testuser',
|
|
email='testuser@example.com',
|
|
password='testpass123'
|
|
)
|
|
|
|
# Create a friend code for the user
|
|
cls.friend_code = FriendCode.objects.create(
|
|
user=cls.user,
|
|
friend_code='SW-1234-5678-9012',
|
|
in_game_name='TestTrainer'
|
|
)
|
|
|
|
# Create decks
|
|
cls.deck1 = Deck.objects.create(
|
|
name='Test Deck 1',
|
|
hex_color='#FF0000',
|
|
cardset='TEST01'
|
|
)
|
|
|
|
# Create cards with different rarities
|
|
cls.common_card = Card.objects.create(
|
|
name='Common Test Card',
|
|
cardset='TEST01',
|
|
cardnum=1,
|
|
style='normal',
|
|
rarity_icon='★',
|
|
rarity_level=1
|
|
)
|
|
cls.common_card.decks.add(cls.deck1)
|
|
|
|
cls.rare_card = Card.objects.create(
|
|
name='Rare Test Card',
|
|
cardset='TEST01',
|
|
cardnum=2,
|
|
style='normal',
|
|
rarity_icon='★★★',
|
|
rarity_level=3
|
|
)
|
|
cls.rare_card.decks.add(cls.deck1)
|
|
|
|
cls.ultra_rare_card = Card.objects.create(
|
|
name='Ultra Rare Test Card',
|
|
cardset='TEST01',
|
|
cardnum=3,
|
|
style='normal',
|
|
rarity_icon='★★★★',
|
|
rarity_level=4
|
|
)
|
|
cls.ultra_rare_card.decks.add(cls.deck1)
|
|
|
|
# Create trade offers with consistent rarities
|
|
cls.common_trade = TradeOffer.objects.create(
|
|
initiated_by=cls.friend_code,
|
|
rarity_icon='★',
|
|
rarity_level=1
|
|
)
|
|
|
|
cls.rare_trade = TradeOffer.objects.create(
|
|
initiated_by=cls.friend_code,
|
|
rarity_icon='★★★',
|
|
rarity_level=3
|
|
)
|
|
|
|
# Add have and want cards with the SAME rarity for each trade
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=cls.common_trade,
|
|
card=cls.common_card,
|
|
quantity=2
|
|
)
|
|
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=cls.rare_trade,
|
|
card=cls.rare_card,
|
|
quantity=1
|
|
)
|
|
|
|
# Add want cards with the SAME rarity as the have cards for each trade
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=cls.common_trade,
|
|
card=cls.common_card,
|
|
quantity=1
|
|
)
|
|
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=cls.rare_trade,
|
|
card=cls.rare_card, # Changed from ultra_rare_card to match the rarity
|
|
quantity=1
|
|
)
|
|
|
|
def setUp(self):
|
|
"""Set up before each test method."""
|
|
self.client = Client()
|
|
self.url = reverse('home')
|
|
self.factory = RequestFactory()
|
|
|
|
def test_home_page_status_code(self):
|
|
"""Test that the home page returns a 200 status code."""
|
|
response = self.client.get(self.url)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_home_page_template(self):
|
|
"""Test that the home page uses the correct template."""
|
|
response = self.client.get(self.url)
|
|
self.assertTemplateUsed(response, 'home/home.html')
|
|
|
|
def test_home_page_context_cards(self):
|
|
"""Test that the home page contains all cards in the context."""
|
|
response = self.client.get(self.url)
|
|
self.assertIn('cards', response.context)
|
|
self.assertEqual(response.context['cards'].count(), 3)
|
|
|
|
def test_home_page_context_recent_offers(self):
|
|
"""Test that the home page contains recent offers in the context."""
|
|
response = self.client.get(self.url)
|
|
self.assertIn('recent_offers', response.context)
|
|
self.assertEqual(len(response.context['recent_offers']), 2)
|
|
# Recent offers should be ordered by most recent first
|
|
self.assertEqual(response.context['recent_offers'][0], self.rare_trade)
|
|
|
|
def test_home_page_context_most_offered_cards(self):
|
|
"""Test that the home page contains most offered cards in the context."""
|
|
response = self.client.get(self.url)
|
|
self.assertIn('most_offered_cards', response.context)
|
|
most_offered = list(response.context['most_offered_cards'])
|
|
self.assertEqual(len(most_offered), 2)
|
|
# Common card should be most offered (quantity of 2)
|
|
self.assertEqual(most_offered[0], self.common_card)
|
|
|
|
def test_home_page_context_most_wanted_cards(self):
|
|
"""Test that the home page contains most wanted cards in the context."""
|
|
response = self.client.get(self.url)
|
|
self.assertIn('most_wanted_cards', response.context)
|
|
most_wanted = list(response.context['most_wanted_cards'])
|
|
self.assertEqual(len(most_wanted), 2)
|
|
|
|
def test_home_page_context_least_offered_cards(self):
|
|
"""Test that the home page contains least offered cards in the context."""
|
|
response = self.client.get(self.url)
|
|
self.assertIn('least_offered_cards', response.context)
|
|
|
|
def test_home_page_context_featured_offers(self):
|
|
"""Test that the home page contains featured offers in the context."""
|
|
response = self.client.get(self.url)
|
|
self.assertIn('featured_offers', response.context)
|
|
featured = response.context['featured_offers']
|
|
# Should be an OrderedDict
|
|
self.assertIsInstance(featured, OrderedDict)
|
|
# Should contain "All" category
|
|
self.assertIn("All", featured)
|
|
# Should contain both rarity icons
|
|
self.assertIn('★★★', featured)
|
|
self.assertIn('★', featured)
|
|
# Higher rarity should come before lower rarity
|
|
keys = list(featured.keys())
|
|
# First key should be "All"
|
|
self.assertEqual(keys[0], "All")
|
|
# Higher rarity (★★★) should come before lower rarity (★)
|
|
self.assertIn('★★★', keys)
|
|
self.assertIn('★', keys)
|
|
self.assertTrue(keys.index('★★★') < keys.index('★'))
|
|
|
|
def test_closed_offers_not_shown(self):
|
|
"""Test that closed offers are not shown on the home page."""
|
|
# Close one of the trade offers
|
|
self.common_trade.is_closed = True
|
|
self.common_trade.save()
|
|
|
|
response = self.client.get(self.url)
|
|
recent_offers = response.context['recent_offers']
|
|
# Should only show the rare trade now
|
|
self.assertEqual(len(recent_offers), 1)
|
|
self.assertEqual(recent_offers[0], self.rare_trade)
|
|
|
|
def test_home_page_with_no_data(self):
|
|
"""Test home page rendering when there's no trade data."""
|
|
# Delete all trade offers
|
|
TradeOffer.objects.all().delete()
|
|
|
|
response = self.client.get(self.url)
|
|
self.assertEqual(response.status_code, 200)
|
|
# Should have empty lists for offers
|
|
self.assertEqual(len(response.context['recent_offers']), 0)
|
|
|
|
def test_home_page_with_authenticated_user(self):
|
|
"""Test that the home page works for authenticated users."""
|
|
self.client.login(username='testuser', password='testpass123')
|
|
response = self.client.get(self.url)
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_rarity_sorting_in_featured_offers(self):
|
|
"""Test that offers are sorted by rarity level in descending order."""
|
|
# Create a new ultra rare trade with consistent rarity
|
|
ultra_trade = TradeOffer.objects.create(
|
|
initiated_by=self.friend_code,
|
|
rarity_icon='★★★★',
|
|
rarity_level=4
|
|
)
|
|
|
|
# Add have and want cards with the same rarity
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=ultra_trade,
|
|
card=self.ultra_rare_card,
|
|
quantity=1
|
|
)
|
|
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=ultra_trade,
|
|
card=self.ultra_rare_card,
|
|
quantity=1
|
|
)
|
|
|
|
response = self.client.get(self.url)
|
|
featured = response.context['featured_offers']
|
|
keys = list(featured.keys())
|
|
|
|
# Order should be: "All", "★★★★" (level 4), "★★★" (level 3), "★" (level 1)
|
|
self.assertEqual(keys[0], "All")
|
|
self.assertEqual(keys[1], "★★★★")
|
|
self.assertEqual(keys[2], "★★★")
|
|
self.assertEqual(keys[3], "★")
|
|
|
|
|
|
class HomePageViewMockTests(TestCase):
|
|
"""Test suite using mocks for HomePageView."""
|
|
|
|
def setUp(self):
|
|
self.factory = RequestFactory()
|
|
self.view = HomePageView()
|
|
|
|
@patch('trades.models.TradeOffer.objects')
|
|
@patch('cards.models.Card.objects')
|
|
def test_get_context_data_with_mocks(self, mock_card_objects, mock_offer_objects):
|
|
"""Test get_context_data using mocks."""
|
|
# Set up request
|
|
request = self.factory.get(reverse('home'))
|
|
self.view.request = request
|
|
|
|
# Mock the queryset responses
|
|
mock_offer_filter = MagicMock()
|
|
mock_offer_objects.filter.return_value = mock_offer_filter
|
|
mock_offer_filter.order_by.return_value = []
|
|
|
|
mock_card_filter = MagicMock()
|
|
mock_card_objects.filter.return_value = mock_card_filter
|
|
mock_card_objects.annotate.return_value = mock_card_filter
|
|
mock_card_objects.all.return_value.order_by.return_value = []
|
|
mock_card_filter.annotate.return_value = mock_card_filter
|
|
mock_card_filter.order_by.return_value = []
|
|
|
|
mock_offer_filter.values_list.return_value.distinct.return_value = []
|
|
|
|
# Call the method
|
|
context = self.view.get_context_data()
|
|
|
|
# Verify the expected context keys exist
|
|
self.assertIn('cards', context)
|
|
self.assertIn('recent_offers', context)
|
|
self.assertIn('most_offered_cards', context)
|
|
self.assertIn('most_wanted_cards', context)
|
|
self.assertIn('least_offered_cards', context)
|
|
self.assertIn('featured_offers', context)
|
|
|
|
@patch('trades.models.TradeOffer.objects')
|
|
def test_empty_featured_offers(self, mock_offer_objects):
|
|
"""Test handling of empty featured offers."""
|
|
# Set up request
|
|
request = self.factory.get(reverse('home'))
|
|
self.view.request = request
|
|
|
|
# Configure mock to return empty queryset
|
|
mock_offer_filter = MagicMock()
|
|
mock_offer_objects.filter.return_value = mock_offer_filter
|
|
mock_offer_filter.order_by.return_value = []
|
|
mock_offer_filter.values_list.return_value.distinct.return_value = []
|
|
|
|
# Call the method
|
|
context = self.view.get_context_data()
|
|
|
|
# Verify the featured_offers is an OrderedDict but with just the "All" key
|
|
self.assertIsInstance(context['featured_offers'], OrderedDict)
|
|
self.assertIn("All", context['featured_offers'])
|
|
self.assertEqual(len(context['featured_offers']), 1)
|
|
|
|
@patch('trades.models.TradeOffer.objects.filter')
|
|
def test_exception_handling(self, mock_filter):
|
|
"""Test that exceptions are handled gracefully."""
|
|
# Set up request
|
|
request = self.factory.get(reverse('home'))
|
|
self.view.request = request
|
|
|
|
# Configure mock to raise an exception
|
|
mock_filter.side_effect = Exception("Database error")
|
|
|
|
# Call the method - should not raise an exception
|
|
with self.assertLogs(level='ERROR') as cm:
|
|
context = self.view.get_context_data()
|
|
|
|
# Check if error was logged
|
|
self.assertIn("Unhandled error in HomePageView.get_context_data", cm.output[0])
|
|
|
|
# Verify fallback values were set
|
|
self.assertEqual(len(context['cards']), 0)
|
|
self.assertEqual(len(context['recent_offers']), 0)
|
|
self.assertEqual(len(context['most_offered_cards']), 0)
|
|
self.assertEqual(len(context['most_wanted_cards']), 0)
|
|
self.assertEqual(len(context['least_offered_cards']), 0)
|
|
self.assertIsInstance(context['featured_offers'], OrderedDict)
|
|
self.assertEqual(len(context['featured_offers']), 1)
|
|
self.assertIn("All", context['featured_offers'])
|
|
|
|
class HomePageEdgeCaseTests(TestCase):
|
|
"""Test edge cases for the home page."""
|
|
|
|
def setUp(self):
|
|
self.client = Client()
|
|
self.url = reverse('home')
|
|
|
|
# Create a user
|
|
self.user = User.objects.create_user(
|
|
username='testuser',
|
|
email='testuser@example.com',
|
|
password='testpass123'
|
|
)
|
|
|
|
# Create a friend code for the user
|
|
self.friend_code = FriendCode.objects.create(
|
|
user=self.user,
|
|
friend_code='SW-1234-5678-9012',
|
|
in_game_name='TestTrainer'
|
|
)
|
|
|
|
def test_home_page_with_no_cards(self):
|
|
"""Test home page with no cards in the database."""
|
|
response = self.client.get(self.url)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(len(response.context['cards']), 0)
|
|
|
|
def test_home_page_with_many_offers(self):
|
|
"""Test home page with many offers to verify pagination or limiting works."""
|
|
# Create a card
|
|
card = Card.objects.create(
|
|
name='Test Card',
|
|
cardset='TEST01',
|
|
cardnum=1,
|
|
style='normal',
|
|
rarity_icon='★',
|
|
rarity_level=1
|
|
)
|
|
|
|
# Create 20 trade offers
|
|
for i in range(20):
|
|
trade = TradeOffer.objects.create(
|
|
initiated_by=self.friend_code,
|
|
rarity_icon='★',
|
|
rarity_level=1
|
|
)
|
|
|
|
# Add have and want cards
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=trade,
|
|
card=card,
|
|
quantity=1
|
|
)
|
|
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=trade,
|
|
card=card,
|
|
quantity=1
|
|
)
|
|
|
|
response = self.client.get(self.url)
|
|
|
|
# Check that recent_offers is limited to 6 as per the view
|
|
self.assertEqual(len(response.context['recent_offers']), 6)
|
|
|
|
def test_home_page_with_invalid_parameters(self):
|
|
"""Test home page with invalid GET parameters."""
|
|
# The view should ignore invalid parameters
|
|
response = self.client.get(f"{self.url}?invalid=param&another=invalid")
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_performance_with_large_dataset(self):
|
|
"""Test performance with a larger dataset (basic check)."""
|
|
# Create a card
|
|
card = Card.objects.create(
|
|
name='Performance Test Card',
|
|
cardset='PERF01',
|
|
cardnum=1,
|
|
style='normal',
|
|
rarity_icon='★',
|
|
rarity_level=1
|
|
)
|
|
|
|
# Create 50 trade offers with different rarities
|
|
for i in range(50):
|
|
rarity_level = (i % 5) + 1 # 1-5
|
|
rarity_icon = '★' * rarity_level
|
|
|
|
trade = TradeOffer.objects.create(
|
|
initiated_by=self.friend_code,
|
|
rarity_icon=rarity_icon,
|
|
rarity_level=rarity_level
|
|
)
|
|
|
|
# Add have and want cards with the same rarity
|
|
rarity_card = Card.objects.create(
|
|
name=f'Performance Test Card {i}',
|
|
cardset='PERF01',
|
|
cardnum=i+10,
|
|
style='normal',
|
|
rarity_icon=rarity_icon,
|
|
rarity_level=rarity_level
|
|
)
|
|
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=trade,
|
|
card=rarity_card,
|
|
quantity=1
|
|
)
|
|
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=trade,
|
|
card=rarity_card,
|
|
quantity=1
|
|
)
|
|
|
|
# Basic performance test - just checking it completes without timeout
|
|
import time
|
|
start = time.time()
|
|
response = self.client.get(self.url)
|
|
end = time.time()
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Should be reasonably fast (adjust threshold as needed)
|
|
execution_time = end - start
|
|
self.assertLess(execution_time, 2.0) # Should complete in under 2 seconds
|
|
|
|
|
|
class TemplateRenderingTests(TestCase):
|
|
"""Tests focused on template rendering."""
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
# Create a user
|
|
cls.user = User.objects.create_user(
|
|
username='testuser',
|
|
email='testuser@example.com',
|
|
password='testpass123'
|
|
)
|
|
|
|
# Create a friend code for the user
|
|
cls.friend_code = FriendCode.objects.create(
|
|
user=cls.user,
|
|
friend_code='SW-1234-5678-9012',
|
|
in_game_name='TestTrainer'
|
|
)
|
|
|
|
# Create a card
|
|
cls.card = Card.objects.create(
|
|
name='Test Card',
|
|
cardset='TEST01',
|
|
cardnum=1,
|
|
style='normal',
|
|
rarity_icon='★',
|
|
rarity_level=1
|
|
)
|
|
|
|
# Create a trade offer
|
|
cls.trade = TradeOffer.objects.create(
|
|
initiated_by=cls.friend_code,
|
|
rarity_icon='★',
|
|
rarity_level=1
|
|
)
|
|
|
|
# Add have and want cards
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=cls.trade,
|
|
card=cls.card,
|
|
quantity=1
|
|
)
|
|
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=cls.trade,
|
|
card=cls.card,
|
|
quantity=1
|
|
)
|
|
|
|
def setUp(self):
|
|
self.client = Client()
|
|
self.factory = RequestFactory()
|
|
|
|
def test_template_used(self):
|
|
"""Test that the correct template is used."""
|
|
response = self.client.get(reverse('home'))
|
|
self.assertTemplateUsed(response, 'home/home.html')
|
|
|
|
def test_context_variables_exist(self):
|
|
"""Test that all expected context variables exist."""
|
|
response = self.client.get(reverse('home'))
|
|
|
|
# Check all required context variables
|
|
expected_keys = [
|
|
'cards',
|
|
'recent_offers',
|
|
'most_offered_cards',
|
|
'most_wanted_cards',
|
|
'least_offered_cards',
|
|
'featured_offers',
|
|
]
|
|
|
|
for key in expected_keys:
|
|
self.assertIn(key, response.context)
|
|
|
|
def test_view_with_pagination_params(self):
|
|
"""Test that view handles pagination parameters correctly, if applicable."""
|
|
# Create additional trade offers if pagination is implemented
|
|
for i in range(10):
|
|
trade = TradeOffer.objects.create(
|
|
initiated_by=self.friend_code,
|
|
rarity_icon='★',
|
|
rarity_level=1
|
|
)
|
|
|
|
# Add have and want cards
|
|
TradeOfferHaveCard.objects.create(
|
|
trade_offer=trade,
|
|
card=self.card,
|
|
quantity=1
|
|
)
|
|
|
|
TradeOfferWantCard.objects.create(
|
|
trade_offer=trade,
|
|
card=self.card,
|
|
quantity=1
|
|
)
|
|
|
|
# Test with page parameter
|
|
response = self.client.get(f"{reverse('home')}?page=1")
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
# Test with invalid page parameter
|
|
response = self.client.get(f"{reverse('home')}?page=999")
|
|
self.assertEqual(response.status_code, 200) # Should still render with default page
|
|
|
|
# Test with non-numeric page parameter
|
|
response = self.client.get(f"{reverse('home')}?page=abc")
|
|
self.assertEqual(response.status_code, 200) # Should handle gracefully
|
|
|
|
@patch('home.views.HomePageView.get_context_data')
|
|
def test_view_renders_with_missing_context(self, mock_get_context):
|
|
"""Test that view renders even with incomplete context data."""
|
|
# Return incomplete context
|
|
mock_get_context.return_value = {'cards': []}
|
|
|
|
# Should still render without error even with missing context variables
|
|
response = self.client.get(reverse('home'))
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_compatibility_with_multiple_django_versions(self):
|
|
"""Ensure compatibility with different Django versions."""
|
|
import django
|
|
# Simply log the Django version - the test itself verifies the page renders
|
|
# with the current version
|
|
django_version = django.get_version()
|
|
response = self.client.get(reverse('home'))
|
|
self.assertEqual(response.status_code, 200)
|