Add tests for GameDetailView to validate expired campaign filtering
This commit is contained in:
parent
3fb0880271
commit
fa7c8caa10
3 changed files with 99 additions and 10 deletions
0
twitch/tests/__init__.py
Normal file
0
twitch/tests/__init__.py
Normal file
83
twitch/tests/test_views.py
Normal file
83
twitch/tests/test_views.py
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from twitch.models import DropCampaign, Game, Organization
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from django.test import Client
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
class TestGameDetailView:
|
||||||
|
"""Test cases for GameDetailView."""
|
||||||
|
|
||||||
|
def test_expired_campaigns_filtering(self, client: Client) -> None:
|
||||||
|
"""Test that expired campaigns are correctly filtered."""
|
||||||
|
# Create test data
|
||||||
|
game = Game.objects.create(
|
||||||
|
id="123",
|
||||||
|
slug="test-game",
|
||||||
|
display_name="Test Game",
|
||||||
|
)
|
||||||
|
|
||||||
|
organization = Organization.objects.create(
|
||||||
|
id="456",
|
||||||
|
name="Test Organization",
|
||||||
|
)
|
||||||
|
|
||||||
|
now = timezone.now()
|
||||||
|
|
||||||
|
# Create an active campaign
|
||||||
|
active_campaign = DropCampaign.objects.create(
|
||||||
|
id="active-campaign",
|
||||||
|
name="Active Campaign",
|
||||||
|
game=game,
|
||||||
|
owner=organization,
|
||||||
|
start_at=now - timezone.timedelta(days=1),
|
||||||
|
end_at=now + timezone.timedelta(days=1),
|
||||||
|
status="ACTIVE",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create an expired campaign (end date in the past)
|
||||||
|
expired_by_date = DropCampaign.objects.create(
|
||||||
|
id="expired-by-date",
|
||||||
|
name="Expired By Date",
|
||||||
|
game=game,
|
||||||
|
owner=organization,
|
||||||
|
start_at=now - timezone.timedelta(days=3),
|
||||||
|
end_at=now - timezone.timedelta(days=1),
|
||||||
|
status="ACTIVE", # Still marked as active but date is expired
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create an expired campaign (status is EXPIRED)
|
||||||
|
expired_by_status = DropCampaign.objects.create(
|
||||||
|
id="expired-by-status",
|
||||||
|
name="Expired By Status",
|
||||||
|
game=game,
|
||||||
|
owner=organization,
|
||||||
|
start_at=now - timezone.timedelta(days=3),
|
||||||
|
end_at=now + timezone.timedelta(days=1),
|
||||||
|
status="EXPIRED", # Explicitly expired
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get the view context
|
||||||
|
url = reverse("twitch:game_detail", kwargs={"pk": game.id})
|
||||||
|
response = client.get(url)
|
||||||
|
|
||||||
|
# Check that active_campaigns only contains the active campaign
|
||||||
|
active_campaigns = response.context["active_campaigns"]
|
||||||
|
assert len(active_campaigns) == 1
|
||||||
|
assert active_campaigns[0].id == active_campaign.id
|
||||||
|
|
||||||
|
# Check that expired_campaigns contains only the expired campaigns
|
||||||
|
expired_campaigns = response.context["expired_campaigns"]
|
||||||
|
assert len(expired_campaigns) == 2
|
||||||
|
expired_campaign_ids = [c.id for c in expired_campaigns]
|
||||||
|
assert expired_by_date.id in expired_campaign_ids
|
||||||
|
assert expired_by_status.id in expired_campaign_ids
|
||||||
|
assert active_campaign.id not in expired_campaign_ids
|
||||||
|
|
@ -41,7 +41,7 @@ class DropCampaignListView(ListView):
|
||||||
# Prefetch related objects to reduce queries
|
# Prefetch related objects to reduce queries
|
||||||
return queryset.select_related("game", "owner").order_by("-start_at")
|
return queryset.select_related("game", "owner").order_by("-start_at")
|
||||||
|
|
||||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
def get_context_data(self, **kwargs: object) -> dict[str, Any]:
|
||||||
"""Add additional context data.
|
"""Add additional context data.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -75,7 +75,7 @@ class DropCampaignDetailView(DetailView):
|
||||||
template_name = "twitch/campaign_detail.html"
|
template_name = "twitch/campaign_detail.html"
|
||||||
context_object_name = "campaign"
|
context_object_name = "campaign"
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset: QuerySet[DropCampaign] | None = None) -> DropCampaign:
|
||||||
"""Get the campaign object with related data prefetched.
|
"""Get the campaign object with related data prefetched.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -93,9 +93,9 @@ class DropCampaignDetailView(DetailView):
|
||||||
# We don't need to prefetch time_based_drops here since we're fetching them separately in get_context_data
|
# We don't need to prefetch time_based_drops here since we're fetching them separately in get_context_data
|
||||||
# with proper ordering and prefetching of benefits
|
# with proper ordering and prefetching of benefits
|
||||||
|
|
||||||
return super().get_object(queryset=queryset)
|
return super().get_object(queryset=queryset) # type: ignore[return-value]
|
||||||
|
|
||||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
def get_context_data(self, **kwargs: object) -> dict[str, Any]:
|
||||||
"""Add additional context data.
|
"""Add additional context data.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -129,7 +129,11 @@ class GameListView(ListView):
|
||||||
context_object_name = "games"
|
context_object_name = "games"
|
||||||
|
|
||||||
def get_queryset(self) -> QuerySet[Game]:
|
def get_queryset(self) -> QuerySet[Game]:
|
||||||
"""Get queryset of games, annotated with campaign counts to avoid N+1 queries."""
|
"""Get queryset of games, annotated with campaign counts to avoid N+1 queries.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
QuerySet[Game]: Queryset of games with annotations.
|
||||||
|
"""
|
||||||
now = timezone.now()
|
now = timezone.now()
|
||||||
return (
|
return (
|
||||||
super()
|
super()
|
||||||
|
|
@ -149,7 +153,7 @@ class GameListView(ListView):
|
||||||
.order_by("display_name")
|
.order_by("display_name")
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
def get_context_data(self, **kwargs: object) -> dict[str, Any]:
|
||||||
"""Add additional context data with games grouped by organization.
|
"""Add additional context data with games grouped by organization.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
@ -225,14 +229,15 @@ class GameDetailView(DetailView):
|
||||||
template_name = "twitch/game_detail.html"
|
template_name = "twitch/game_detail.html"
|
||||||
context_object_name = "game"
|
context_object_name = "game"
|
||||||
|
|
||||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
def get_context_data(self, **kwargs: object) -> dict[str, Any]:
|
||||||
"""Add additional context data.
|
"""Add additional context data.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
**kwargs: Additional arguments.
|
**kwargs: Additional arguments.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Context data.
|
dict: Context data with active, upcoming, and expired campaigns.
|
||||||
|
Expired campaigns are filtered based on either end date or status.
|
||||||
"""
|
"""
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
game = self.get_object()
|
game = self.get_object()
|
||||||
|
|
@ -250,12 +255,13 @@ class GameDetailView(DetailView):
|
||||||
upcoming_campaigns = [campaign for campaign in all_campaigns if campaign.start_at > now and campaign.status == "UPCOMING"]
|
upcoming_campaigns = [campaign for campaign in all_campaigns if campaign.start_at > now and campaign.status == "UPCOMING"]
|
||||||
upcoming_campaigns.sort(key=lambda c: c.start_at) # Sort by start_at ascending
|
upcoming_campaigns.sort(key=lambda c: c.start_at) # Sort by start_at ascending
|
||||||
|
|
||||||
# No need to fetch expired_campaigns separately as we already have all_campaigns
|
# Filter for expired campaigns
|
||||||
|
expired_campaigns = [campaign for campaign in all_campaigns if campaign.end_at < now or campaign.status == "EXPIRED"]
|
||||||
|
|
||||||
context.update({
|
context.update({
|
||||||
"active_campaigns": active_campaigns,
|
"active_campaigns": active_campaigns,
|
||||||
"upcoming_campaigns": upcoming_campaigns,
|
"upcoming_campaigns": upcoming_campaigns,
|
||||||
"expired_campaigns": all_campaigns, # We already have all campaigns sorted by -end_at
|
"expired_campaigns": expired_campaigns, # Only include expired campaigns
|
||||||
"now": now,
|
"now": now,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue