generated from westfarn/web_django_template
## Summary - Slim the public contact form to email, interest, and message. Name, phone, and address live on the customer profile instead. - Customers can register, sign in, save shipping details, and view order history. Logged-in checkout creates a Stripe Customer and saves cards on Stripe (`setup_future_usage`); we only store `stripe_customer_id`. - Shipment tracking: EasyPost tracker lookup + webhook, plus paste-in numbers from Pirate Ship/Shippo. Customers see carrier status on their orders; `dispatch_due` refreshes open shipments. - Product reviews (1–5) only after a paid/fulfilled purchase of that product. Fixes #7 ## Test plan - [ ] Contact form submits with only email + message; extra name/phone/address fields are ignored - [ ] Register, sign in, save profile (name/phone/shipping) - [ ] Guest checkout still works; after signup, prior orders with that email show in history - [ ] Logged-in checkout prefills shipping and does not collect card data locally - [ ] Portal: buy label or paste a Pirate Ship tracking number, confirm status/events; customer order page shows tracking - [ ] Product page: non-buyers cannot review; buyers can leave one 1–5 star review - [ ] Non-staff users hitting `/portal/` redirect to `/account/` Reviewed-on: #8
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
from datetime import timedelta
|
|
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import Client, TestCase
|
|
from django.urls import reverse
|
|
from django.utils import timezone
|
|
|
|
from analytics.models import PageView, UTMVisit
|
|
|
|
|
|
class PublicPageViewTests(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
|
|
def test_home_records_page_view(self):
|
|
response = self.client.get("/")
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(PageView.objects.count(), 1)
|
|
self.assertEqual(PageView.objects.get().path, "/")
|
|
|
|
def test_about_records_page_view(self):
|
|
self.client.get(reverse("public:about"))
|
|
self.assertEqual(PageView.objects.filter(path="/about/").count(), 1)
|
|
|
|
def test_plain_visit_does_not_create_utm_visit(self):
|
|
self.client.get("/")
|
|
self.assertEqual(PageView.objects.count(), 1)
|
|
self.assertEqual(UTMVisit.objects.count(), 0)
|
|
|
|
def test_utm_hit_records_both(self):
|
|
self.client.get("/?utm_source=test&utm_campaign=demo")
|
|
self.assertEqual(PageView.objects.count(), 1)
|
|
self.assertEqual(UTMVisit.objects.count(), 1)
|
|
|
|
def test_healthz_not_recorded(self):
|
|
self.client.get("/healthz/")
|
|
self.assertEqual(PageView.objects.count(), 0)
|
|
|
|
def test_portal_and_admin_not_recorded(self):
|
|
self.client.get("/portal/")
|
|
self.client.get("/admin/")
|
|
self.assertEqual(PageView.objects.count(), 0)
|
|
|
|
def test_robots_and_sitemap_not_recorded(self):
|
|
self.client.get("/robots.txt")
|
|
self.client.get("/sitemap.xml")
|
|
self.assertEqual(PageView.objects.count(), 0)
|
|
|
|
def test_missing_page_not_recorded(self):
|
|
response = self.client.get("/not-a-real-page/")
|
|
self.assertEqual(response.status_code, 404)
|
|
self.assertEqual(PageView.objects.count(), 0)
|
|
|
|
def test_contact_post_not_recorded(self):
|
|
self.client.post(reverse("public:contact"), {})
|
|
self.assertEqual(PageView.objects.count(), 0)
|
|
|
|
|
|
class AnalyticsReportTests(TestCase):
|
|
def setUp(self):
|
|
self.client = Client()
|
|
user = get_user_model().objects.create_user(
|
|
username="monica", password="pass-word-1", is_staff=True
|
|
)
|
|
self.client.force_login(user)
|
|
|
|
def test_views_card_uses_public_pageviews(self):
|
|
self.client.get("/")
|
|
self.client.get(reverse("public:about"))
|
|
self.client.get(reverse("public:about"))
|
|
stale = PageView.objects.create(path="/terms/")
|
|
PageView.objects.filter(pk=stale.pk).update(
|
|
created_at=timezone.now() - timedelta(days=31)
|
|
)
|
|
|
|
response = self.client.get(reverse("analytics:report"))
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.context["pageviews_last_30_days"], 3)
|
|
top = {row["path"]: row["count"] for row in response.context["top_pages"]}
|
|
self.assertEqual(top["/about/"], 2)
|
|
self.assertEqual(top["/"], 1)
|
|
self.assertNotIn("/terms/", top)
|
|
self.assertContains(response, "Top pages")
|
|
self.assertContains(response, "/about/")
|