vicky469_aside/tests/commentHighlightController.test.ts
vicky469 0cdc6ca29d refactor(comments): remove resolved feature
Removes the resolved/unresolve comment feature entirely. Comments are
now always visible — there is no archived state or toggle.

- Removes `resolved?: boolean` from CommentThread, Comment, and all
  storage/normalization paths
- Removes resolveComment/unresolveComment from CommentManager,
  CommentMutationController, and public plugin API
- Removes shouldShowResolvedComments/setShowResolvedComments from
  session, mutation, and persistence controllers
- Removes sidebar resolve button, toolbar chip, and resolved empty
  states from AsideView
- Removes setThreadResolved sync event generation; keeps the op in the
  union type as a backward-compatible no-op so old stored events parse
  without error
- Deletes resolvedCommentVisibility.ts, commentSelectionVisibility.ts,
  and resolve-note-comment.mjs scripts
- Updates README to remove resolved feature mentions
- Updates all tests accordingly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 18:11:45 +08:00

265 lines
8.6 KiB
TypeScript

import * as assert from "node:assert/strict";
import test from "node:test";
import type { Comment } from "../src/commentManager";
import { findClickedHighlightCommentId } from "../src/comments/commentHighlightClickTarget";
import {
findClickedIndexLivePreviewTarget,
isIndexNativeCollapseControlTarget,
shouldBlockIndexPreviewBackgroundTarget,
shouldUseIndexPreviewRowActivator,
shouldUseIndexLivePreviewLineFallback,
} from "../src/comments/commentIndexClickTarget";
import { buildPreviewHighlightWraps } from "../src/comments/commentHighlightPlanner";
function createComment(overrides: Partial<Comment> = {}): Comment {
return {
id: "comment-1",
filePath: "note.md",
startLine: 0,
startChar: 0,
endLine: 0,
endChar: 4,
selectedText: "beta",
selectedTextHash: "hash-beta",
comment: "note",
timestamp: 1710000000000,
...overrides,
};
}
test("buildPreviewHighlightWraps follows the source occurrence when rendered text repeats", () => {
const wraps = buildPreviewHighlightWraps(
"beta one beta",
0,
"beta one beta",
[createComment({
startChar: 9,
endChar: 13,
selectedText: "beta",
})],
);
assert.equal(wraps.length, 1);
assert.equal(wraps[0].start, 9);
assert.equal(wraps[0].end, 13);
assert.equal(wraps[0].comment.id, "comment-1");
});
test("buildPreviewHighlightWraps respects section line offsets for later lines", () => {
const wraps = buildPreviewHighlightWraps(
"alpha beta\nsecond beta",
10,
"alpha beta\nsecond beta",
[createComment({
id: "comment-2",
startLine: 11,
startChar: 7,
endLine: 11,
endChar: 11,
selectedText: "beta",
})],
);
assert.equal(wraps.length, 1);
assert.equal(wraps[0].start, 18);
assert.equal(wraps[0].end, 22);
assert.equal(wraps[0].comment.id, "comment-2");
});
test("findClickedHighlightCommentId returns the clicked highlight comment id", () => {
const target = {
closest: (selector: string) => {
assert.equal(selector, ".aside-highlight");
return {
getAttribute: (name: string) => {
assert.equal(name, "data-comment-id");
return "comment-7";
},
};
},
};
assert.equal(findClickedHighlightCommentId(target), "comment-7");
});
test("findClickedHighlightCommentId returns null when the target is not inside a highlight", () => {
const target = {
closest: () => null,
};
assert.equal(findClickedHighlightCommentId(target), null);
assert.equal(findClickedHighlightCommentId(null), null);
});
test("findClickedIndexLivePreviewTarget resolves comment links from live preview DOM", () => {
const target = {
closest: (selector: string) => {
if (selector === "a.aside-index-comment-link[data-aside-comment-url]") {
return {
dataset: {
asideCommentUrl: "obsidian://aside-comment?vault=public&file=books%2FNote.md&commentId=comment-7",
},
getAttribute: () => null,
};
}
return null;
},
};
assert.deepEqual(findClickedIndexLivePreviewTarget(target), {
kind: "comment",
filePath: "books/Note.md",
commentId: "comment-7",
});
});
test("findClickedIndexLivePreviewTarget resolves file headings from live preview DOM", () => {
const target = {
closest: (selector: string) => {
if (selector === "a.aside-index-comment-link[data-aside-comment-url]") {
return null;
}
if (selector.includes(".aside-index-heading-label[title]")) {
return {
dataset: {},
getAttribute: (name: string) => {
assert.equal(name, "title");
return "books/Note.md";
},
};
}
return null;
},
};
assert.deepEqual(findClickedIndexLivePreviewTarget(target), {
kind: "file",
filePath: "books/Note.md",
});
});
test("findClickedIndexLivePreviewTarget resolves plain generated file links", () => {
const target = {
closest: (selector: string) => {
if (selector.includes("a[href^=\"obsidian://open\"]")) {
return {
dataset: {},
getAttribute: (name: string) => {
assert.equal(name, "href");
return "obsidian://open?vault=public&file=books%2FNote.md";
},
};
}
return null;
},
};
assert.deepEqual(findClickedIndexLivePreviewTarget(target), {
kind: "file",
filePath: "books/Note.md",
});
});
test("findClickedIndexLivePreviewTarget leaves native collapse controls alone", () => {
const target = {
closest: (selector: string) => {
if (selector.includes(".collapse-indicator")) {
return {
dataset: {},
getAttribute: () => null,
};
}
if (selector === "a.aside-index-comment-link[data-aside-comment-url]") {
return {
dataset: {
asideCommentUrl: "obsidian://aside-comment?vault=public&file=books%2FNote.md&commentId=comment-7",
},
getAttribute: () => null,
};
}
return null;
},
};
assert.equal(isIndexNativeCollapseControlTarget(target), true);
assert.equal(findClickedIndexLivePreviewTarget(target), null);
});
test("findClickedIndexLivePreviewTarget returns null for non-index elements", () => {
const target = {
closest: () => null,
};
assert.equal(findClickedIndexLivePreviewTarget(target), null);
assert.equal(findClickedIndexLivePreviewTarget(null), null);
});
test("index live preview line fallback ignores clicks on blank line space", () => {
const lineEl = {};
const childTarget = {};
assert.equal(shouldUseIndexLivePreviewLineFallback(lineEl, lineEl), false);
assert.equal(shouldUseIndexLivePreviewLineFallback(childTarget, lineEl), false);
});
test("index preview row activator ignores clicks on blank row space", () => {
const rowEl = {};
const childTarget = {};
assert.equal(shouldUseIndexPreviewRowActivator(rowEl, rowEl), false);
assert.equal(shouldUseIndexPreviewRowActivator(childTarget, rowEl), false);
});
test("index preview background clicks are blocked only on generated index rows", () => {
const generatedRow = {
getAttribute: () => null,
querySelector: (selector: string) =>
selector.includes("a[href^=\"obsidian://open\"]")
? { getAttribute: () => "obsidian://open?vault=dev&file=test.md" }
: null,
};
const rowBackgroundTarget = {
closest: (selector: string) => selector === "p, li" ? generatedRow : null,
};
const linkTarget = {
closest: (selector: string) => {
if (selector.includes("a[href^=\"obsidian://open\"]")) {
return {
dataset: {},
getAttribute: () => "obsidian://open?vault=dev&file=test.md",
};
}
if (selector === "p, li") {
return generatedRow;
}
return null;
},
};
const normalRowTarget = {
closest: (selector: string) => selector === "p, li"
? { getAttribute: () => null, querySelector: () => null }
: null,
};
assert.equal(shouldBlockIndexPreviewBackgroundTarget(rowBackgroundTarget), true);
assert.equal(shouldBlockIndexPreviewBackgroundTarget(linkTarget), false);
assert.equal(shouldBlockIndexPreviewBackgroundTarget(normalRowTarget), false);
});
test("index preview background clicks are blocked on the generated preview surface", () => {
const indexPreviewBackgroundTarget = {
closest: () => null,
matches: (selector: string) => selector.includes(".aside-index-note-view .markdown-preview-sizer"),
};
const normalPreviewBackgroundTarget = {
closest: () => null,
matches: () => false,
};
assert.equal(shouldBlockIndexPreviewBackgroundTarget(indexPreviewBackgroundTarget), true);
assert.equal(shouldBlockIndexPreviewBackgroundTarget(normalPreviewBackgroundTarget), false);
});