import { describe, it, expect } from "vitest"; import type { TelemetryRecord } from "../telemetry"; import { recordTime, recordSubject, recordDuration, matchesFilter, filterRecords, sortRecords, nextIndex, computeKpis, distinctKinds, shortId, } from "../live-table"; function rec(over: Partial & { kind: string }): TelemetryRecord { return over as TelemetryRecord; } const dispatched = rec({ kind: "action.dispatched", action: "moderation.submit-post", ts: "2026-06-15T10:00:00.000Z", appName: "moderation", envelope: { messageId: "m-1-aaa", correlationId: "c-1-zzz", causationId: "m-1-aaa", tenant: "acme", }, }); const completed = rec({ kind: "action.completed", action: "moderation.submit-post", durationMs: 42, ts: "2026-06-15T10:00:01.000Z", envelope: { messageId: "m-2", correlationId: "c-1-zzz", causationId: "m-1-aaa" }, }); const failed = rec({ kind: "action.failed", action: "moderation.submit-post", ts: "2026-06-15T10:00:02.000Z", error: { name: "Error", message: "boom" }, envelope: { messageId: "m-3", correlationId: "c-2", causationId: "m-1-aaa" }, }); const published = rec({ kind: "event.published", event: { name: "post.submitted" }, ts: "2026-06-15T10:00:00.500Z", envelope: { messageId: "m-4", correlationId: "c-1-zzz", causationId: "m-1-aaa" }, }); describe("recordTime", () => { it("parses ts to epoch millis", () => { expect(recordTime(dispatched)).toBe(Date.parse("2026-06-15T10:00:00.000Z")); }); it("is 0 when ts is missing or unparseable", () => { expect(recordTime(rec({ kind: "x" }))).toBe(0); expect(recordTime(rec({ kind: "x", ts: "not-a-date" }))).toBe(0); }); }); describe("recordSubject", () => { it("reads the per-kind subject field", () => { expect(recordSubject(dispatched)).toBe("moderation.submit-post"); expect(recordSubject(rec({ kind: "query.executed", query: "users.by-id" }))).toBe( "users.by-id", ); expect(recordSubject(rec({ kind: "actor.transitioned", actor: "Post" }))).toBe("Post"); }); it("unwraps an EventMessage-shaped event or a string event", () => { expect(recordSubject(published)).toBe("post.submitted"); expect(recordSubject(rec({ kind: "listener.fired", event: "post.submitted" }))).toBe( "post.submitted", ); }); it("falls back to em-dash when nothing identifies it", () => { expect(recordSubject(rec({ kind: "mystery" }))).toBe("—"); }); }); describe("recordDuration", () => { it("returns the ms when present, else undefined", () => { expect(recordDuration(completed)).toBe(42); expect(recordDuration(dispatched)).toBeUndefined(); }); }); describe("matchesFilter", () => { it("matches across kind, subject, ids, tenant and error", () => { expect(matchesFilter(dispatched, "submit-post")).toBe(true); expect(matchesFilter(dispatched, "ACME")).toBe(true); // case-insensitive expect(matchesFilter(dispatched, "c-1-zzz")).toBe(true); expect(matchesFilter(failed, "boom")).toBe(true); expect(matchesFilter(dispatched, "nope")).toBe(false); }); it("an empty query matches everything", () => { expect(matchesFilter(dispatched, "")).toBe(true); expect(matchesFilter(dispatched, " ")).toBe(true); }); }); describe("filterRecords", () => { const all = [dispatched, completed, failed, published]; it("filters by kind", () => { expect(filterRecords(all, { kind: "action.failed" })).toEqual([failed]); }); it("filters by correlation chain", () => { expect(filterRecords(all, { correlationId: "c-1-zzz" })).toEqual([ dispatched, completed, published, ]); }); it("filters failures only", () => { expect(filterRecords(all, { failuresOnly: true })).toEqual([failed]); }); it("combines clauses (AND)", () => { expect(filterRecords(all, { correlationId: "c-1-zzz", text: "event" })).toEqual([published]); }); }); describe("sortRecords", () => { const all = [dispatched, completed, failed, published]; it("sorts by time descending (newest first) without mutating input", () => { const out = sortRecords(all, "time", "desc"); expect(out.map((r) => r.kind)).toEqual([ "action.failed", "action.completed", "event.published", "action.dispatched", ]); expect(all[0]).toBe(dispatched); // original order intact }); it("sorts by duration ascending (missing durations sort first)", () => { const out = sortRecords(all, "duration", "asc"); expect(out[out.length - 1]).toBe(completed); // only one with a duration → last asc }); it("sorts by subject and is stable on ties", () => { const a = rec({ kind: "action.completed", action: "z", ts: "2026-06-15T10:00:00.000Z" }); const b = rec({ kind: "action.completed", action: "z", ts: "2026-06-15T10:00:05.000Z" }); const out = sortRecords([a, b], "subject", "asc"); expect(out).toEqual([a, b]); // first-seen order preserved on equal subjects }); }); describe("nextIndex", () => { it("returns -1 for an empty list", () => { expect(nextIndex(0, 0, 1)).toBe(-1); }); it("starts at the head/tail from no selection", () => { expect(nextIndex(-1, 5, 1)).toBe(0); expect(nextIndex(-1, 5, -1)).toBe(4); }); it("clamps at the ends (no wrap)", () => { expect(nextIndex(0, 5, -1)).toBe(0); expect(nextIndex(4, 5, 1)).toBe(4); expect(nextIndex(2, 5, 1)).toBe(3); }); }); describe("computeKpis", () => { it("rolls up totals, failures, distinct kinds + chains, and rate/s", () => { const k = computeKpis([dispatched, completed, failed, published]); expect(k.total).toBe(4); expect(k.failures).toBe(1); expect(k.kinds).toBe(4); expect(k.chains).toBe(2); // c-1-zzz + c-2 // span = 2s across 4 records → 2/s expect(k.perSecond).toBe(2); }); it("rate is 0 with fewer than two timestamps", () => { expect(computeKpis([dispatched]).perSecond).toBe(0); expect(computeKpis([]).total).toBe(0); }); }); describe("distinctKinds", () => { it("lists kinds in first-seen order", () => { expect(distinctKinds([completed, dispatched, completed, published])).toEqual([ "action.completed", "action.dispatched", "event.published", ]); }); }); describe("shortId", () => { it("takes the first dash segment", () => { expect(shortId("c-1-zzz")).toBe("c"); expect(shortId("abcdef0123456789")).toBe("abcdef01"); expect(shortId(undefined)).toBe("—"); }); });