Stamp UTC on naive API timestamps before serializing (B-35)
SQLite/aiosqlite returns DateTime columns as naive even though every value is written in UTC, so a bare .isoformat() dropped the offset and the frontend's new Date() parsed it as local time. Add a shared isoformat_utc() helper and use it at every call site that was missing the fix already applied ad hoc in rounds.py. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from app.api.timeutil import isoformat_utc
|
||||
|
||||
|
||||
def test_naive_datetime_is_stamped_utc():
|
||||
# SQLite/aiosqlite round-trips DateTime columns as naive even though every
|
||||
# value written is UTC (app.db.models.utcnow) — this is the exact shape
|
||||
# returned by the ORM after a read (B-35).
|
||||
naive = datetime(2026, 7, 27, 6, 56, 47, 489110)
|
||||
result = isoformat_utc(naive)
|
||||
assert result == "2026-07-27T06:56:47.489110+00:00"
|
||||
|
||||
|
||||
def test_aware_datetime_is_left_unchanged():
|
||||
aware = datetime(2026, 7, 27, 6, 56, 47, tzinfo=timezone.utc)
|
||||
assert isoformat_utc(aware) == aware.isoformat()
|
||||
|
||||
|
||||
def test_none_passes_through():
|
||||
assert isoformat_utc(None) is None
|
||||
@@ -162,3 +162,17 @@ async def test_register_rejects_weak_credentials(client, payload):
|
||||
async def test_register_accepts_valid_credentials(client):
|
||||
resp = await client.post("/auth/register", json={"username": "goodname", "password": "longenough1"})
|
||||
assert resp.status_code == 201
|
||||
|
||||
|
||||
async def test_me_created_at_is_utc_stamped(client):
|
||||
"""B-35: SQLite/aiosqlite returns DateTime columns as naive, even though every
|
||||
value written is UTC (app.db.models.utcnow). A bare .isoformat() on that naive
|
||||
value has no "Z"/offset, and JavaScript's `new Date()` then parses it as local
|
||||
time instead of UTC."""
|
||||
token = await _register(client)
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
|
||||
resp = await client.get("/users/me", headers=headers)
|
||||
assert resp.status_code == 200
|
||||
created_at = resp.json()["created_at"]
|
||||
assert created_at.endswith("+00:00") or created_at.endswith("Z")
|
||||
|
||||
Reference in New Issue
Block a user