import { describe, expect, it } from "bun:test"; import { getSubscriptionKey as getLiveSubscriptionKey } from "@islandflow/types"; import { NAV_ITEMS, appendHistoryTail, buildDefaultFlowFilters, classifierToneForFamily, deriveAlertDirection, countActiveFlowFilterGroups, formatCompactUsd, formatOptionContractLabel, flushPausableTapeData, getAlertWindowAnchorTs, getScopedLiveAutoHydrationChannels, getLiveHistoryRetentionCap, getOptionTableSnapshot, getLiveFeedStatus, getLiveManifest, mergeNewestWithOverflow, normalizeAlertSeverity, nextFlowFilterPopoverState, projectPausableTapeState, reducePausableTapeData, shouldRetainLiveSnapshotHistory, shouldShowEquitiesSilentFeedWarning, selectPrimaryClassifierHit, smartMoneyProfileLabel, smartMoneyToneForProfile, statusLabel, toggleFilterValue } from "./terminal"; const makeItem = (traceId: string, seq: number, ts: number) => ({ trace_id: traceId, seq, ts }); const makeAlert = (overrides: Record = {}) => ({ trace_id: "alert-1", seq: 1, source_ts: 1_000, severity: "low", score: 20, hits: [], ...overrides }) as any; describe("live manifest", () => { it("includes options on home and tape", () => { const filters = buildDefaultFlowFilters(); for (const pathname of ["/", "/tape"]) { expect( getLiveManifest(pathname, "SPY", 60000, filters).some( (subscription) => subscription.channel === "options" ) ).toBe(true); } }); it("dedupes tape options subscription", () => { const tapeOptionsSubscriptions = getLiveManifest( "/tape", "SPY", 60000, buildDefaultFlowFilters() ).filter((subscription) => subscription.channel === "options"); expect(tapeOptionsSubscriptions).toHaveLength(1); }); it("keeps option filters on baseline subscription across page changes", () => { const filters = { ...buildDefaultFlowFilters(), minNotional: 125_000 }; const homeOptionsSubscription = getLiveManifest("/", "SPY", 60000, filters).find( (subscription) => subscription.channel === "options" ); const tapeOptionsSubscription = getLiveManifest("/tape", "SPY", 60000, filters).find( (subscription) => subscription.channel === "options" ); expect(homeOptionsSubscription?.filters).toBe(filters); expect(tapeOptionsSubscription?.filters).toBe(filters); }); it("applies global flow filters to flow subscriptions on home and tape", () => { const filters = { ...buildDefaultFlowFilters(), minNotional: 50_000 }; const homeFlowSubscription = getLiveManifest("/", "SPY", 60000, filters).find( (subscription) => subscription.channel === "flow" ); const tapeFlowSubscription = getLiveManifest("/tape", "SPY", 60000, filters).find( (subscription) => subscription.channel === "flow" ); expect(homeFlowSubscription?.filters).toBe(filters); expect(tapeFlowSubscription?.filters).toBe(filters); }); it("includes scoped option and equity subscriptions", () => { const manifest = getLiveManifest( "/tape", "AAPL", 60000, buildDefaultFlowFilters(), { underlying_ids: ["AAPL"], option_contract_id: "AAPL-2025-01-17-200-C" }, { underlying_ids: ["AAPL"] } ); const optionsSubscription = manifest.find( (subscription): subscription is Extract<(typeof manifest)[number], { channel: "options" }> => subscription.channel === "options" ); const equitiesSubscription = manifest.find( (subscription): subscription is Extract<(typeof manifest)[number], { channel: "equities" }> => subscription.channel === "equities" ); expect(optionsSubscription?.underlying_ids).toEqual(["AAPL"]); expect(optionsSubscription?.option_contract_id).toBe("AAPL-2025-01-17-200-C"); expect(equitiesSubscription?.underlying_ids).toEqual(["AAPL"]); }); }); describe("terminal navigation", () => { it("exposes only Home and Tape as top-level destinations", () => { expect(NAV_ITEMS).toEqual([ { href: "/", label: "Home" }, { href: "/tape", label: "Tape" } ]); }); }); describe("live tape pausable helpers", () => { it("queues new items while paused and flushes them on resume", () => { let state = reducePausableTapeData( { visible: [], queued: [], seenKeys: new Set(), dropped: 0 }, [makeItem("a", 1, 100), makeItem("b", 2, 200)], false ); expect(state.visible.map((item) => item.trace_id)).toEqual(["b", "a"]); expect(state.dropped).toBe(0); state = reducePausableTapeData(state, [makeItem("c", 3, 300)], true); expect(state.visible.map((item) => item.trace_id)).toEqual(["b", "a"]); expect(state.queued.map((item) => item.trace_id)).toEqual(["c"]); expect(state.dropped).toBe(1); state = flushPausableTapeData(state); expect(state.visible.map((item) => item.trace_id)).toEqual(["c", "b", "a"]); expect(state.queued).toHaveLength(0); expect(state.dropped).toBe(0); }); it("does not duplicate unchanged arrays", () => { let state = reducePausableTapeData( { visible: [], queued: [], seenKeys: new Set(), dropped: 0 }, [makeItem("a", 1, 100)], false ); state = reducePausableTapeData(state, [makeItem("a", 1, 100)], false); expect(state.visible.map((item) => item.trace_id)).toEqual(["a"]); }); it("applies custom retention limits when requested", () => { const state = reducePausableTapeData( { visible: [], queued: [], seenKeys: new Set(), dropped: 0 }, [makeItem("a", 1, 100), makeItem("b", 2, 200), makeItem("c", 3, 300)], false, 2 ); expect(state.visible.map((item) => item.trace_id)).toEqual(["c", "b"]); expect(state.visible).toHaveLength(2); }); it("marks connected feeds stale once their freshest event ages past the threshold", () => { expect(getLiveFeedStatus("connected", 1000, 500, 1400)).toBe("connected"); expect(getLiveFeedStatus("connected", 1000, 500, 1601)).toBe("stale"); expect(getLiveFeedStatus("disconnected", 1000, 500, 1601)).toBe("disconnected"); }); it("waits for an additional behind-delay before surfacing stale", () => { expect(getLiveFeedStatus("connected", 1000, 500, 2000, 15_000)).toBe("connected"); expect(getLiveFeedStatus("connected", 1000, 500, 16_501, 15_000)).toBe("stale"); }); it("keeps visible history even when live status is stale", () => { const projected = projectPausableTapeState([makeItem("stale", 7, 1000)], "stale", 2000); expect(projected.items.map((item) => item.trace_id)).toEqual(["stale"]); expect(projected.lastUpdate).toBeNull(); }); it("flags connected equities feeds that stay silent past threshold", () => { expect( shouldShowEquitiesSilentFeedWarning({ wsStatus: "connected", equitiesSubscribed: true, connectedAt: 1_000, lastEquitiesEventAt: null, now: 20_000, thresholdMs: 25_000 }) ).toBe(false); expect( shouldShowEquitiesSilentFeedWarning({ wsStatus: "connected", equitiesSubscribed: true, connectedAt: 1_000, lastEquitiesEventAt: null, now: 27_000, thresholdMs: 25_000 }) ).toBe(true); expect( shouldShowEquitiesSilentFeedWarning({ wsStatus: "connected", equitiesSubscribed: true, connectedAt: 1_000, lastEquitiesEventAt: 20_000, now: 40_000, thresholdMs: 25_000 }) ).toBe(false); }); it("retains live history when freshness-gated snapshots are empty", () => { expect(shouldRetainLiveSnapshotHistory("options", true, 0, 3)).toBe(true); expect(shouldRetainLiveSnapshotHistory("equities", true, 0, 2)).toBe(true); expect(shouldRetainLiveSnapshotHistory("alerts", true, 0, 3)).toBe(false); expect(shouldRetainLiveSnapshotHistory("options", true, 1, 3)).toBe(false); expect(shouldRetainLiveSnapshotHistory("options", false, 0, 3)).toBe(false); }); }); describe("live tape history helpers", () => { it("promotes hot-window overflow into the history tail", () => { const currentHot = [makeItem("hot-3", 3, 300), makeItem("hot-2", 2, 200), makeItem("hot-1", 1, 100)]; const incoming = [makeItem("hot-4", 4, 400)]; const { kept, evicted } = mergeNewestWithOverflow(incoming, currentHot, 3); const nextHistory = appendHistoryTail([], evicted, kept, 5000); expect(kept.map((item) => item.trace_id)).toEqual(["hot-4", "hot-3", "hot-2"]); expect(nextHistory.map((item) => item.trace_id)).toEqual(["hot-1"]); }); it("keeps the combined tape continuous beyond the hot live window", () => { let hot: Array> = []; let history: Array> = []; for (let seq = 1; seq <= 5; seq += 1) { const { kept, evicted } = mergeNewestWithOverflow([makeItem(`row-${seq}`, seq, seq * 100)], hot, 2); hot = kept; history = appendHistoryTail(history, evicted, hot, 5000); } expect([...hot, ...history].map((item) => item.trace_id)).toEqual([ "row-5", "row-4", "row-3", "row-2", "row-1" ]); }); it("appends older scoped rows behind the hot live head", () => { const liveHead = Array.from({ length: 100 }, (_, idx) => makeItem(`hot-${idx}`, 200 - idx, 2_000 - idx) ); const older = [makeItem("older-1", 99, 999), makeItem("older-2", 98, 998)]; const next = appendHistoryTail([], older, liveHead, 5000); expect(next.map((item) => item.trace_id)).toEqual(["older-1", "older-2"]); }); it("skips duplicates already present in the live head", () => { const liveHead = [makeItem("latest", 3, 300), makeItem("duplicate", 2, 200)]; const older = [makeItem("duplicate", 2, 200), makeItem("older", 1, 100)]; const next = appendHistoryTail([], older, liveHead, 5000); expect(next.map((item) => item.trace_id)).toEqual(["older"]); }); it("dedupes the seam between promoted overflow and fetched history", () => { const currentHot = [makeItem("hot-3", 3, 300), makeItem("hot-2", 2, 200), makeItem("hot-1", 1, 100)]; const { kept, evicted } = mergeNewestWithOverflow([makeItem("hot-4", 4, 400)], currentHot, 3); const promoted = appendHistoryTail([], evicted, kept, 5000); const merged = appendHistoryTail(promoted, [makeItem("hot-1", 1, 100), makeItem("older", 0, 50)], kept, 5000); expect(merged.map((item) => item.trace_id)).toEqual(["hot-1", "older"]); expect(new Set([...kept, ...merged].map((item) => item.trace_id)).size).toBe(kept.length + merged.length); }); it("trims the history tail to the soft cap", () => { const current = [makeItem("existing", 4, 400)]; const older = [makeItem("older-1", 3, 300), makeItem("older-2", 2, 200)]; const next = appendHistoryTail(current, older, [], 2); expect(next.map((item) => item.trace_id)).toEqual(["existing", "older-1"]); }); it("keeps scoped option and equity history on the normal retention cap", () => { expect( getLiveHistoryRetentionCap({ channel: "options", underlying_ids: ["AAPL"], option_contract_id: "AAPL-2025-01-17-200-C" } as any) ).toBeGreaterThan(0); expect( getLiveHistoryRetentionCap({ channel: "equities", underlying_ids: ["AAPL"] } as any) ).toBeGreaterThan(0); }); it("keeps auto-hydrating scoped live history while next_before exists", () => { const manifest = getLiveManifest( "/tape", "AAPL", 60000, buildDefaultFlowFilters(), { underlying_ids: ["AAPL"], option_contract_id: "AAPL-2025-01-17-200-C" }, { underlying_ids: ["AAPL"] } ); const historyCursors = Object.fromEntries( manifest.map((subscription) => [getLiveSubscriptionKey(subscription), { ts: 1, seq: 1 }]) ); expect( getScopedLiveAutoHydrationChannels(true, "/tape", manifest, historyCursors, {}) ).toEqual(["options", "equities"]); expect( getScopedLiveAutoHydrationChannels(true, "/tape", manifest, historyCursors, { [getLiveSubscriptionKey(manifest.find((subscription) => subscription.channel === "options")!)]: true }) ).toEqual(["equities"]); expect( getScopedLiveAutoHydrationChannels(true, "/tape", manifest, { ...historyCursors, [getLiveSubscriptionKey(manifest.find((subscription) => subscription.channel === "equities")!)]: null }, {}) ).toEqual(["options"]); }); }); describe("options display formatters", () => { it("formats dashed option contracts as ticker strike expiry", () => { expect(formatOptionContractLabel("SPY-2025-01-17-450-C")).toEqual({ ticker: "SPY", strike: "450C", expiration: "01-17-25" }); }); it("formats OCC contracts as ticker strike expiry", () => { expect(formatOptionContractLabel("AAPL250117P00150000")).toEqual({ ticker: "AAPL", strike: "150P", expiration: "01-17-25" }); }); it("preserves decimal strikes and side suffix", () => { expect(formatOptionContractLabel("QQQ-2025-01-17-509.5-C")).toEqual({ ticker: "QQQ", strike: "509.5C", expiration: "01-17-25" }); }); it("returns null when contract parsing fails", () => { expect(formatOptionContractLabel("not-a-contract")).toBeNull(); }); it("formats compact notional values", () => { expect(formatCompactUsd(999)).toBe("999.00"); expect(formatCompactUsd(11_430)).toBe("11.4K"); expect(formatCompactUsd(1_250_000)).toBe("1.3M"); expect(formatCompactUsd(Number.NaN)).toBe("0.00"); }); it("renders options table snapshot values from preserved spot and IV", () => { expect( getOptionTableSnapshot({ price: 1.25, size: 10, notional: 12_500, execution_nbbo_side: "A", execution_underlying_spot: 450.05, execution_iv: 0.42 }) ).toEqual({ spot: "450.05", iv: "42%", side: "A", details: "10@1.25_A", value: "12.5K" }); }); it("renders legacy options table snapshot spot and IV as dashes", () => { const snapshot = getOptionTableSnapshot({ price: 1, size: 2 }); expect(snapshot.spot).toBe("--"); expect(snapshot.iv).toBe("--"); }); }); describe("classifier row decoration helpers", () => { it("maps classifier families to row tones", () => { expect(classifierToneForFamily("large_bullish_call_sweep")).toBe("green"); expect(classifierToneForFamily("large_bearish_put_sweep")).toBe("red"); expect(classifierToneForFamily("straddle")).toBe("blue"); expect(classifierToneForFamily("unknown_family")).toBe("neutral"); }); it("selects primary hits by confidence, source timestamp, then seq", () => { const hit = selectPrimaryClassifierHit([ { ...makeAlert({ classifier_id: "old", confidence: 0.9, source_ts: 1_000, seq: 1 }), direction: "bullish", explanations: [] }, { ...makeAlert({ classifier_id: "new", confidence: 0.9, source_ts: 2_000, seq: 1 }), direction: "bullish", explanations: [] }, { ...makeAlert({ classifier_id: "low", confidence: 0.5, source_ts: 3_000, seq: 9 }), direction: "bullish", explanations: [] } ]); expect(hit?.classifier_id).toBe("new"); }); }); describe("smart-money profile helpers", () => { it("labels and colors primary profiles", () => { expect(smartMoneyProfileLabel("institutional_directional")).toBe("Institutional Directional"); expect(smartMoneyProfileLabel(null)).toBe("Abstained"); expect(smartMoneyToneForProfile("event_driven")).toBe("blue"); expect(smartMoneyToneForProfile(null)).toBe("neutral"); }); }); describe("flow filter popup helpers", () => { it("opens and closes the popup via toggle and dismiss actions", () => { expect(nextFlowFilterPopoverState(false, "toggle")).toBe(true); expect(nextFlowFilterPopoverState(true, "toggle")).toBe(false); expect(nextFlowFilterPopoverState(true, "dismiss")).toBe(false); }); it("tracks active filter groups and resets to defaults", () => { const defaults = buildDefaultFlowFilters(); const next = { ...defaults, securityTypes: toggleFilterValue(defaults.securityTypes, "etf", true), nbboSides: toggleFilterValue(defaults.nbboSides, "B", true), minNotional: 25_000 }; expect(countActiveFlowFilterGroups(defaults)).toBe(0); expect(countActiveFlowFilterGroups(next)).toBe(3); expect(buildDefaultFlowFilters()).toEqual(defaults); }); }); describe("signals helpers", () => { it("normalizes severity aliases/casing and falls back to score", () => { expect(normalizeAlertSeverity(makeAlert({ severity: "HIGH", score: 1 }))).toBe("high"); expect(normalizeAlertSeverity(makeAlert({ severity: "med", score: 1 }))).toBe("medium"); expect(normalizeAlertSeverity(makeAlert({ severity: "informational", score: 99 }))).toBe("low"); expect(normalizeAlertSeverity(makeAlert({ severity: "unknown", score: 80 }))).toBe("high"); expect(normalizeAlertSeverity(makeAlert({ severity: "unknown", score: 45 }))).toBe("medium"); expect(normalizeAlertSeverity(makeAlert({ severity: "unknown", score: 44 }))).toBe("low"); }); it("derives dominant direction with confidence tie-break and neutral fallback", () => { expect( deriveAlertDirection( makeAlert({ hits: [ { direction: "bullish", confidence: 0.4 }, { direction: "bullish", confidence: 0.2 }, { direction: "bearish", confidence: 0.9 } ] }) ) ).toBe("bullish"); expect( deriveAlertDirection( makeAlert({ hits: [ { direction: "bullish", confidence: 0.4 }, { direction: "bearish", confidence: 0.9 } ] }) ) ).toBe("bearish"); expect(deriveAlertDirection(makeAlert({ hits: [{ direction: "weird", confidence: 0.4 }] }))).toBe( "neutral" ); expect(deriveAlertDirection(makeAlert({ hits: [] }))).toBe("neutral"); }); it("anchors strip window to latest visible alert timestamp", () => { const alerts = [ makeAlert({ source_ts: 1_700_000_000_000, severity: "high" }), makeAlert({ source_ts: 1_700_000_000_000 - 10 * 60 * 1000, severity: "low" }) ]; expect(getAlertWindowAnchorTs(alerts, 42)).toBe(1_700_000_000_000); expect(getAlertWindowAnchorTs([], 42)).toBe(42); }); it("returns connected/stale live status labels without live wording", () => { expect(statusLabel("connected", false, "live")).toBe("Connected"); expect(statusLabel("stale", false, "live")).toBe("Feed behind"); }); });