Add running personal records and historical PR badges

This commit is contained in:
Peter Stockings
2026-10-02 13:52:27 +10:00
parent b902ec6312
commit a82135bc89
10 changed files with 240 additions and 9 deletions
+21 -1
View File
@@ -86,12 +86,32 @@ def test_owner_dashboard_activity_json_and_settings_render(app):
assert "point" not in data["chart"][0]
def test_personal_records_render_and_remain_owner_only(app):
with app.app_context():
row = db.session.get(Activity, 1)
row.samples = [{"distance": 0, "time": 0}, {"distance": 5000, "time": 1500}]
row.share_token = "record-test"
db.session.commit()
client = app.test_client()
login(client)
dashboard = client.get("/dashboard").data
assert b"Personal records" in dashboard
assert b"5 km PR" in dashboard
detail = client.get("/activities/1").data
assert b"Best efforts on this run" in detail
assert b"5 km" in detail
assert b"Best efforts on this run" not in client.get("/shared/runs/record-test").data
client.post("/logout")
login(client, "other")
assert b"5 km PR" not in client.get("/dashboard").data
def test_dashboard_replays_latest_accessible_gps_run(app):
client = app.test_client()
login(client)
page = client.get("/dashboard").data
assert b'id="dashboard-route-map" data-url="/activities/1/data"' in page
assert b'id="toggle-route-replay"' in page
assert b'id="toggle-route-replay"' not in page
assert b'vendor/leaflet.js' in page
assert b'class="dashboard-map"' not in page
client.post("/logout")
+64
View File
@@ -0,0 +1,64 @@
from datetime import UTC, datetime, timedelta
from types import SimpleNamespace
import pytest
from app.records import best_efforts, record_book
def run(points, id=1, sport="running"):
return SimpleNamespace(
id=id,
sport=sport,
started_at=datetime(2026, 1, 1, tzinfo=UTC) + timedelta(days=id),
samples=[{"distance": d, "time": t} for d, t in points],
)
def test_fastest_window_can_start_between_samples():
efforts = best_efforts(run([(0, 0), (600, 300), (1500, 480), (2000, 730)]))
assert efforts[0]["seconds"] == pytest.approx(230)
assert efforts[0]["start_m"] == 500
assert efforts[1]["seconds"] == 730
def test_stops_inside_count_but_boundary_stops_do_not():
efforts = best_efforts(run([(0, 0), (0, 60), (500, 210), (500, 270), (1000, 420), (1000, 480)]))
assert efforts[0]["seconds"] == 360
@pytest.mark.parametrize(
"middle",
[
[(None, 150)],
[(float("nan"), 150)],
[(400, 200), (100, 210)],
[(500, 150), (600, 140)],
],
)
def test_invalid_or_reset_data_cannot_be_bridged(middle):
assert best_efforts(run([(0, 0), *middle, (1000, 330)])) == []
def test_missing_time_short_run_and_other_sports_have_no_records():
assert best_efforts(run([(0, None), (5000, None)])) == []
assert best_efforts(run([(0, 0), (999.99, 300)])) == []
assert best_efforts(run([(0, 0), (5000, 300)], sport="cycling")) == []
def test_record_history_backfills_ties_and_improvements():
first = run([(0, 0), (1000, 300)], id=1)
faster = run([(0, 0), (1000, 290)], id=2)
tie = run([(0, 0), (1000, 290)], id=3)
slower = run([(0, 0), (1000, 320)], id=4)
book = record_book([slower, tie, faster, first])
assert book["records"][0]["activity"] is faster
assert [book["runs"][i][0]["pr"] for i in range(1, 5)] == [True, True, False, False]
assert record_book([first, slower])["records"][0]["activity"] is first
def test_all_distances_and_timestamp_gaps_use_elapsed_time():
efforts = best_efforts(run([(0, 100), (42195, 12758.5)]))
assert len(efforts) == 6
assert efforts[0]["seconds"] == pytest.approx(300)
assert efforts[-1]["seconds"] == 12658.5