Files
Example-TCG-Site/store/tests/test_existing.py
Ryan Westfall 739d136209 Last bit of major changes
Closes #1
Closes #5
Closes #6
Closes #8
Closes #9
Closes #10
2026-01-26 04:11:38 -06:00

317 lines
13 KiB
Python

from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.files.uploadedfile import SimpleUploadedFile
from .models import Seller, Game, Set, Card, CardListing, Order
from decimal import Decimal
User = get_user_model()
class CardListingTests(TestCase):
def setUp(self):
# Create User and Seller
self.user = User.objects.create_user(username='seller', password='password')
self.seller = Seller.objects.create(
user=self.user,
store_name='Test Store',
slug='test-store'
)
# Create Game, Set, Card
self.game = Game.objects.create(name='Test Game', slug='test-game')
self.set = Set.objects.create(game=self.game, name='Test Set')
self.card = Card.objects.create(set=self.set, name='Test Card')
# Create Listing
self.listing = CardListing.objects.create(
card=self.card,
seller=self.seller,
price=10.00,
quantity=1,
condition='NM'
)
self.client = Client()
self.client.force_login(self.user)
def test_edit_card_listing_image_upload(self):
url = reverse('store:edit_card_listing', args=[self.listing.uuid])
# Create a small image file
image_content = b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x00\x00\x2c\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x01\x44\x00\x3b'
image = SimpleUploadedFile("test_image.gif", image_content, content_type="image/gif")
data = {
'condition': 'LP',
'price': '15.00',
'quantity': 2,
'status': 'listed',
'image': image
}
response = self.client.post(url, data, format='multipart')
# Check redirect
self.assertRedirects(response, reverse('store:manage_listings'))
# Reload listing
self.listing.refresh_from_db()
# Check updates
self.assertEqual(self.listing.condition, 'LP')
self.assertEqual(self.listing.price, 15.00)
self.assertEqual(self.listing.quantity, 2)
# Check image
self.assertTrue(self.listing.image)
self.assertTrue(self.listing.image.name.endswith('test_image.gif'))
class SellerDashboardTests(TestCase):
def setUp(self):
# Create User and Seller
self.user = User.objects.create_user(username='dashboard_seller', password='password')
self.seller = Seller.objects.create(
user=self.user,
store_name='Dashboard Store',
slug='dashboard-store'
)
self.buyer_user = User.objects.create_user(username='buyer', password='password')
from users.models import Buyer
self.buyer = Buyer.objects.create(user=self.buyer_user)
# Create Game, Set, Card
self.game = Game.objects.create(name='Dashboard Game', slug='dashboard-game')
self.set = Set.objects.create(game=self.game, name='Dashboard Set')
self.card = Card.objects.create(set=self.set, name='Dashboard Card')
# Create Listing
self.listing = CardListing.objects.create(
card=self.card,
seller=self.seller,
price=10.00,
quantity=10,
condition='NM'
)
# Create Order & OrderItem
from .models import Order, OrderItem
self.order = Order.objects.create(
buyer=self.buyer,
status='paid',
total_price=20.00
)
OrderItem.objects.create(
order=self.order,
listing=self.listing,
price_at_purchase=10.00,
quantity=2
)
self.client = Client()
self.client.force_login(self.user)
def test_dashboard_context_data(self):
url = reverse('store:seller_dashboard')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
# Check for new context keys
self.assertIn('condition_labels', response.context)
self.assertIn('condition_data', response.context)
self.assertIn('set_labels', response.context)
self.assertIn('set_data', response.context)
self.assertIn('game_labels', response.context)
self.assertIn('game_data', response.context)
self.assertIn('all_games', response.context)
# Check data correctness (we sold 2 NM items)
import json
cond_data = json.loads(response.context['condition_data'])
cond_labels = json.loads(response.context['condition_labels'])
self.assertIn('Near Mint', cond_labels)
idx = cond_labels.index('Near Mint')
self.assertEqual(cond_data[idx], 2)
def test_dashboard_game_filter(self):
from .models import OrderItem
url = reverse('store:seller_dashboard')
# Create another game/sale
game2 = Game.objects.create(name='Other Game', slug='other-game')
set2 = Set.objects.create(game=game2, name='Other Set')
card2 = Card.objects.create(set=set2, name='Other Card')
listing2 = CardListing.objects.create(card=card2, seller=self.seller, price=5, quantity=5, condition='LP')
OrderItem.objects.create(
order=self.order,
listing=listing2,
price_at_purchase=5.00,
quantity=1
)
# 1. No Filter - Should see both
response = self.client.get(url)
import json
game_labels = json.loads(response.context['game_labels'])
self.assertIn('Dashboard Game', game_labels)
self.assertIn('Other Game', game_labels)
# 2. Filter by Dashboard Game
response = self.client.get(url, {'game': 'Dashboard Game'})
game_labels = json.loads(response.context['game_labels'])
self.assertIn('Dashboard Game', game_labels)
self.assertNotIn('Other Game', game_labels)
# Check condition data also filtered
cond_labels = json.loads(response.context['condition_labels'])
# Dashboard Game items were NM. Other Game items were LP.
self.assertIn('Near Mint', cond_labels)
self.assertNotIn('Lightly Played', cond_labels)
class AdminRevenueTests(TestCase):
def setUp(self):
self.client = Client()
self.staff_user = User.objects.create_user(username='staff', password='password', is_staff=True)
self.seller_user = User.objects.create_user(username='seller2', password='password')
self.seller = Seller.objects.create(
user=self.seller_user,
store_name='Revenue Store',
slug='revenue-store',
tax_id='123-45-6789',
payout_details='Bank Acct 123'
)
# Create Orders
from users.models import Buyer
buyer_user = User.objects.create_user(username='buyer2', password='password')
buyer = Buyer.objects.create(user=buyer_user)
# Order 1: $100 -> Fee: 5 + 0.70 = 5.70
order1 = Order.objects.create(buyer=buyer, status='paid', total_price=Decimal('100.00'), seller=self.seller)
# Order 2: $1000 -> Fee: 50 + 0.70 = 50.70 -> Capped at 25.00
order2 = Order.objects.create(buyer=buyer, status='shipped', total_price=Decimal('1000.00'), seller=self.seller)
# Order 3: Pending (should be ignored)
order3 = Order.objects.create(buyer=buyer, status='pending', total_price=Decimal('50.00'), seller=self.seller)
def test_encryption(self):
# Refresh from db
seller = Seller.objects.get(pk=self.seller.pk)
# Verify decrypted values match
self.assertEqual(seller.tax_id, '123-45-6789')
self.assertEqual(seller.payout_details, 'Bank Acct 123')
# Verify db values are encrypted (not plaintext and are bytes)
self.assertIsInstance(seller.tax_id_encrypted, bytes)
self.assertNotEqual(seller.tax_id_encrypted, b'123-45-6789')
# Ensure it's not just the string encoded
self.assertNotEqual(seller.tax_id_encrypted, '123-45-6789'.encode('utf-8'))
def test_fee_calculation(self):
from .utils import calculate_platform_fee
# 5% + 0.70
self.assertEqual(calculate_platform_fee(Decimal('10.00')), Decimal('1.20')) # 0.50 + 0.70
self.assertEqual(calculate_platform_fee(Decimal('100.00')), Decimal('5.70')) # 5.00 + 0.70
# Cap at 25
# Threshold: (25 - 0.70) / 0.05 = 486.00
self.assertEqual(calculate_platform_fee(Decimal('486.00')), Decimal('25.00'))
self.assertEqual(calculate_platform_fee(Decimal('1000.00')), Decimal('25.00'))
def test_dashboard_view(self):
self.client.force_login(self.staff_user)
response = self.client.get(reverse('store:admin_revenue_dashboard'))
self.assertEqual(response.status_code, 200)
# Check context
total_rev = response.context['total_platform_revenue']
# Order 1 (5.70) + Order 2 (25.00) = 30.70
self.assertEqual(total_rev, Decimal('30.70'))
seller_data = response.context['seller_data']
self.assertEqual(len(seller_data), 1)
self.assertEqual(seller_data[0]['total_revenue'], Decimal('1100.00'))
self.assertEqual(seller_data[0]['platform_fees'], Decimal('30.70'))
class CardListStockTests(TestCase):
def setUp(self):
# Create Data
self.user = User.objects.create_user(username='stock_seller', password='password')
self.seller = Seller.objects.create(
user=self.user,
store_name='Stock Store',
slug='stock-store'
)
self.game = Game.objects.create(name='Stock Game', slug='stock-game')
self.set = Set.objects.create(game=self.game, name='Stock Set')
self.card = Card.objects.create(set=self.set, name='Stock Card')
def test_stock_aggregation(self):
# 1. No listings
url = reverse('store:card_list')
response = self.client.get(url, {'hide_out_of_stock': 'off'})
# Expect card in context
self.assertEqual(len(response.context['page_obj']), 1)
self.assertEqual(response.context['page_obj'][0].total_quantity, 0)
# 2. Add listings
CardListing.objects.create(card=self.card, seller=self.seller, price=10, quantity=5, status='listed')
CardListing.objects.create(card=self.card, seller=self.seller, price=10, quantity=3, status='listed')
# Add a sold listing (should be ignored)
CardListing.objects.create(card=self.card, seller=self.seller, price=10, quantity=2, status='sold')
response = self.client.get(url, {'hide_out_of_stock': 'off'})
# Should be 5 + 3 = 8
self.assertEqual(response.context['page_obj'][0].total_quantity, 8)
class SellerProfileRestrictionTests(TestCase):
def setUp(self):
self.user = User.objects.create_user(username='restricted_seller', password='password')
self.seller = Seller.objects.create(
user=self.user,
store_name='Restricted Store',
slug='restricted-store'
# tax_id and payout_details are initially empty
)
self.client = Client()
self.client.force_login(self.user)
def test_add_listing_incomplete_profile(self):
url = reverse('store:add_card_listing')
response = self.client.get(url)
# Should redirect to edit profile
self.assertRedirects(response, reverse('store:edit_seller_profile'))
# Verify message (this requires session support in test client which is default)
messages = list(response.wsgi_request._messages)
self.assertEqual(len(messages), 1)
self.assertIn("must complete your seller profile", str(messages[0]))
def test_add_bounty_incomplete_profile(self):
# Ensure feature flag is on if needed, or assume True based on settings
# The view checks FEATURE_BOUNTY_BOARD, so we might need override_settings if it defaults to False
# But settings.DEBUG is True in current env, so it should be on.
url = reverse('store:bounty_create')
response = self.client.get(url)
self.assertRedirects(response, reverse('store:edit_seller_profile'))
def test_complete_profile_allows_access(self):
# Update profile
self.seller.tax_id = '123'
self.seller.payout_details = 'Bank'
self.seller.save()
url = reverse('store:add_card_listing')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
url = reverse('store:bounty_create')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)