Files
wehub-resource-sync 64ed910d3f
CI / Backend Checks (push) Has been cancelled
CI / Frontend Checks (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 11:57:20 +08:00

225 lines
6.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
extractCodexPromptPreview,
formatSessionMessagePreview,
groupSessionsByProviderAndDirectory,
shouldHideCodexMessageFromToc,
} from "@/components/sessions/utils";
import type { SessionMeta } from "@/types";
describe("session utils", () => {
it("extracts Codex VS Code prompts after the request marker", () => {
const content = [
"# Context from my IDE setup:",
"",
"## Active file: src/main.ts",
"",
"## My request for Codex:",
"Fix the session title preview",
].join("\n");
expect(extractCodexPromptPreview(content)).toBe(
"Fix the session title preview",
);
});
it("extracts inline Codex VS Code prompts", () => {
const content = [
"# Context from my IDE setup:",
"",
"## My request for Codex: Fix the TOC preview",
].join("\n");
expect(extractCodexPromptPreview(content)).toBe("Fix the TOC preview");
});
it("ignores marker mentions before the Codex request heading", () => {
const content = [
"# Context from my IDE setup:",
"",
"## Active selection:",
"My request for Codex: not the prompt",
"",
"## My request for Codex:",
"Use the real request heading",
].join("\n");
expect(extractCodexPromptPreview(content)).toBe(
"Use the real request heading",
);
});
it("uses the last request heading when the selection contains one", () => {
const content = [
"# Context from my IDE setup:",
"",
"## Active selection: docs/codex-format.md:10-14",
"## My request for Codex:",
"selected document content, not the real request",
"",
"## My request for Codex:",
"the real injected request",
].join("\n");
expect(extractCodexPromptPreview(content)).toBe(
"the real injected request",
);
});
// Known limitation: the IDE marker is matched purely by text, so a
// "## My request for Codex:" line inside the real request body is treated as
// a new boundary and only the trailing part is kept. Pinning this documents
// the best-effort behavior; fully fixing it needs structured IDE section data
// that the Codex VS Code context does not provide.
it("keeps only the trailing part when the request body repeats the heading", () => {
const content = [
"# Context from my IDE setup:",
"",
"## Active file: foo.ts",
"",
"## My request for Codex:",
"Document the format, for example:",
"## My request for Codex:",
"and the rest follows.",
].join("\n");
expect(extractCodexPromptPreview(content)).toBe("and the rest follows.");
});
it("does not extract from ordinary messages that mention the marker", () => {
const content = "Please explain the phrase My request for Codex.";
expect(extractCodexPromptPreview(content)).toBe(content);
});
it("hides Codex context messages without user prompts from the TOC", () => {
expect(
shouldHideCodexMessageFromToc("# AGENTS.md instructions for F:/project"),
).toBe(true);
expect(
shouldHideCodexMessageFromToc(
"<environment_context>\n<cwd>F:/project</cwd>",
),
).toBe(true);
expect(shouldHideCodexMessageFromToc("# Context from my IDE setup:")).toBe(
true,
);
expect(
shouldHideCodexMessageFromToc(
"# Context from my IDE setup:\n\n## My request for Codex:\nFix it",
),
).toBe(false);
});
it("formats message previews with truncation", () => {
expect(formatSessionMessagePreview("short message")).toBe("short message");
expect(formatSessionMessagePreview("a".repeat(51))).toBe(
`${"a".repeat(50)}...`,
);
});
it("groups sessions by provider and project directory", () => {
const sessions: SessionMeta[] = [
{
providerId: "codex",
sessionId: "codex-1",
projectDir: "/workspace/app",
},
{
providerId: "codex",
sessionId: "codex-2",
projectDir: "/workspace/app",
},
{
providerId: "claude",
sessionId: "claude-1",
projectDir: "/workspace/docs",
},
];
const groups = groupSessionsByProviderAndDirectory(sessions, "未知目录");
expect(groups).toHaveLength(2);
expect(groups[0].providerId).toBe("codex");
expect(groups[0].sessions.map((session) => session.sessionId)).toEqual([
"codex-1",
"codex-2",
]);
expect(groups[0].directories).toHaveLength(1);
expect(groups[0].directories[0]).toMatchObject({
projectDir: "/workspace/app",
label: "app",
});
expect(
groups[0].directories[0].sessions.map((session) => session.sessionId),
).toEqual(["codex-1", "codex-2"]);
expect(groups[1].providerId).toBe("claude");
expect(groups[1].directories[0].label).toBe("docs");
});
it("uses an unknown directory group for sessions without project directories", () => {
const sessions: SessionMeta[] = [
{
providerId: "codex",
sessionId: "codex-1",
projectDir: null,
},
{
providerId: "codex",
sessionId: "codex-2",
projectDir: " ",
},
];
const groups = groupSessionsByProviderAndDirectory(sessions, "未知目录");
expect(groups).toHaveLength(1);
expect(groups[0].directories).toHaveLength(1);
expect(groups[0].directories[0]).toMatchObject({
projectDir: null,
label: "未知目录",
});
expect(
groups[0].directories[0].sessions.map((session) => session.sessionId),
).toEqual(["codex-1", "codex-2"]);
});
it("preserves filtered session order inside provider and directory groups", () => {
const sessions: SessionMeta[] = [
{
providerId: "codex",
sessionId: "newest",
projectDir: "/workspace/app",
lastActiveAt: 30,
},
{
providerId: "codex",
sessionId: "middle",
projectDir: "/workspace/docs",
lastActiveAt: 20,
},
{
providerId: "codex",
sessionId: "oldest",
projectDir: "/workspace/app",
lastActiveAt: 10,
},
];
const groups = groupSessionsByProviderAndDirectory(sessions, "未知目录");
expect(groups[0].sessions.map((session) => session.sessionId)).toEqual([
"newest",
"middle",
"oldest",
]);
expect(groups[0].directories.map((group) => group.label)).toEqual([
"app",
"docs",
]);
expect(
groups[0].directories[0].sessions.map((session) => session.sessionId),
).toEqual(["newest", "oldest"]);
});
});