require_relative "test_helper" require "maptool/livetrack_client" # No real network calls here — Garmin's page format was verified manually # against real sessions during development; a synthetic fixture (matching # the real page's structure: several `self.__next_f.push(...)` calls, one # holding the track points nested under some data-fetching library's own # structure) is what actually needs to keep working over time. class LiveTrackClientTest < Minitest::Test def setup @client = Maptool::LiveTrackClient.new end FAKE_PAGE = <<~HTML.freeze
HTML def test_finds_track_points_and_session_across_separate_push_payloads payloads = @client.send(:parse_payloads, FAKE_PAGE) points = @client.send(:search, payloads) { |n| n["trackPoints"] if n["trackPoints"].is_a?(Array) } assert_equal 2, points.size assert_in_delta 48.1, points[0]["position"]["lat"] session = @client.send(:search, payloads) { |n| n if n["sessionName"] } assert_equal "Test Ride", session["sessionName"] end def test_undefined_sentinel_is_cleaned_to_nil payloads = @client.send(:parse_payloads, FAKE_PAGE) points = @client.send(:search, payloads) { |n| n["trackPoints"] if n["trackPoints"].is_a?(Array) } cleaned = @client.send(:clean, points) assert_nil cleaned[0]["totalDistanceMeters"] end def test_summarize_pulls_from_last_point_and_session payloads = @client.send(:parse_payloads, FAKE_PAGE) points = @client.send(:clean, @client.send(:search, payloads) { |n| n["trackPoints"] if n["trackPoints"].is_a?(Array) }) session = @client.send(:clean, @client.send(:search, payloads) { |n| n if n["sessionName"] }) result = Maptool::LiveTrackClient::Result.new(points: points, session: session) summary = Maptool::LiveTrackClient.summarize(result) assert_equal "Test Ride", summary["session_name"] assert_equal "CYCLING", summary["activity_type"] assert_equal 5000, summary["distance_meters"] refute summary["active"], "last track point is long in the past" end # Not session["end"].nil? (the original signal, before 2026-09-20 — see # LiveTrackClient's own comment): verified live against a real, # still-recording session that day, Garmin had already set `end` to # exactly start + 24h (the share link's own expiry, not an end time), # so that check called an active session "ended". def test_summarize_marks_active_when_last_point_is_recent payloads = @client.send(:parse_payloads, FAKE_PAGE) points = @client.send(:clean, @client.send(:search, payloads) { |n| n["trackPoints"] if n["trackPoints"].is_a?(Array) }) points[-1] = points[-1].merge("dateTime" => Time.now.utc.iso8601) # end present and in the future, same shape Garmin actually sends for a # session that's still live — active must come from the point, not this. session = @client.send(:clean, @client.send(:search, payloads) { |n| n if n["sessionName"] }) .merge("end" => (Time.now.utc + 24 * 60 * 60).iso8601) result = Maptool::LiveTrackClient::Result.new(points: points, session: session) assert Maptool::LiveTrackClient.summarize(result)["active"] end def test_no_track_points_found_in_a_page_without_them points = @client.send(:search, @client.send(:parse_payloads, "")) { |n| n["trackPoints"] if n["trackPoints"].is_a?(Array) } assert_nil points end end