diff --git a/ui/src/pages/overview/event-log.test.ts b/ui/src/pages/overview/event-log.test.ts new file mode 100644 index 00000000000..ff55941c650 --- /dev/null +++ b/ui/src/pages/overview/event-log.test.ts @@ -0,0 +1,39 @@ +/* @vitest-environment jsdom */ + +import { render } from "lit"; +import { describe, expect, it } from "vitest"; +import { formatEventPayload } from "../../lib/presenter.ts"; +import { renderOverviewEventLog } from "./event-log.ts"; + +function createBoundaryPayload() { + const emptyPayload = formatEventPayload({ message: "" }); + const valueStart = emptyPayload.indexOf('""') + 1; + return { message: `${"a".repeat(119 - valueStart)}🙂tail` }; +} + +describe("renderOverviewEventLog", () => { + it("keeps payload previews UTF-16 safe at the truncation boundary", () => { + const payload = createBoundaryPayload(); + const formatted = formatEventPayload(payload); + const oldPreview = formatted.slice(0, 120); + expect(oldPreview.charCodeAt(oldPreview.length - 1)).toBe(0xd83d); + + const container = document.createElement("div"); + render( + renderOverviewEventLog({ + events: [ + { + ts: 1, + event: "agent.message", + payload, + }, + ], + }), + container, + ); + + const preview = container.querySelector(".ov-event-log-payload")?.textContent ?? ""; + expect(preview).toBe(formatted.slice(0, 119)); + expect(preview.charCodeAt(preview.length - 1)).not.toBe(0xd83d); + }); +}); diff --git a/ui/src/pages/overview/event-log.ts b/ui/src/pages/overview/event-log.ts index 94d04d4e303..9363609d578 100644 --- a/ui/src/pages/overview/event-log.ts +++ b/ui/src/pages/overview/event-log.ts @@ -3,7 +3,7 @@ import { html, nothing } from "lit"; import type { EventLogEntry } from "../../api/event-log.ts"; import { icons } from "../../components/icons.ts"; import { t } from "../../i18n/index.ts"; -import { formatTimeMs } from "../../lib/format.ts"; +import { formatTimeMs, truncateText } from "../../lib/format.ts"; import { formatEventPayload } from "../../lib/presenter.ts"; type OverviewEventLogProps = { @@ -32,7 +32,7 @@ export function renderOverviewEventLog(props: OverviewEventLogProps) { ${entry.event} ${entry.payload ? html`${formatEventPayload(entry.payload).slice(0, 120)}${truncateText(formatEventPayload(entry.payload), 120).text}` : nothing}