mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
177 lines
7.1 KiB
TypeScript
177 lines
7.1 KiB
TypeScript
// @vitest-environment jsdom
|
|
|
|
import type { WorkspaceLeaf } from "obsidian";
|
|
import { describe, expect, it, vi } from "vitest";
|
|
|
|
import { persistedTurnDiffViewState } from "../../../src/features/turn-diff/model";
|
|
import { renderTurnDiffView } from "../../../src/features/turn-diff/render.dom";
|
|
import { CodexTurnDiffView } from "../../../src/features/turn-diff/view.obsidian";
|
|
import { installObsidianDomShims } from "../../support/dom";
|
|
|
|
installObsidianDomShims();
|
|
|
|
describe("turn diff view decisions", () => {
|
|
it("renders the turn diff view with classified unified diff lines", () => {
|
|
const parent = document.createElement("div");
|
|
const copyDiff = vi.fn();
|
|
|
|
renderTurnDiffView(
|
|
parent,
|
|
{
|
|
threadId: "019e061e-0046-7653-a362-86de9a47cb5c",
|
|
turnId: "019e061f-0046-7653-a362-86de9a47cb5c",
|
|
cwd: "/vault/project",
|
|
files: ["src/main.ts"],
|
|
diff: "diff --git a/src/main.ts b/src/main.ts\n--- a/src/main.ts\n+++ b/src/main.ts\n@@\n-old\n+new\n context",
|
|
},
|
|
{ copyDiff },
|
|
);
|
|
|
|
expect(parent.querySelector(".codex-panel-turn-diff__title")?.textContent).toBe("Turn diff");
|
|
expect(parent.querySelector(".codex-panel-turn-diff__meta")?.textContent).toContain("019e061e");
|
|
const changedFilesSummary = parent.querySelector<HTMLElement>(".codex-panel-turn-diff__files summary");
|
|
expect(changedFilesSummary?.textContent).toBe("Changed files");
|
|
expect(changedFilesSummary?.tabIndex).toBe(-1);
|
|
expect(parent.querySelector(".codex-panel-turn-diff__files")?.textContent).toContain("src/main.ts");
|
|
expect(parent.querySelector(".codex-panel-diff__line--file")?.textContent).toBe("src/main.ts");
|
|
expect(parent.textContent).not.toContain("diff --git");
|
|
expect(parent.textContent).not.toContain("+++ b/src/main.ts");
|
|
expect(parent.textContent).not.toContain("-old");
|
|
expect(parent.textContent).not.toContain("+new");
|
|
expect(parent.textContent).toContain("old");
|
|
expect(parent.textContent).toContain("new");
|
|
expect(parent.querySelectorAll(".codex-panel-diff__line--hunk")).toHaveLength(1);
|
|
expect(parent.querySelectorAll(".codex-panel-diff__line--removed")).toHaveLength(1);
|
|
expect(parent.querySelectorAll(".codex-panel-diff__line--added")).toHaveLength(1);
|
|
parent.querySelector<HTMLButtonElement>(".codex-panel-turn-diff__copy")?.click();
|
|
expect(copyDiff).toHaveBeenCalled();
|
|
});
|
|
|
|
it("highlights changed English words inside adjacent removed and added lines", () => {
|
|
const parent = document.createElement("div");
|
|
|
|
renderTurnDiffView(parent, {
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
cwd: "/vault/project",
|
|
files: ["Note.md"],
|
|
diff: "diff --git a/Note.md b/Note.md\n@@\n-The quick brown fox\n+The quick red fox",
|
|
});
|
|
|
|
expect(parent.textContent).toContain("The quick brown fox");
|
|
expect(parent.textContent).toContain("The quick red fox");
|
|
expect(parent.querySelector(".codex-panel-diff__word--removed")?.textContent).toBe("brown");
|
|
expect(parent.querySelector(".codex-panel-diff__word--added")?.textContent).toBe("red");
|
|
});
|
|
|
|
it("highlights changed Japanese words with Intl.Segmenter", () => {
|
|
const parent = document.createElement("div");
|
|
|
|
renderTurnDiffView(parent, {
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
cwd: "/vault/project",
|
|
files: ["Note.md"],
|
|
diff: "diff --git a/Note.md b/Note.md\n@@\n-吾輩は猫である\n+吾輩は犬である",
|
|
});
|
|
|
|
expect(parent.textContent).toContain("吾輩は猫である");
|
|
expect(parent.textContent).toContain("吾輩は犬である");
|
|
expect(parent.querySelector(".codex-panel-diff__word--removed")?.textContent).toBe("猫");
|
|
expect(parent.querySelector(".codex-panel-diff__word--added")?.textContent).toBe("犬");
|
|
});
|
|
|
|
it("pairs changed words by line inside multi-line replacement blocks", () => {
|
|
const parent = document.createElement("div");
|
|
|
|
renderTurnDiffView(parent, {
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
cwd: "/vault/project",
|
|
files: ["Note.md"],
|
|
diff: [
|
|
"diff --git a/Note.md b/Note.md",
|
|
"@@",
|
|
"-これはdiffのテストです。",
|
|
"-今日は元気です。",
|
|
"-とても元気です。",
|
|
"+これはdiffのてすとです。",
|
|
"+きょうはげんきです。",
|
|
"+とてもげんきです。",
|
|
].join("\n"),
|
|
});
|
|
|
|
const removedHighlights = Array.from(parent.querySelectorAll(".codex-panel-diff__word--removed"), (element) => element.textContent);
|
|
const addedHighlights = Array.from(parent.querySelectorAll(".codex-panel-diff__word--added"), (element) => element.textContent);
|
|
|
|
expect(removedHighlights).toEqual(["テスト", "今日", "元気", "元気"]);
|
|
expect(addedHighlights).toEqual(["てすと", "きょう", "げんき", "げんき"]);
|
|
expect(removedHighlights).not.toContain("これはdiffのテスト");
|
|
});
|
|
|
|
it("falls back to line-level rendering for large intraline candidates", () => {
|
|
const parent = document.createElement("div");
|
|
const oldText = `start ${"old ".repeat(600)}end`;
|
|
const newText = `start ${"new ".repeat(600)}end`;
|
|
|
|
renderTurnDiffView(parent, {
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
cwd: "/vault/project",
|
|
files: ["Note.md"],
|
|
diff: `diff --git a/Note.md b/Note.md\n@@\n-${oldText}\n+${newText}`,
|
|
});
|
|
|
|
expect(parent.textContent).toContain(oldText);
|
|
expect(parent.textContent).toContain(newText);
|
|
expect(parent.querySelector(".codex-panel-diff__word")).toBeNull();
|
|
});
|
|
|
|
it("keeps unified diff text out of persisted turn diff view state", () => {
|
|
const persisted = persistedTurnDiffViewState({
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
cwd: "/vault/project",
|
|
files: ["src/main.ts"],
|
|
diff: "@@\n-old\n+new",
|
|
});
|
|
|
|
expect(persisted).toEqual({
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
cwd: "/vault/project",
|
|
files: ["src/main.ts"],
|
|
});
|
|
expect(persisted).not.toHaveProperty("diff");
|
|
});
|
|
|
|
it("renders restored turn diff metadata without unavailable diff text", () => {
|
|
const parent = document.createElement("div");
|
|
|
|
renderTurnDiffView(parent, null, {}, { threadId: "thread", turnId: "turn", cwd: "/vault/project", files: ["src/main.ts"] });
|
|
|
|
expect(parent.querySelector(".codex-panel-turn-diff__meta")?.textContent).toContain("thread / turn");
|
|
expect(parent.textContent).toContain("Turn diff is no longer available.");
|
|
expect(parent.querySelector(".codex-panel-turn-diff__copy")).toBeNull();
|
|
expect(parent.querySelector(".codex-panel-turn-diff__diff")).toBeNull();
|
|
});
|
|
|
|
it("unmounts the turn diff Preact root when the view closes", async () => {
|
|
const containerEl = document.createElement("div");
|
|
const view = new CodexTurnDiffView({ containerEl } as unknown as WorkspaceLeaf);
|
|
|
|
view.setDiffPayload({
|
|
threadId: "thread",
|
|
turnId: "turn",
|
|
cwd: "/vault/project",
|
|
files: ["src/main.ts"],
|
|
diff: "diff --git a/src/main.ts b/src/main.ts\n@@\n-old\n+new",
|
|
});
|
|
|
|
expect(view.contentEl.querySelector(".codex-panel-turn-diff__title")?.textContent).toBe("Turn diff");
|
|
|
|
await view.onClose();
|
|
|
|
expect(view.contentEl.childElementCount).toBe(0);
|
|
});
|
|
});
|