import { describe, it, expect } from "vitest"; import { mount } from "@vue/test-utils"; import LiveTable from "../LiveTable.vue"; import type { TelemetryRecord } from "@/lib/telemetry"; function rec(over: Partial & { kind: string }): TelemetryRecord { return over as TelemetryRecord; } const rows: TelemetryRecord[] = [ rec({ kind: "action.dispatched", action: "shop.place-order", ts: "2026-06-15T10:00:00.000Z", envelope: { messageId: "m1", correlationId: "c-abc-1", causationId: "m1" }, }), rec({ kind: "action.completed", action: "shop.place-order", durationMs: 37, ts: "2026-06-15T10:00:01.000Z", envelope: { messageId: "m2", correlationId: "c-abc-1", causationId: "m1" }, }), rec({ kind: "query.executed", query: "shop.order-by-id", durationMs: 4, ts: "2026-06-15T10:00:02.000Z", envelope: { messageId: "m3", correlationId: "c-def-2", causationId: "m1" }, }), ]; describe("LiveTable", () => { it("renders a row per record, newest first by default", () => { const w = mount(LiveTable, { props: { rows } }); const cells = w.findAll('[data-testid="live-row"]'); expect(cells).toHaveLength(3); // default sort is time desc → query.executed (10:00:02) leads expect(cells[0]!.text()).toContain("query.executed"); }); it("shows subject, duration and short correlation", () => { const w = mount(LiveTable, { props: { rows } }); const text = w.text(); expect(text).toContain("shop.place-order"); expect(text).toContain("37ms"); expect(text).toContain("c"); // shortId("c-abc-1") → "c" }); it("toggles sort direction when a header is clicked", async () => { const w = mount(LiveTable, { props: { rows } }); await w.find('[data-testid="col-time"]').trigger("click"); // time → asc const cells = w.findAll('[data-testid="live-row"]'); expect(cells[0]!.text()).toContain("action.dispatched"); // oldest first now }); it("re-sorts by a different column on header click", async () => { const w = mount(LiveTable, { props: { rows } }); await w.find('[data-testid="col-subject"]').trigger("click"); // subject asc const cells = w.findAll('[data-testid="live-row"]'); // "shop.order-by-id" < "shop.place-order" expect(cells[0]!.text()).toContain("shop.order-by-id"); }); it("emits select + update:selectedIndex on row click", async () => { const w = mount(LiveTable, { props: { rows } }); await w.findAll('[data-testid="live-row"]')[0]!.trigger("click"); expect(w.emitted("select")).toBeTruthy(); const idx = w.emitted("update:selectedIndex"); expect(idx).toBeTruthy(); expect(idx![0]![0]).toBe(0); }); it("walks selection with ArrowDown / ArrowUp", async () => { const w = mount(LiveTable, { props: { rows, selectedIndex: -1 } }); const grid = w.find('[data-testid="live-table"]'); await grid.trigger("keydown", { key: "ArrowDown" }); expect(w.emitted("update:selectedIndex")!.at(-1)![0]).toBe(0); await w.setProps({ selectedIndex: 0 }); await grid.trigger("keydown", { key: "ArrowDown" }); expect(w.emitted("update:selectedIndex")!.at(-1)![0]).toBe(1); await w.setProps({ selectedIndex: 1 }); await grid.trigger("keydown", { key: "ArrowUp" }); expect(w.emitted("update:selectedIndex")!.at(-1)![0]).toBe(0); }); it("opens the selected row on Enter", async () => { const w = mount(LiveTable, { props: { rows, selectedIndex: 0 } }); await w.find('[data-testid="live-table"]').trigger("keydown", { key: "Enter" }); expect(w.emitted("select")).toBeTruthy(); }); it("marks the selected row with aria-selected", () => { const w = mount(LiveTable, { props: { rows, selectedIndex: 1 } }); const selected = w.findAll('[data-testid="live-row"]')[1]!; expect(selected.attributes("aria-selected")).toBe("true"); }); });