dnscms: add more tests
This commit is contained in:
+319
-18
@@ -1,16 +1,21 @@
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
|
||||
from events.models import (
|
||||
EventCategory,
|
||||
EventOccurrence,
|
||||
EventOrganizer,
|
||||
EventOrganizerLink,
|
||||
EventPage,
|
||||
)
|
||||
from tests.conftest import EventPageFactory
|
||||
from tests.conftest import (
|
||||
AssociationPageFactory,
|
||||
CustomImageFactory,
|
||||
EventPageFactory,
|
||||
)
|
||||
|
||||
|
||||
def test_eventpage_clean_unsets_specific_pricing_when_free():
|
||||
@@ -30,6 +35,58 @@ def test_eventpage_clean_unsets_specific_pricing_when_free():
|
||||
assert page.price_member == ""
|
||||
|
||||
|
||||
def test_eventpage_clean_keeps_specific_pricing_when_not_free():
|
||||
page = EventPage(
|
||||
title="Paid event",
|
||||
slug="paid-event",
|
||||
free=False,
|
||||
price_regular="100",
|
||||
price_student="50",
|
||||
price_member="25",
|
||||
)
|
||||
|
||||
page.clean()
|
||||
|
||||
assert page.price_regular == "100"
|
||||
assert page.price_student == "50"
|
||||
assert page.price_member == "25"
|
||||
|
||||
|
||||
def test_eventpage_clean_dedupes_organizers_by_name(event_index):
|
||||
org_a = EventOrganizer.objects.create(name="DNS", slug="dns-a")
|
||||
org_b = EventOrganizer.objects.create(name="DNS", slug="dns-b")
|
||||
|
||||
event = EventPageFactory(parent=event_index)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=org_a)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=org_b)
|
||||
|
||||
event = EventPage.objects.get(pk=event.pk)
|
||||
assert event.organizer_links.count() == 2
|
||||
|
||||
event.clean()
|
||||
|
||||
assert event.organizer_links.count() == 1
|
||||
|
||||
|
||||
def test_eventpage_clean_dedupes_three_duplicates_and_keeps_distinct(event_index):
|
||||
dup_1 = EventOrganizer.objects.create(name="DNS", slug="dns-1")
|
||||
dup_2 = EventOrganizer.objects.create(name="DNS", slug="dns-2")
|
||||
dup_3 = EventOrganizer.objects.create(name="DNS", slug="dns-3")
|
||||
distinct = EventOrganizer.objects.create(name="Studentersamfundet", slug="ss")
|
||||
|
||||
event = EventPageFactory(parent=event_index)
|
||||
for organizer in (dup_1, dup_2, dup_3, distinct):
|
||||
EventOrganizerLink.objects.create(event=event, organizer=organizer)
|
||||
|
||||
event = EventPage.objects.get(pk=event.pk)
|
||||
assert event.organizer_links.count() == 4
|
||||
|
||||
event.clean()
|
||||
|
||||
names = sorted(link.organizer.name for link in event.organizer_links.all())
|
||||
assert names == ["DNS", "Studentersamfundet"]
|
||||
|
||||
|
||||
def test_eventoccurrence_clean_rejects_both_venue_and_venue_custom(event_index, venue):
|
||||
event = EventPageFactory(parent=event_index)
|
||||
occurrence = EventOccurrence(
|
||||
@@ -57,14 +114,10 @@ def test_eventpage_manager_future_filters_past_and_annotates(event_index):
|
||||
now = timezone.now()
|
||||
|
||||
past = EventPageFactory(parent=event_index, title="Past")
|
||||
EventOccurrence.objects.create(
|
||||
event=past, start=now - timedelta(days=7), venue_custom="Old"
|
||||
)
|
||||
EventOccurrence.objects.create(event=past, start=now - timedelta(days=7), venue_custom="Old")
|
||||
|
||||
future = EventPageFactory(parent=event_index, title="Future")
|
||||
EventOccurrence.objects.create(
|
||||
event=future, start=now + timedelta(days=7), venue_custom="New"
|
||||
)
|
||||
EventOccurrence.objects.create(event=future, start=now + timedelta(days=7), venue_custom="New")
|
||||
|
||||
results = list(EventPage.objects.live().future().order_by("next_occurrence"))
|
||||
|
||||
@@ -72,17 +125,265 @@ def test_eventpage_manager_future_filters_past_and_annotates(event_index):
|
||||
assert results[0].next_occurrence is not None
|
||||
|
||||
|
||||
def test_eventpage_clean_dedupes_organizers_by_name(event_index):
|
||||
org_a = EventOrganizer.objects.create(name="DNS", slug="dns-a")
|
||||
org_b = EventOrganizer.objects.create(name="DNS", slug="dns-b")
|
||||
def test_future_includes_occurrence_late_today(event_index):
|
||||
today_start = timezone.localtime(timezone.now()).replace(
|
||||
hour=0, minute=0, second=0, microsecond=0
|
||||
)
|
||||
late_today = today_start + timedelta(hours=23, minutes=59)
|
||||
|
||||
event = EventPageFactory(parent=event_index)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=org_a)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=org_b)
|
||||
event = EventPageFactory(parent=event_index, title="Late today")
|
||||
EventOccurrence.objects.create(event=event, start=late_today, venue_custom="X")
|
||||
|
||||
event = EventPage.objects.get(pk=event.pk)
|
||||
assert event.organizer_links.count() == 2
|
||||
assert event.pk in EventPage.objects.future().values_list("pk", flat=True)
|
||||
|
||||
event.clean()
|
||||
|
||||
assert event.organizer_links.count() == 1
|
||||
def test_future_excludes_occurrence_just_before_today(event_index):
|
||||
today_start = timezone.localtime(timezone.now()).replace(
|
||||
hour=0, minute=0, second=0, microsecond=0
|
||||
)
|
||||
just_before_today = today_start - timedelta(seconds=1)
|
||||
|
||||
event = EventPageFactory(parent=event_index, title="Just past")
|
||||
EventOccurrence.objects.create(event=event, start=just_before_today, venue_custom="X")
|
||||
|
||||
assert event.pk not in EventPage.objects.future().values_list("pk", flat=True)
|
||||
|
||||
|
||||
def test_future_next_occurrence_picks_earliest_future_ignoring_past(event_index):
|
||||
now = timezone.now()
|
||||
soonest_future = now + timedelta(days=3)
|
||||
|
||||
event = EventPageFactory(parent=event_index, title="With history")
|
||||
EventOccurrence.objects.create(event=event, start=now - timedelta(days=30), venue_custom="X")
|
||||
EventOccurrence.objects.create(event=event, start=soonest_future, venue_custom="X")
|
||||
EventOccurrence.objects.create(event=event, start=now + timedelta(days=10), venue_custom="X")
|
||||
|
||||
annotated = EventPage.objects.future().filter(pk=event.pk).first()
|
||||
assert annotated is not None
|
||||
assert abs((annotated.next_occurrence - soonest_future).total_seconds()) < 1
|
||||
|
||||
|
||||
def test_graphql_event_index_future_events_query(event_index, graphql_post):
|
||||
upcoming = EventPageFactory(parent=event_index, title="Upcoming gig")
|
||||
EventOccurrence.objects.create(
|
||||
event=upcoming,
|
||||
start=timezone.now() + timedelta(days=3),
|
||||
venue_custom="Storsalen",
|
||||
)
|
||||
|
||||
response, body = graphql_post(
|
||||
"""
|
||||
query {
|
||||
eventIndex {
|
||||
futureEvents { title }
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "errors" not in body, body
|
||||
titles = [e["title"] for e in body["data"]["eventIndex"]["futureEvents"]]
|
||||
assert "Upcoming gig" in titles
|
||||
|
||||
|
||||
def test_graphql_event_index_future_events_ordered_by_next_occurrence(event_index, graphql_post):
|
||||
now = timezone.now()
|
||||
|
||||
later = EventPageFactory(parent=event_index, title="Later gig")
|
||||
EventOccurrence.objects.create(event=later, start=now + timedelta(days=10), venue_custom="X")
|
||||
|
||||
sooner = EventPageFactory(parent=event_index, title="Sooner gig")
|
||||
EventOccurrence.objects.create(event=sooner, start=now + timedelta(days=3), venue_custom="X")
|
||||
|
||||
response, body = graphql_post(
|
||||
"""
|
||||
query {
|
||||
eventIndex {
|
||||
futureEvents { title }
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "errors" not in body, body
|
||||
titles = [e["title"] for e in body["data"]["eventIndex"]["futureEvents"]]
|
||||
assert titles.index("Sooner gig") < titles.index("Later gig")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def comprehensive_event(event_index, venue, association_index):
|
||||
"""A fully-populated paid EventPage exercising every field exposed via GraphQL."""
|
||||
image = CustomImageFactory(
|
||||
title="Cover",
|
||||
alt="Et fotografi av en gris med solbriller",
|
||||
attribution="Foto: Test",
|
||||
)
|
||||
|
||||
konsert = EventCategory.objects.create(
|
||||
name="Konsert", slug="konsert", show_in_filters=True, pig="pigHeadLogo"
|
||||
)
|
||||
klubb = EventCategory.objects.create(name="Klubb", slug="klubb")
|
||||
|
||||
association = AssociationPageFactory(
|
||||
parent=association_index,
|
||||
title="Internal",
|
||||
association_type="forening",
|
||||
)
|
||||
internal_org = EventOrganizer.objects.create(
|
||||
name="Internal", slug="internal", association=association
|
||||
)
|
||||
external_org = EventOrganizer.objects.create(
|
||||
name="External",
|
||||
slug="external",
|
||||
external_url="https://external.example.com",
|
||||
)
|
||||
|
||||
event = EventPageFactory(
|
||||
parent=event_index,
|
||||
title="Et arrangement",
|
||||
slug="et-arrangement",
|
||||
subtitle="En undertekst",
|
||||
lead="<p>Ingress.</p>",
|
||||
body=[("paragraph", "<p>Body content.</p>")],
|
||||
pig="automatic",
|
||||
free=False,
|
||||
price_regular="150",
|
||||
price_student="100",
|
||||
price_member="75",
|
||||
ticket_url="https://example.com/tickets",
|
||||
facebook_url="https://facebook.com/example",
|
||||
featured_image=image,
|
||||
)
|
||||
event.categories.add(konsert, klubb)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=internal_org)
|
||||
EventOrganizerLink.objects.create(event=event, organizer=external_org)
|
||||
|
||||
now = timezone.now()
|
||||
EventOccurrence.objects.create(
|
||||
event=event,
|
||||
start=now + timedelta(days=5),
|
||||
end=now + timedelta(days=5, hours=3),
|
||||
venue=venue,
|
||||
)
|
||||
EventOccurrence.objects.create(
|
||||
event=event,
|
||||
start=now + timedelta(days=12),
|
||||
end=now + timedelta(days=12, hours=2),
|
||||
venue_custom="Frederikkeplassen",
|
||||
)
|
||||
|
||||
event.save()
|
||||
return event
|
||||
|
||||
|
||||
def test_graphql_event_index_returns_all_fields_for_comprehensive_event(
|
||||
comprehensive_event, graphql_post
|
||||
):
|
||||
response, body = graphql_post(
|
||||
"""
|
||||
query {
|
||||
eventIndex {
|
||||
futureEvents {
|
||||
title
|
||||
slug
|
||||
subtitle
|
||||
lead
|
||||
body {
|
||||
blockType
|
||||
field
|
||||
... on RichTextBlock {
|
||||
value
|
||||
}
|
||||
}
|
||||
pig
|
||||
free
|
||||
priceRegular
|
||||
priceStudent
|
||||
priceMember
|
||||
ticketUrl
|
||||
facebookUrl
|
||||
featuredImage {
|
||||
alt
|
||||
attribution
|
||||
}
|
||||
categories {
|
||||
name
|
||||
slug
|
||||
showInFilters
|
||||
pig
|
||||
}
|
||||
organizers {
|
||||
name
|
||||
slug
|
||||
externalUrl
|
||||
association {
|
||||
title
|
||||
}
|
||||
}
|
||||
occurrences {
|
||||
start
|
||||
end
|
||||
venueCustom
|
||||
venue {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert "errors" not in body, body
|
||||
|
||||
events = body["data"]["eventIndex"]["futureEvents"]
|
||||
event = next(e for e in events if e["title"] == "Et arrangement")
|
||||
|
||||
assert event["slug"] == "et-arrangement"
|
||||
assert event["subtitle"] == "En undertekst"
|
||||
assert "Ingress." in event["lead"]
|
||||
assert event["pig"] == "automatic"
|
||||
assert event["free"] is False
|
||||
assert event["priceRegular"] == "150"
|
||||
assert event["priceStudent"] == "100"
|
||||
assert event["priceMember"] == "75"
|
||||
assert event["ticketUrl"] == "https://example.com/tickets"
|
||||
assert event["facebookUrl"] == "https://facebook.com/example"
|
||||
|
||||
assert event["featuredImage"]["alt"] == "Et fotografi av en gris med solbriller"
|
||||
assert event["featuredImage"]["attribution"] == "Foto: Test"
|
||||
|
||||
assert event["body"][0]["blockType"] == "RichTextBlock"
|
||||
assert "Body content." in event["body"][0]["value"]
|
||||
|
||||
categories_by_name = {c["name"]: c for c in event["categories"]}
|
||||
assert set(categories_by_name) == {"Konsert", "Klubb"}
|
||||
assert categories_by_name["Konsert"]["slug"] == "konsert"
|
||||
assert categories_by_name["Konsert"]["showInFilters"] is True
|
||||
assert categories_by_name["Konsert"]["pig"] == "pigHeadLogo"
|
||||
assert categories_by_name["Klubb"]["showInFilters"] is False
|
||||
|
||||
organizers_by_name = {o["name"]: o for o in event["organizers"]}
|
||||
assert set(organizers_by_name) == {"Internal", "External"}
|
||||
assert organizers_by_name["Internal"]["association"]["title"] == "Internal"
|
||||
assert organizers_by_name["Internal"]["externalUrl"] == ""
|
||||
assert organizers_by_name["External"]["association"] is None
|
||||
assert organizers_by_name["External"]["externalUrl"] == "https://external.example.com"
|
||||
|
||||
assert len(event["occurrences"]) == 2
|
||||
venue_occ = next(o for o in event["occurrences"] if o["venue"] is not None)
|
||||
custom_occ = next(o for o in event["occurrences"] if o["venueCustom"])
|
||||
assert venue_occ["venueCustom"] == ""
|
||||
assert venue_occ["venue"]["title"]
|
||||
assert custom_occ["venue"] is None
|
||||
assert custom_occ["venueCustom"] == "Frederikkeplassen"
|
||||
|
||||
venue_occ_db = comprehensive_event.occurrences.exclude(venue=None).get()
|
||||
custom_occ_db = comprehensive_event.occurrences.exclude(venue_custom="").get()
|
||||
assert datetime.fromisoformat(venue_occ["start"]) == venue_occ_db.start
|
||||
assert datetime.fromisoformat(venue_occ["end"]) == venue_occ_db.end
|
||||
assert datetime.fromisoformat(custom_occ["start"]) == custom_occ_db.start
|
||||
assert datetime.fromisoformat(custom_occ["end"]) == custom_occ_db.end
|
||||
|
||||
Reference in New Issue
Block a user