Add initial home tests

This commit is contained in:
badblocks 2025-03-27 00:16:56 -07:00
parent 2785e0ed13
commit 0d4655bf80
2 changed files with 682 additions and 54 deletions

View file

@ -1,3 +1,590 @@
from django.test import TestCase
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
# Create your tests here.
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)