From 1303e952a7f64cc1bc19c8addd13aabc6201048e Mon Sep 17 00:00:00 2001 From: MrAlders0n Date: Fri, 24 Jul 2026 06:19:19 -0400 Subject: [PATCH] Add tests for path endpoint, trace, and clock-drift edge cases --- tests/features/map/packet-path.test.ts | 24 +++++++++++++++++++ .../packets/payload-renderers.test.tsx | 10 ++++++++ tests/lib/formatters.test.ts | 5 ++++ 3 files changed, 39 insertions(+) diff --git a/tests/features/map/packet-path.test.ts b/tests/features/map/packet-path.test.ts index 43860ba..1c78385 100644 --- a/tests/features/map/packet-path.test.ts +++ b/tests/features/map/packet-path.test.ts @@ -124,6 +124,30 @@ describe("buildPacketPaths", () => { expect(buildPacketPaths(d).map((p) => p.key)).toEqual(["trace"]); }); + it("draws nothing for a TRACE with no resolved route", () => { + // per-observation lines are suppressed for TRACE, so without resolvedRoute there is nothing to draw + const d = detail( + [obs(1, [hop("a", -79, 43), hop("b", -75, 45)], { observerId: "obs-1", propagationTimeMs: 100 })], + { header: { payloadType: PayloadType.TRACE, routeType: 1 } } as unknown as Partial, + ); + expect(buildPacketPaths(d)).toEqual([]); + }); + + it("uses the first located candidate for an ambiguous relay hop", () => { + const multi: ResolvedHop = { + confidence: "ambiguous", + nodes: [ + { id: "unlocated", publicKey: "p0" }, // no coords — skipped + { id: "located", publicKey: "p1", longitude: -78, latitude: 44 }, // first with coords — used + ], + }; + const d = detail([ + obs(1, [multi, hop("relay2", -77, 45)], { observerId: "obs-1", propagationTimeMs: 100 }), + ]); + const [path] = buildPacketPaths(d); + expect(path!.points.map((p) => p.id)).toEqual(["located", "relay2"]); + }); + it("omits observations that resolve to fewer than 2 located hops", () => { const d = detail([ obs(1, [hop("a", -79, 43), hop("x")], { observerId: "obs-1" }), diff --git a/tests/features/packets/payload-renderers.test.tsx b/tests/features/packets/payload-renderers.test.tsx index f759115..2b695d7 100644 --- a/tests/features/packets/payload-renderers.test.tsx +++ b/tests/features/packets/payload-renderers.test.tsx @@ -73,6 +73,16 @@ describe("PayloadBreakdown — resolved source/destination endpoints", () => { expect(screen.getByText("BB")).toBeInTheDocument(); }); + it("renders an unresolved (none-confidence) endpoint as a non-clickable resolved block", () => { + // the backend sends resolvedSource/Destination as {confidence:"none", nodes:[]} (not omitted) + // when a 1-byte prefix matches nothing — it must not become a clickable node, but still show the hash + const none: ResolvedHop = { confidence: "none", nodes: [] }; + render(); + expect(screen.queryByRole("button", { name: "AA" })).not.toBeInTheDocument(); + expect(screen.getByText("AA")).toBeInTheDocument(); + expect(screen.getByText("BB")).toBeInTheDocument(); + }); + it("resolves an ANON_REQUEST destination hash to a node block", () => { const onViewNode = vi.fn(); const anon = { type: "ANON_REQUEST", destination: 0xbb, ephemeralPubKey: "cc" }; diff --git a/tests/lib/formatters.test.ts b/tests/lib/formatters.test.ts index d94464c..4e22947 100644 --- a/tests/lib/formatters.test.ts +++ b/tests/lib/formatters.test.ts @@ -119,4 +119,9 @@ describe("formatClockDrift", () => { expect(formatClockDrift(432)).toBe("+7m 12s ahead"); // 7*60 + 12 expect(formatClockDrift(-3670)).toBe("-1h 1m behind"); // 3670 -> 1h 1m }); + + it("renders exact minute/hour boundaries with a zero remainder", () => { + expect(formatClockDrift(60)).toBe("+1m 0s ahead"); + expect(formatClockDrift(3600)).toBe("+1h 0m ahead"); + }); });