- Add LocationService with create/rename/archive methods - Add LocationProjection for event handling - Add admin-only location management routes at /locations - Add error response helpers (error_response, error_toast, success_toast) - Add toast handler JS to base template for HX-Trigger notifications - Update seeds.py to emit LocationCreated events per spec §23 - Archived locations block animal moves with 422 error 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
110 lines
4.0 KiB
Python
110 lines
4.0 KiB
Python
# ABOUTME: Tests for web response helper functions.
|
|
# ABOUTME: Tests error_response, error_toast, and success_toast helpers.
|
|
|
|
import json
|
|
|
|
from starlette.responses import HTMLResponse
|
|
|
|
from animaltrack.web.responses import error_response, error_toast, success_toast
|
|
|
|
|
|
class TestErrorResponse:
|
|
"""Tests for error_response()."""
|
|
|
|
def test_returns_html_response(self):
|
|
"""error_response returns an HTMLResponse."""
|
|
response = error_response("<div>Error</div>")
|
|
assert isinstance(response, HTMLResponse)
|
|
|
|
def test_default_status_422(self):
|
|
"""error_response defaults to 422 status code."""
|
|
response = error_response("<div>Validation error</div>")
|
|
assert response.status_code == 422
|
|
|
|
def test_custom_status_code(self):
|
|
"""error_response accepts custom status code."""
|
|
response = error_response("<div>Conflict</div>", status_code=409)
|
|
assert response.status_code == 409
|
|
|
|
def test_403_status_code(self):
|
|
"""error_response works with 403 status code."""
|
|
response = error_response("<div>Forbidden</div>", status_code=403)
|
|
assert response.status_code == 403
|
|
|
|
def test_401_status_code(self):
|
|
"""error_response works with 401 status code."""
|
|
response = error_response("<div>Unauthorized</div>", status_code=401)
|
|
assert response.status_code == 401
|
|
|
|
def test_content_in_body(self):
|
|
"""error_response includes content in body."""
|
|
response = error_response("<p>Error message</p>")
|
|
assert b"<p>Error message</p>" in response.body
|
|
|
|
|
|
class TestErrorToast:
|
|
"""Tests for error_toast()."""
|
|
|
|
def test_returns_html_response(self):
|
|
"""error_toast returns an HTMLResponse."""
|
|
response = error_toast("Something went wrong")
|
|
assert isinstance(response, HTMLResponse)
|
|
|
|
def test_default_status_422(self):
|
|
"""error_toast defaults to 422 status code."""
|
|
response = error_toast("Validation failed")
|
|
assert response.status_code == 422
|
|
|
|
def test_custom_status_code(self):
|
|
"""error_toast accepts custom status code."""
|
|
response = error_toast("Not allowed", status_code=403)
|
|
assert response.status_code == 403
|
|
|
|
def test_has_hx_trigger_header(self):
|
|
"""error_toast sets HX-Trigger header."""
|
|
response = error_toast("Error message")
|
|
assert "HX-Trigger" in response.headers
|
|
|
|
def test_toast_message_in_header(self):
|
|
"""error_toast includes message in HX-Trigger header."""
|
|
response = error_toast("Error message")
|
|
trigger = json.loads(response.headers["HX-Trigger"])
|
|
assert trigger["showToast"]["message"] == "Error message"
|
|
|
|
def test_toast_type_error(self):
|
|
"""error_toast sets toast type to error."""
|
|
response = error_toast("Error message")
|
|
trigger = json.loads(response.headers["HX-Trigger"])
|
|
assert trigger["showToast"]["type"] == "error"
|
|
|
|
|
|
class TestSuccessToast:
|
|
"""Tests for success_toast()."""
|
|
|
|
def test_returns_dict(self):
|
|
"""success_toast returns a dict (for HX-Trigger header)."""
|
|
result = success_toast("Action completed")
|
|
assert isinstance(result, dict)
|
|
|
|
def test_has_show_toast_key(self):
|
|
"""success_toast dict has showToast key."""
|
|
result = success_toast("Action completed")
|
|
assert "showToast" in result
|
|
|
|
def test_message_in_toast(self):
|
|
"""success_toast includes message."""
|
|
result = success_toast("Created successfully")
|
|
assert result["showToast"]["message"] == "Created successfully"
|
|
|
|
def test_toast_type_success(self):
|
|
"""success_toast sets toast type to success."""
|
|
result = success_toast("Done")
|
|
assert result["showToast"]["type"] == "success"
|
|
|
|
def test_can_json_dumps(self):
|
|
"""success_toast result can be JSON serialized."""
|
|
result = success_toast("Test message")
|
|
serialized = json.dumps(result)
|
|
assert '"showToast"' in serialized
|
|
assert '"Test message"' in serialized
|