test: add unit tests for readSessionMessages stable ID
Verify that readSessionMessages includes the JSONL entry ID in returned messages. Tests cover: - Messages with stable IDs are preserved - Messages without IDs handle gracefully (id: undefined) - Invalid JSON and empty lines are skipped - Message content and metadata are preserved - Nonexistent files return empty array
This commit is contained in:
parent
3a48941c96
commit
56692db403
@ -5,6 +5,7 @@ import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
||||
import {
|
||||
readFirstUserMessageFromTranscript,
|
||||
readLastMessagePreviewFromTranscript,
|
||||
readSessionMessages,
|
||||
readSessionPreviewItemsFromTranscript,
|
||||
} from "./session-utils.fs.js";
|
||||
|
||||
@ -404,3 +405,119 @@ describe("readSessionPreviewItemsFromTranscript", () => {
|
||||
expect(result[0]?.text.endsWith("...")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("readSessionMessages", () => {
|
||||
let tmpDir: string;
|
||||
let sessionFile: string;
|
||||
|
||||
beforeEach(() => {
|
||||
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "session-messages-test-"));
|
||||
sessionFile = path.join(tmpDir, "test-session.jsonl");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
test("includes stable entry ID in returned messages", () => {
|
||||
// Create JSONL transcript with entries that have IDs
|
||||
const entries = [
|
||||
{
|
||||
id: "entry-1",
|
||||
message: { role: "user", content: "Hello" },
|
||||
},
|
||||
{
|
||||
id: "entry-2",
|
||||
message: { role: "assistant", content: "Hi there!" },
|
||||
},
|
||||
{
|
||||
id: "entry-3",
|
||||
message: { role: "user", content: "How are you?" },
|
||||
},
|
||||
];
|
||||
|
||||
const jsonl = entries.map((e) => JSON.stringify(e)).join("\n");
|
||||
fs.writeFileSync(sessionFile, jsonl, "utf-8");
|
||||
|
||||
// Read messages
|
||||
const messages = readSessionMessages("test-session", undefined, sessionFile);
|
||||
|
||||
// Verify each message includes the stable entry ID
|
||||
expect(messages).toHaveLength(3);
|
||||
expect(messages[0]).toMatchObject({ role: "user", content: "Hello", id: "entry-1" });
|
||||
expect(messages[1]).toMatchObject({ role: "assistant", content: "Hi there!", id: "entry-2" });
|
||||
expect(messages[2]).toMatchObject({ role: "user", content: "How are you?", id: "entry-3" });
|
||||
});
|
||||
|
||||
test("handles entries without IDs gracefully", () => {
|
||||
// Create JSONL with mixed entries (some with IDs, some without)
|
||||
const entries = [
|
||||
{
|
||||
id: "entry-1",
|
||||
message: { role: "user", content: "Hello" },
|
||||
},
|
||||
{
|
||||
// No id field
|
||||
message: { role: "assistant", content: "Hi!" },
|
||||
},
|
||||
];
|
||||
|
||||
const jsonl = entries.map((e) => JSON.stringify(e)).join("\n");
|
||||
fs.writeFileSync(sessionFile, jsonl, "utf-8");
|
||||
|
||||
const messages = readSessionMessages("test-session", undefined, sessionFile);
|
||||
|
||||
expect(messages).toHaveLength(2);
|
||||
expect(messages[0]).toMatchObject({ role: "user", content: "Hello", id: "entry-1" });
|
||||
// Second message should have id: undefined (spread of undefined value)
|
||||
expect(messages[1]).toMatchObject({ role: "assistant", content: "Hi!", id: undefined });
|
||||
});
|
||||
|
||||
test("skips empty lines and invalid JSON", () => {
|
||||
const jsonl = [
|
||||
JSON.stringify({ id: "entry-1", message: { role: "user", content: "Valid" } }),
|
||||
"", // Empty line
|
||||
"invalid json {",
|
||||
JSON.stringify({ id: "entry-2", message: { role: "user", content: "Also valid" } }),
|
||||
].join("\n");
|
||||
|
||||
fs.writeFileSync(sessionFile, jsonl, "utf-8");
|
||||
|
||||
const messages = readSessionMessages("test-session", undefined, sessionFile);
|
||||
|
||||
expect(messages).toHaveLength(2);
|
||||
expect(messages[0]).toMatchObject({ id: "entry-1" });
|
||||
expect(messages[1]).toMatchObject({ id: "entry-2" });
|
||||
});
|
||||
|
||||
test("returns empty array when session file does not exist", () => {
|
||||
const messages = readSessionMessages("nonexistent", undefined, "/nonexistent/path.jsonl");
|
||||
expect(messages).toEqual([]);
|
||||
});
|
||||
|
||||
test("preserves message content and metadata", () => {
|
||||
const entries = [
|
||||
{
|
||||
id: "msg-1",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "Complex content" }],
|
||||
metadata: { foo: "bar" },
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const jsonl = entries.map((e) => JSON.stringify(e)).join("\n");
|
||||
fs.writeFileSync(sessionFile, jsonl, "utf-8");
|
||||
|
||||
const messages = readSessionMessages("test-session", undefined, sessionFile);
|
||||
|
||||
expect(messages).toHaveLength(1);
|
||||
expect(messages[0]).toMatchObject({
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "Complex content" }],
|
||||
metadata: { foo: "bar" },
|
||||
id: "msg-1",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user