Unit Tests / test (push) Successful in 5s
## Summary Closes #30. - Green check (“Paid this year”) on membership list, person list, and person inline when `Payments.email` matches `MembershipPerson.email` (case-insensitive) for the current calendar year. Also matches via the payment’s person FK. - CSV downloads for payments, memberships by person, and memberships by address prompt for a year (default current year, or All years). Payments filter by payment date; memberships filter by record created year. Changelists also get a year sidebar filter. - Payments admin remains searchable by email. ## Test plan - [ ] `uv run python manage.py test` - [ ] In admin, open Memberships / Membership people and confirm a green check when a same-year payment email matches, and a red X otherwise - [ ] Select memberships → Download CSV by member/address → pick a year → confirm only that year is in the file - [ ] Select payments → Download payments CSV → pick a year → confirm filter - [ ] On Payments, search by email and filter by year Reviewed-on: #31
657 lines
23 KiB
Python
657 lines
23 KiB
Python
import datetime
|
|
from unittest.mock import patch
|
|
|
|
from django.test import Client, TestCase, override_settings
|
|
from django.urls import reverse
|
|
|
|
from scha.settings.base import build_csrf_trusted_origins
|
|
|
|
from django.contrib.auth.models import User
|
|
from django.utils import timezone
|
|
|
|
from .admin import membership_payment_exists, person_payment_exists
|
|
from .forms import AddressForm, PeopleForm
|
|
from .models import (
|
|
AddressModel1,
|
|
CalendarEvent,
|
|
Membership,
|
|
MembershipPerson,
|
|
Payments,
|
|
SCHAOfficer,
|
|
UsefulLinks,
|
|
)
|
|
|
|
|
|
class CsrfTrustedOriginsTests(TestCase):
|
|
def test_derives_https_origins_from_public_hosts(self):
|
|
origins = build_csrf_trusted_origins(
|
|
["schawheaton.com", "www.schawheaton.com"]
|
|
)
|
|
|
|
self.assertEqual(
|
|
origins,
|
|
[
|
|
"https://schawheaton.com",
|
|
"https://www.schawheaton.com",
|
|
],
|
|
)
|
|
|
|
def test_derives_http_origins_for_local_hosts(self):
|
|
origins = build_csrf_trusted_origins(["localhost", "127.0.0.1"])
|
|
|
|
self.assertEqual(origins, ["http://localhost", "http://127.0.0.1"])
|
|
|
|
def test_explicit_origins_win(self):
|
|
origins = build_csrf_trusted_origins(
|
|
["schawheaton.com"],
|
|
["https://custom.example"],
|
|
)
|
|
|
|
self.assertEqual(origins, ["https://custom.example"])
|
|
|
|
|
|
class PublicPageTests(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
|
|
def test_index_renders(self):
|
|
response = self.client.get(reverse("index2"))
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_about_us_renders(self):
|
|
response = self.client.get(reverse("about_us2"))
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_calendar_renders(self):
|
|
response = self.client.get(reverse("calendar2"))
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_newsletters_renders(self):
|
|
response = self.client.get(reverse("newsletters2"))
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_dues_renders(self):
|
|
response = self.client.get(reverse("dues2"))
|
|
self.assertEqual(response.status_code, 200)
|
|
|
|
def test_scha_board_renders_officers(self):
|
|
SCHAOfficer.objects.create(
|
|
name="Jane President",
|
|
position="President",
|
|
email="jane@example.com",
|
|
)
|
|
|
|
response = self.client.get(reverse("scha_board2"))
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, "Jane President")
|
|
|
|
def test_useful_links_renders_links(self):
|
|
UsefulLinks.objects.create(name="City of Wheaton", url="https://example.com")
|
|
|
|
response = self.client.get(reverse("useful_links2"))
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, "City of Wheaton")
|
|
|
|
def test_public_pages_include_seo_metadata(self):
|
|
pages = [
|
|
("index2", "Home | Stonehedge"),
|
|
("about_us2", "About Us | Stonehedge"),
|
|
("calendar2", "Calendar | Stonehedge"),
|
|
("dues2", "Pay Dues | Stonehedge"),
|
|
("membership_form2", "Join Today | Stonehedge"),
|
|
("scha_board2", "SCHA Board | Stonehedge"),
|
|
("useful_links2", "Useful Links | Stonehedge"),
|
|
]
|
|
|
|
for name, title_fragment in pages:
|
|
with self.subTest(page=name):
|
|
response = self.client.get(reverse(name))
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, f"<title>{title_fragment}")
|
|
self.assertContains(response, 'name="description"')
|
|
self.assertContains(response, 'property="og:title"')
|
|
self.assertContains(response, 'rel="canonical"')
|
|
self.assertContains(response, 'id="main-content"')
|
|
self.assertContains(response, "Skip to main content")
|
|
|
|
def test_robots_txt(self):
|
|
response = self.client.get(reverse("robots_txt"))
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response["Content-Type"].split(";")[0], "text/plain")
|
|
self.assertContains(response, "Sitemap:")
|
|
self.assertContains(response, "Disallow: /admin/")
|
|
|
|
def test_sitemap_xml(self):
|
|
response = self.client.get(reverse("sitemap_xml"))
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertIn("xml", response["Content-Type"])
|
|
self.assertContains(response, reverse("index2"))
|
|
self.assertContains(response, reverse("dues2"))
|
|
|
|
def test_llms_txt(self):
|
|
response = self.client.get(reverse("llms_txt"))
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response["Content-Type"].split(";")[0], "text/plain")
|
|
self.assertContains(response, "Stonehedge Community Homeowners Association")
|
|
self.assertContains(response, reverse("membership_form2").lstrip("/"))
|
|
|
|
|
|
@override_settings(
|
|
RECAPTCHA_PUBLIC_KEY="test-public-key",
|
|
RECAPTCHA_PRIVATE_KEY="test-private-key",
|
|
)
|
|
class MembershipFormViewTests(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
self.url = reverse("membership_form2")
|
|
|
|
def test_get_renders_form(self):
|
|
response = self.client.get(self.url)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertIn("peopleForm1", response.context)
|
|
self.assertIn("addressForm", response.context)
|
|
self.assertIn("captchaForm", response.context)
|
|
|
|
@patch("schasite.views.CaptchaForm")
|
|
def test_post_success_creates_membership_and_redirects(self, mock_captcha_form):
|
|
mock_captcha_form.return_value.is_valid.return_value = True
|
|
|
|
payload = {
|
|
"streetAddress": "123 Main St",
|
|
"unit": "",
|
|
"city": "Wheaton",
|
|
"state": "IL",
|
|
"zipCode": "60189",
|
|
"firstName1": "Pat",
|
|
"lastName1": "Neighbor",
|
|
"email1": "pat@example.com",
|
|
"phone1": "6305551212",
|
|
"firstName2": "",
|
|
"lastName2": "",
|
|
"email2": "",
|
|
"phone2": "",
|
|
"captcha": "passed",
|
|
}
|
|
|
|
response = self.client.post(self.url, payload)
|
|
|
|
self.assertEqual(response.status_code, 302)
|
|
self.assertEqual(response.url, reverse("index2"))
|
|
self.assertEqual(Membership.objects.count(), 1)
|
|
membership = Membership.objects.get()
|
|
self.assertEqual(membership.addressmodel1.address_1, "123 Main St")
|
|
self.assertEqual(
|
|
MembershipPerson.objects.filter(membership=membership).count(),
|
|
1,
|
|
)
|
|
|
|
@patch("schasite.views.CaptchaForm")
|
|
def test_post_missing_address_rerenders_form(self, mock_captcha_form):
|
|
mock_captcha_form.return_value.is_valid.return_value = True
|
|
|
|
payload = {
|
|
"streetAddress": "",
|
|
"unit": "",
|
|
"city": "Wheaton",
|
|
"state": "IL",
|
|
"zipCode": "60189",
|
|
"firstName1": "Pat",
|
|
"lastName1": "Neighbor",
|
|
"email1": "pat@example.com",
|
|
"phone1": "6305551212",
|
|
"firstName2": "",
|
|
"lastName2": "",
|
|
"email2": "",
|
|
"phone2": "",
|
|
"captcha": "passed",
|
|
}
|
|
|
|
response = self.client.post(self.url, payload)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(Membership.objects.count(), 0)
|
|
self.assertIn("addressForm", response.context)
|
|
|
|
|
|
class AddressFormTests(TestCase):
|
|
def test_valid_address(self):
|
|
form = AddressForm(
|
|
data={
|
|
"address_1": "123 Main St",
|
|
"address_2": "",
|
|
"city": "Wheaton",
|
|
"state": "IL",
|
|
"zip_code": "60189",
|
|
}
|
|
)
|
|
self.assertTrue(form.is_valid())
|
|
|
|
def test_missing_street_is_invalid(self):
|
|
form = AddressForm(
|
|
data={
|
|
"address_1": "",
|
|
"city": "Wheaton",
|
|
"state": "IL",
|
|
"zip_code": "60189",
|
|
}
|
|
)
|
|
self.assertFalse(form.is_valid())
|
|
self.assertIn("address_1", form.errors)
|
|
|
|
|
|
class PeopleFormTests(TestCase):
|
|
def test_valid_person(self):
|
|
form = PeopleForm(
|
|
data={
|
|
"first_name": "Pat",
|
|
"last_name": "Neighbor",
|
|
"email": "pat@example.com",
|
|
"phone_number": "+16305551212",
|
|
}
|
|
)
|
|
self.assertTrue(form.is_valid())
|
|
|
|
def test_missing_phone_is_invalid(self):
|
|
form = PeopleForm(
|
|
data={
|
|
"first_name": "Pat",
|
|
"last_name": "Neighbor",
|
|
"email": "pat@example.com",
|
|
"phone_number": "",
|
|
}
|
|
)
|
|
self.assertFalse(form.is_valid())
|
|
|
|
|
|
class MembershipModelTests(TestCase):
|
|
def test_get_address_str_and_person_1(self):
|
|
membership = Membership.objects.create()
|
|
AddressModel1.objects.create(
|
|
membership=membership,
|
|
address_1="456 Oak Ave",
|
|
city="Wheaton",
|
|
state="IL",
|
|
zip_code="60189",
|
|
)
|
|
MembershipPerson.objects.create(
|
|
membership=membership,
|
|
first_name="Alex",
|
|
last_name="Resident",
|
|
email="alex@example.com",
|
|
phone_number="+16305559876",
|
|
)
|
|
|
|
self.assertEqual(membership.get_address_str(), "456 Oak Ave")
|
|
self.assertEqual(membership.get_person_1(), "alex@example.com")
|
|
self.assertIn("456 Oak Ave", str(membership))
|
|
|
|
def test_get_person_1_with_no_people(self):
|
|
membership = Membership.objects.create()
|
|
AddressModel1.objects.create(
|
|
membership=membership,
|
|
address_1="789 Pine St",
|
|
city="Wheaton",
|
|
state="IL",
|
|
zip_code="60189",
|
|
)
|
|
|
|
self.assertEqual(membership.get_person_1(), "No Person")
|
|
|
|
|
|
class CalendarEventTests(TestCase):
|
|
def test_has_date_and_future_past_helpers(self):
|
|
today = datetime.date.today()
|
|
past = CalendarEvent.objects.create(
|
|
event_name="Past Picnic",
|
|
start_date=today - datetime.timedelta(days=7),
|
|
)
|
|
future = CalendarEvent.objects.create(
|
|
event_name="Future Picnic",
|
|
start_date=today + datetime.timedelta(days=7),
|
|
)
|
|
undated = CalendarEvent.objects.create(event_name="TBD Event")
|
|
|
|
self.assertTrue(past.has_date())
|
|
self.assertTrue(past.past_event())
|
|
self.assertFalse(past.future_event())
|
|
|
|
self.assertTrue(future.future_event())
|
|
self.assertFalse(future.past_event())
|
|
|
|
self.assertTrue(undated.no_date())
|
|
self.assertFalse(undated.has_date())
|
|
self.assertFalse(undated.past_event())
|
|
self.assertFalse(undated.future_event())
|
|
|
|
def test_time_range_display(self):
|
|
event = CalendarEvent.objects.create(
|
|
event_name="Timed Event",
|
|
start_time=datetime.time(11, 0),
|
|
end_time=datetime.time(15, 0),
|
|
)
|
|
self.assertEqual(event.time_range_display(), "11:00 AM - 3:00 PM")
|
|
|
|
start_only = CalendarEvent.objects.create(
|
|
event_name="Start Only",
|
|
start_time=datetime.time(9, 30),
|
|
)
|
|
self.assertEqual(start_only.time_range_display(), "9:30 AM")
|
|
|
|
no_time = CalendarEvent.objects.create(event_name="No Time")
|
|
self.assertEqual(no_time.time_range_display(), "")
|
|
|
|
def test_calendar_page_splits_past_and_future(self):
|
|
today = datetime.date.today()
|
|
CalendarEvent.objects.create(
|
|
event_name="Past Event",
|
|
start_date=today - datetime.timedelta(days=3),
|
|
)
|
|
CalendarEvent.objects.create(
|
|
event_name="Future Event",
|
|
start_date=today + datetime.timedelta(days=3),
|
|
)
|
|
|
|
response = self.client.get(reverse("calendar2"))
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(len(response.context["past_events"]), 1)
|
|
self.assertEqual(len(response.context["future_events"]), 1)
|
|
self.assertEqual(response.context["past_events"][0].event_name, "Past Event")
|
|
self.assertEqual(
|
|
response.context["future_events"][0].event_name, "Future Event"
|
|
)
|
|
|
|
|
|
@override_settings(
|
|
STRIPE_PUBLISHABLE_KEY="pk_test_123",
|
|
STRIPE_SECRET_KEY="sk_test_123",
|
|
)
|
|
class StripeEndpointTests(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
|
|
def test_stripe_config_returns_publishable_key(self):
|
|
response = self.client.get("/config/")
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.json(), {"publicKey": "pk_test_123"})
|
|
|
|
@patch("schasite.views.stripe.checkout.Session.create")
|
|
def test_create_checkout_session_returns_session_id(self, mock_create):
|
|
mock_create.return_value = {"id": "cs_test_abc"}
|
|
|
|
response = self.client.get("/create-checkout-session/")
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.json(), {"sessionId": "cs_test_abc"})
|
|
mock_create.assert_called_once()
|
|
|
|
@patch("schasite.views.stripe.checkout.Session.create")
|
|
def test_create_checkout_session_returns_error_payload(self, mock_create):
|
|
mock_create.side_effect = Exception("stripe down")
|
|
|
|
response = self.client.get("/create-checkout-session/")
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.json(), {"error": "stripe down"})
|
|
|
|
|
|
class AuthViewTests(TestCase):
|
|
"""Auth member routes are gated on settings.DEBUG at URLconf import time.
|
|
|
|
Django forces DEBUG=False during tests, so those named URLs are not
|
|
registered. Call views via RequestFactory instead of reverse()/Client.
|
|
"""
|
|
|
|
def setUp(self):
|
|
from django.contrib.auth.models import AnonymousUser
|
|
from django.test import RequestFactory
|
|
|
|
from schasite import views
|
|
|
|
self.factory = RequestFactory()
|
|
self.views = views
|
|
self.AnonymousUser = AnonymousUser
|
|
|
|
@patch("schasite.views.render")
|
|
def test_login_get_uses_signin_template(self, mock_render):
|
|
from django.http import HttpResponse
|
|
|
|
mock_render.return_value = HttpResponse(status=200)
|
|
request = self.factory.get("/login/")
|
|
|
|
response = self.views.login(request)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
mock_render.assert_called_once_with(request, "schasite/signin.html", {})
|
|
|
|
@patch("schasite.views.render")
|
|
def test_signup_get_uses_signup_template(self, mock_render):
|
|
from django.http import HttpResponse
|
|
|
|
mock_render.return_value = HttpResponse(status=200)
|
|
request = self.factory.get("/signup/")
|
|
|
|
response = self.views.signup(request)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
mock_render.assert_called_once_with(request, "schasite/signup.html", {})
|
|
|
|
@patch("schasite.views.render")
|
|
def test_password_reset_get_uses_template(self, mock_render):
|
|
from django.http import HttpResponse
|
|
|
|
mock_render.return_value = HttpResponse(status=200)
|
|
request = self.factory.get("/password_reset/")
|
|
|
|
response = self.views.password_reset(request)
|
|
|
|
self.assertEqual(response.status_code, 200)
|
|
mock_render.assert_called_once_with(
|
|
request, "schasite/password_reset.html", {}
|
|
)
|
|
|
|
def test_member_directory_redirects_anonymous(self):
|
|
request = self.factory.get("/directory/")
|
|
request.user = self.AnonymousUser()
|
|
response = self.views.member_directory(request)
|
|
self.assertEqual(response.status_code, 302)
|
|
self.assertIn("/login", response.url)
|
|
|
|
def test_member_dashboard_redirects_anonymous(self):
|
|
request = self.factory.get("/dashboard/")
|
|
request.user = self.AnonymousUser()
|
|
response = self.views.member_dashboard(request)
|
|
self.assertEqual(response.status_code, 302)
|
|
self.assertIn("/login", response.url)
|
|
|
|
def test_member_posts_redirects_anonymous(self):
|
|
request = self.factory.get("/posts/")
|
|
request.user = self.AnonymousUser()
|
|
response = self.views.member_posts(request)
|
|
self.assertEqual(response.status_code, 302)
|
|
self.assertIn("/login", response.url)
|
|
|
|
|
|
def _membership_with_person(email="alex@example.com"):
|
|
membership = Membership.objects.create()
|
|
AddressModel1.objects.create(
|
|
membership=membership,
|
|
address_1="123 Main St",
|
|
city="Wheaton",
|
|
state="IL",
|
|
zip_code="60189",
|
|
)
|
|
person = MembershipPerson.objects.create(
|
|
membership=membership,
|
|
first_name="Alex",
|
|
last_name="Resident",
|
|
email=email,
|
|
phone_number="+16305559876",
|
|
)
|
|
return membership, person
|
|
|
|
|
|
class AdminPaidIndicatorTests(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
self.admin_user = User.objects.create_superuser(
|
|
"admin", "admin@example.com", "pass"
|
|
)
|
|
self.client.force_login(self.admin_user)
|
|
self.this_year = timezone.now().year
|
|
self.membership, self.person = _membership_with_person("paid@example.com")
|
|
|
|
def test_person_marked_paid_when_email_matches_current_year_payment(self):
|
|
Payments.objects.create(
|
|
email="PAID@example.com",
|
|
date=datetime.date(self.this_year, 3, 1),
|
|
)
|
|
|
|
paid = MembershipPerson.objects.annotate(
|
|
_has_payment=person_payment_exists()
|
|
).get(pk=self.person.pk)
|
|
self.assertTrue(paid._has_payment)
|
|
|
|
unpaid_membership, unpaid_person = _membership_with_person("unpaid@example.com")
|
|
unpaid = MembershipPerson.objects.annotate(
|
|
_has_payment=person_payment_exists()
|
|
).get(pk=unpaid_person.pk)
|
|
self.assertFalse(unpaid._has_payment)
|
|
|
|
membership = Membership.objects.annotate(
|
|
_has_payment=membership_payment_exists()
|
|
).get(pk=self.membership.pk)
|
|
self.assertTrue(membership._has_payment)
|
|
other = Membership.objects.annotate(
|
|
_has_payment=membership_payment_exists()
|
|
).get(pk=unpaid_membership.pk)
|
|
self.assertFalse(other._has_payment)
|
|
|
|
def test_prior_year_payment_does_not_count_as_paid(self):
|
|
Payments.objects.create(
|
|
email="paid@example.com",
|
|
date=datetime.date(self.this_year - 1, 6, 1),
|
|
)
|
|
person = MembershipPerson.objects.annotate(
|
|
_has_payment=person_payment_exists()
|
|
).get(pk=self.person.pk)
|
|
self.assertFalse(person._has_payment)
|
|
|
|
def test_person_changelist_shows_paid_icon(self):
|
|
Payments.objects.create(
|
|
email="paid@example.com",
|
|
date=datetime.date(self.this_year, 4, 15),
|
|
)
|
|
url = reverse("admin:schasite_membershipperson_changelist")
|
|
response = self.client.get(url)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, "Paid this year")
|
|
self.assertContains(response, "icon-yes.svg")
|
|
|
|
|
|
class AdminPaymentSearchTests(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
self.admin_user = User.objects.create_superuser(
|
|
"admin", "admin@example.com", "pass"
|
|
)
|
|
self.client.force_login(self.admin_user)
|
|
Payments.objects.create(email="dues@example.com", date=datetime.date(2026, 1, 10))
|
|
Payments.objects.create(email="other@example.com", date=datetime.date(2026, 2, 10))
|
|
|
|
def test_payments_admin_search_by_email(self):
|
|
url = reverse("admin:schasite_payments_changelist")
|
|
response = self.client.get(url, {"q": "dues@example.com"})
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, "dues@example.com")
|
|
self.assertNotContains(response, "other@example.com")
|
|
|
|
|
|
class AdminCsvYearFilterTests(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
self.admin_user = User.objects.create_superuser(
|
|
"admin", "admin@example.com", "pass"
|
|
)
|
|
self.client.force_login(self.admin_user)
|
|
|
|
self.current, self.current_person = _membership_with_person("now@example.com")
|
|
self.old, self.old_person = _membership_with_person("old@example.com")
|
|
Membership.objects.filter(pk=self.old.pk).update(
|
|
created=timezone.make_aware(datetime.datetime(2024, 5, 1, 12, 0, 0))
|
|
)
|
|
|
|
Payments.objects.create(email="now@example.com", date=datetime.date(2026, 3, 1))
|
|
Payments.objects.create(email="old@example.com", date=datetime.date(2024, 3, 1))
|
|
|
|
def test_membership_csv_prompts_for_year(self):
|
|
url = reverse("admin:schasite_membership_changelist")
|
|
response = self.client.post(
|
|
url,
|
|
{
|
|
"action": "download_csv_by_members",
|
|
"_selected_action": [str(self.current.pk), str(self.old.pk)],
|
|
"index": "0",
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertContains(response, "Year:")
|
|
self.assertContains(response, "Download CSV")
|
|
|
|
def test_membership_csv_filters_by_created_year(self):
|
|
url = reverse("admin:schasite_membership_changelist")
|
|
response = self.client.post(
|
|
url,
|
|
{
|
|
"action": "download_csv_by_members",
|
|
"_selected_action": [str(self.current.pk), str(self.old.pk)],
|
|
"index": "0",
|
|
"apply": "Download CSV",
|
|
"year": "2024",
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response["Content-Type"], "text/csv")
|
|
content = response.content.decode()
|
|
self.assertIn("old@example.com", content)
|
|
self.assertNotIn("now@example.com", content)
|
|
|
|
def test_membership_csv_by_address_filters_by_created_year(self):
|
|
url = reverse("admin:schasite_membership_changelist")
|
|
response = self.client.post(
|
|
url,
|
|
{
|
|
"action": "download_csv_by_address",
|
|
"_selected_action": [str(self.current.pk), str(self.old.pk)],
|
|
"index": "0",
|
|
"apply": "Download CSV",
|
|
"year": "2024",
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
content = response.content.decode()
|
|
self.assertIn("old@example.com", content)
|
|
self.assertNotIn("now@example.com", content)
|
|
|
|
def test_payments_csv_filters_by_payment_year(self):
|
|
url = reverse("admin:schasite_payments_changelist")
|
|
payments = list(Payments.objects.values_list("pk", flat=True))
|
|
response = self.client.post(
|
|
url,
|
|
{
|
|
"action": "download_payments",
|
|
"_selected_action": [str(pk) for pk in payments],
|
|
"index": "0",
|
|
"apply": "Download CSV",
|
|
"year": "2024",
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, 200)
|
|
content = response.content.decode()
|
|
self.assertIn("old@example.com", content)
|
|
self.assertNotIn("now@example.com", content)
|