Files
timetracker/tests/test_middleware_integration.py
T

107 lines
3.9 KiB
Python

import json
from datetime import datetime
from zoneinfo import ZoneInfo
from django.conf import settings
from django.test import TestCase, Client
from games.models import Device, Game, Platform, Purchase, Session
from django.contrib.auth.models import User
class MiddlewareIntegrationTest(TestCase):
"""Integration tests for HTMXMessagesMiddleware.
These tests hit real endpoints that use messages.success() to verify
the full chain: API endpoint → messages → middleware → HX-Trigger header.
"""
@staticmethod
def _create_user():
return User.objects.create_user(
username="testuser", password="testpass123"
)
def setUp(self):
self.client = Client()
self.user = self._create_user()
self.client.force_login(self.user)
pl = Platform(name="Test Platform")
pl.save()
self.game = Game(name="Test Game", platform=pl)
self.game.save()
def test_non_htmx_request_with_message_gets_hx_trigger(self):
"""
Regression test: vanilla fetch() requests that set Django messages
must receive HX-Trigger so fetchWithHtmxTriggers can read them.
"""
response = self.client.patch(
f"/api/games/{self.game.id}/status",
data=json.dumps({"status": "played"}),
content_type="application/json",
)
self.assertEqual(response.status_code, 204)
self.assertIn("HX-Trigger", response)
data = json.loads(response["HX-Trigger"])
self.assertIn("show-toast", data)
self.assertEqual(data["show-toast"]["type"], "success")
def test_session_device_api_endpoint_sends_hx_trigger(self):
"""
Verify the session device API endpoint also produces HX-Trigger.
This is the exact endpoint used by sessiondevice_selector.html.
"""
device = Device(name="Test Device")
device.save()
zt = ZoneInfo(settings.TIME_ZONE)
session = Session(
game=self.game,
device=device,
timestamp_start=datetime(2022, 9, 26, 14, 58, tzinfo=zt),
)
session.save()
response = self.client.patch(
f"/api/session/{session.id}/device",
data=json.dumps({"device_id": device.id}),
content_type="application/json",
)
self.assertEqual(response.status_code, 204)
self.assertIn("HX-Trigger", response)
data = json.loads(response["HX-Trigger"])
self.assertIn("show-toast", data)
self.assertEqual(data["show-toast"]["message"], "Device updated")
def test_refund_purchase_returns_updated_row_with_hx_trigger(
self,
):
"""
Verify the refund endpoint returns the updated row HTML so the page
swaps it in place without navigating away (preserving URL/query params).
"""
purchase = Purchase.objects.create(
date_purchased=datetime(2023, 1, 1),
platform=Platform.objects.first() or pl,
)
purchase.games.set([self.game])
response = self.client.post(
f"/tracker/purchase/{purchase.id}/refund",
data={"set_abandoned": ""},
)
self.assertEqual(response.status_code, 200)
self.assertNotIn("HX-Redirect", response)
self.assertIn("HX-Trigger", response)
data = json.loads(response["HX-Trigger"])
self.assertIn("show-toast", data)
self.assertEqual(data["show-toast"]["message"], "Purchase refunded")
# Verify the row HTML contains the updated row id
body = response.content.decode()
self.assertIn(f'purchase-row-{purchase.id}', body)
# Verify OoO modal close element
self.assertIn('hx-swap-oob', body)
self.assertIn('refund-confirmation-modal', body)
# Verify the purchase is actually refunded
purchase.refresh_from_db()
self.assertIsNotNone(purchase.date_refunded)