diff --git a/src/functional_tests/test_applet_my_sky.py b/src/functional_tests/test_applet_my_sky.py index f0e9eaa..af147fd 100644 --- a/src/functional_tests/test_applet_my_sky.py +++ b/src/functional_tests/test_applet_my_sky.py @@ -7,6 +7,8 @@ to their account (stored on the User model, independent of any game room). import json as _json import unittest +import zoneinfo +from datetime import datetime from selenium.webdriver.common.by import By @@ -163,7 +165,7 @@ class MySkyAppletWheelTest(FunctionalTest): ) self.gamer = User.objects.create(email="stargazer@test.io") self.gamer.sky_chart_data = _CHART_FIXTURE - self.gamer.sky_birth_place = "Lindenwold, NJ, US" + self.gamer.sky_birth_place = "Baltimore, MD, US" self.gamer.save() # ── T3 ─────────────────────────────────────────────────────────────────── @@ -297,6 +299,79 @@ class MySkyAppletFormTest(FunctionalTest): )) +class MySkyTimezoneRefreshTest(FunctionalTest): + """Selecting a new birth place must refresh the auto-detected timezone.""" + + def setUp(self): + super().setUp() + Applet.objects.get_or_create( + slug="my-sky", + defaults={"name": "My Sky", "grid_cols": 6, "grid_rows": 6, "context": "dashboard"}, + ) + self.gamer = User.objects.create(email="stargazer@test.io") + self.gamer.sky_chart_data = _CHART_FIXTURE + self.gamer.sky_birth_place = "Baltimore, MD, US" + self.gamer.sky_birth_tz = "America/New_York" + self.gamer.sky_birth_lat = 39.2904 + self.gamer.sky_birth_lon = -76.6122 + self.gamer.sky_birth_dt = datetime( + 1990, 6, 15, 12, 0, tzinfo=zoneinfo.ZoneInfo("UTC") + ) + self.gamer.save() + self.sky_url = self.live_server_url + "/dashboard/sky/" + + def test_changing_place_refreshes_auto_detected_timezone(self): + """Picking a new place via the suggestion dropdown must update the + timezone field to the new place's auto-detected TZ rather than sticking + on the previously saved value.""" + self.create_pre_authenticated_session("stargazer@test.io") + self.browser.get(self.sky_url) + + # 1. Initial state: TZ field shows the saved America/New_York + tz_input = self.wait_for(lambda: self.browser.find_element(By.ID, "id_nf_tz")) + self.assertEqual(tz_input.get_attribute("value"), "America/New_York") + + # 2. Mock Nominatim search + sky/preview to return Camarillo / Pacific TZ + camarillo_chart = dict(_CHART_FIXTURE) + camarillo_chart["timezone"] = "America/Los_Angeles" + self.browser.execute_script(""" + const NEW_CHART = """ + _json.dumps(camarillo_chart) + """; + window._origFetch = window.fetch; + window.fetch = function(url, opts) { + if (typeof url === 'string' && url.includes('nominatim.openstreetmap.org/search')) { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve([{ + display_name: 'Camarillo, Ventura County, California, US', + lat: '34.2176', lon: '-119.0384', + }]), + }); + } + if (typeof url === 'string' && url.includes('/sky/preview')) { + return Promise.resolve({ + ok: true, + json: () => Promise.resolve(NEW_CHART), + }); + } + return window._origFetch(url, opts); + }; + """) + + # 3. Type into the place input → click first Nominatim suggestion + place_input = self.browser.find_element(By.ID, "id_nf_place") + place_input.clear() + place_input.send_keys("Cam") + suggestion = self.wait_for_slow(lambda: self.browser.find_element( + By.CSS_SELECTOR, ".sky-suggestion-item" + )) + suggestion.click() + + # 4. After preview resolves, TZ field should show the new auto-detected TZ + self.wait_for(lambda: self.assertEqual( + tz_input.get_attribute("value"), "America/Los_Angeles" + )) + + class MySkyWheelConjunctionTest(FunctionalTest): """Tick lines, z-raise, and dual tooltip for conjunct planets.""" diff --git a/src/templates/apps/dashboard/_partials/_applet-my-sky.html b/src/templates/apps/dashboard/_partials/_applet-my-sky.html index 8ccad62..149a28a 100644 --- a/src/templates/apps/dashboard/_partials/_applet-my-sky.html +++ b/src/templates/apps/dashboard/_partials/_applet-my-sky.html @@ -214,6 +214,8 @@ placeInput.value = place.display_name; latInput.value = parseFloat(place.lat).toFixed(4); lonInput.value = parseFloat(place.lon).toFixed(4); + tzInput.value = ''; + tzHint.textContent = ''; hideSuggestions(); _saveForm(); schedulePreview(); @@ -231,6 +233,8 @@ (pos) => { latInput.value = pos.coords.latitude.toFixed(4); lonInput.value = pos.coords.longitude.toFixed(4); + tzInput.value = ''; + tzHint.textContent = ''; fetch( `https://nominatim.openstreetmap.org/reverse?format=json&lat=${latInput.value}&lon=${lonInput.value}`, { headers: { 'User-Agent': USER_AGENT } } diff --git a/src/templates/apps/dashboard/sky.html b/src/templates/apps/dashboard/sky.html index 52c08aa..0d3d64e 100644 --- a/src/templates/apps/dashboard/sky.html +++ b/src/templates/apps/dashboard/sky.html @@ -184,6 +184,8 @@ placeInput.value = place.display_name; latInput.value = parseFloat(place.lat).toFixed(4); lonInput.value = parseFloat(place.lon).toFixed(4); + tzInput.value = ''; + tzHint.textContent = ''; hideSuggestions(); schedulePreview(); } @@ -200,6 +202,8 @@ (pos) => { latInput.value = pos.coords.latitude.toFixed(4); lonInput.value = pos.coords.longitude.toFixed(4); + tzInput.value = ''; + tzHint.textContent = ''; fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${latInput.value}&lon=${lonInput.value}`, { headers: { 'User-Agent': USER_AGENT }, }) diff --git a/src/templates/apps/gameboard/_partials/_sky_overlay.html b/src/templates/apps/gameboard/_partials/_sky_overlay.html index e3757c0..204f3ed 100644 --- a/src/templates/apps/gameboard/_partials/_sky_overlay.html +++ b/src/templates/apps/gameboard/_partials/_sky_overlay.html @@ -246,6 +246,8 @@ placeInput.value = place.display_name; latInput.value = parseFloat(place.lat).toFixed(4); lonInput.value = parseFloat(place.lon).toFixed(4); + tzInput.value = ''; + tzHint.textContent = ''; hideSuggestions(); _saveForm(); schedulePreview(); @@ -263,6 +265,8 @@ (pos) => { latInput.value = pos.coords.latitude.toFixed(4); lonInput.value = pos.coords.longitude.toFixed(4); + tzInput.value = ''; + tzHint.textContent = ''; fetch(`https://nominatim.openstreetmap.org/reverse?format=json&lat=${latInput.value}&lon=${lonInput.value}`, { headers: { 'User-Agent': USER_AGENT }, })