sky wheel: element contributor display; sign + house tooltips — TDD
All checks were successful
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline was successful

sky_save now re-fetches from PySwiss server-side on save so stored
chart_data always carries enriched element format (contributors/stellia/
parades). New sky/data endpoint serves fresh PySwiss data to the My Sky
applet on load, replacing the stale inline json_script approach.

natus-wheel.js: sign ring slices (data-sign-name) and house ring slices
(data-house) now have click handlers with _activateSign/_activateHouse;
em-dash fallback added for classic elements with empty contributor lists.
Action URLs sky/preview, sky/save, sky/data lose trailing slashes.

Jasmine: T12 sign tooltip, T13 house tooltip, T14 enriched element
contributor display (symbols, Stellium/Parade formations, em-dash fallback).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-04-21 20:07:40 -04:00
parent 02975d79d3
commit b8ac004fb6
10 changed files with 868 additions and 95 deletions

View File

@@ -1,8 +1,8 @@
"""Integration tests for the My Sky dashboard views.
sky_view — GET /dashboard/sky/ → renders sky template
sky_preview — GET /dashboard/sky/preview/ → proxies to PySwiss (no DB write)
sky_save — POST /dashboard/sky/save/ → saves natal data to User model
sky_preview — GET /dashboard/sky/preview → proxies to PySwiss (no DB write)
sky_save — POST /dashboard/sky/save → saves natal data to User model
"""
import json
@@ -113,14 +113,13 @@ class SkySaveTest(TestCase):
self.assertEqual(response.status_code, 405)
def test_saves_sky_fields_to_user(self):
chart = {"planets": {}, "houses": {}, "elements": {}}
payload = {
"birth_dt": "1990-06-15T08:30:00",
"birth_lat": 51.5074,
"birth_lon": -0.1278,
"birth_place": "London, UK",
"house_system": "O",
"chart_data": chart,
"chart_data": {},
}
response = self._post(payload)
self.assertEqual(response.status_code, 200)
@@ -131,7 +130,6 @@ class SkySaveTest(TestCase):
self.assertAlmostEqual(float(self.user.sky_birth_lon), -0.1278, places=3)
self.assertEqual(self.user.sky_birth_place, "London, UK")
self.assertEqual(self.user.sky_house_system, "O")
self.assertEqual(self.user.sky_chart_data, chart)
def test_invalid_json_returns_400(self):
response = self.client.post(

View File

@@ -1,4 +1,6 @@
import json
import lxml.html
from unittest.mock import patch, MagicMock
from django.contrib.messages import get_messages
from django.test import override_settings, TestCase
@@ -482,3 +484,117 @@ class WalletAppletTest(TestCase):
def test_wallet_applet_has_manage_link(self):
[link] = self.parsed.cssselect("#id_applet_wallet a.wallet-manage-link")
self.assertEqual(link.get("href"), "/dashboard/wallet/")
ENRICHED_CHART = {
"planets": {"Sun": {"lon": 10.0, "sign": "Aries", "house": 1, "degree": 10.0}},
"houses": {"cusps": [float(i * 30) for i in range(12)]},
"elements": {
"Fire": {"count": 3, "contributors": ["Sun", "Mars", "Jupiter"]},
"Stone": {"count": 1, "contributors": ["Venus"]},
"Air": {"count": 2, "contributors": ["Mercury", "Uranus"]},
"Water": {"count": 0, "contributors": []},
"Time": {"count": 1, "stellia": ["Saturn"]},
"Space": {"count": 1, "parades": ["Neptune"]},
},
"distinctions": [],
"timezone": "UTC",
}
BIRTH_PAYLOAD = {
"birth_dt": "1990-06-15T12:00:00Z",
"birth_lat": 51.5,
"birth_lon": -0.1,
"birth_place": "London",
"house_system": "O",
"chart_data": {"stale": True},
}
@override_settings(PYSWISS_URL="http://pyswiss-test")
class SkySaveViewTest(TestCase):
def setUp(self):
self.user = User.objects.create(
email="disco@test.io",
sky_birth_lat=51.5,
sky_birth_lon=-0.1,
sky_birth_place="London",
)
self.client.force_login(self.user)
def _post(self, payload=None):
return self.client.post(
"/dashboard/sky/save",
data=json.dumps(payload or BIRTH_PAYLOAD),
content_type="application/json",
)
@patch("apps.dashboard.views.http_requests.get")
def test_save_fetches_enriched_data_from_pyswiss(self, mock_get):
mock_resp = MagicMock()
mock_resp.raise_for_status.return_value = None
mock_resp.json.return_value = dict(ENRICHED_CHART)
mock_get.return_value = mock_resp
response = self._post()
self.assertEqual(response.status_code, 200)
self.user.refresh_from_db()
saved = self.user.sky_chart_data
self.assertIsNotNone(saved)
fire = saved["elements"]["Fire"]
self.assertIn("contributors", fire)
self.assertIn("Sun", fire["contributors"])
@patch("apps.dashboard.views.http_requests.get")
def test_save_falls_back_to_client_data_if_pyswiss_unreachable(self, mock_get):
mock_get.side_effect = Exception("connection refused")
client_chart = {"planets": {}, "elements": {"Fire": 2}}
payload = dict(BIRTH_PAYLOAD, chart_data=client_chart)
response = self._post(payload)
self.assertEqual(response.status_code, 200)
self.user.refresh_from_db()
self.assertEqual(self.user.sky_chart_data, client_chart)
@override_settings(PYSWISS_URL="http://pyswiss-test")
class SkyNatusDataViewTest(TestCase):
def setUp(self):
self.user = User.objects.create(
email="disco@test.io",
sky_birth_lat=51.5,
sky_birth_lon=-0.1,
sky_birth_place="London",
)
self.client.force_login(self.user)
@patch("apps.dashboard.views.http_requests.get")
def test_returns_enriched_chart_data(self, mock_get):
from datetime import datetime, timezone as dt_timezone
self.user.sky_birth_dt = datetime(1990, 6, 15, 12, 0, tzinfo=dt_timezone.utc)
self.user.sky_house_system = "O"
self.user.save(update_fields=["sky_birth_dt", "sky_house_system"])
mock_resp = MagicMock()
mock_resp.raise_for_status.return_value = None
mock_resp.json.return_value = dict(ENRICHED_CHART)
mock_get.return_value = mock_resp
response = self.client.get("/dashboard/sky/data")
self.assertEqual(response.status_code, 200)
data = json.loads(response.content)
self.assertIn("elements", data)
fire = data["elements"]["Fire"]
self.assertIn("contributors", fire)
def test_returns_404_if_no_birth_data_saved(self):
response = self.client.get("/dashboard/sky/data")
self.assertEqual(response.status_code, 404)
def test_requires_login(self):
self.client.logout()
response = self.client.get("/dashboard/sky/data")
self.assertRedirects(response, "/?next=/dashboard/sky/data", fetch_redirect_response=False)