import { create } from "@bufbuild/protobuf";
import { afterEach, describe, expect, it } from "vitest";
import { AttachmentSchema, MotionMediaFamily, MotionMediaRole, MotionMediaSchema } from "@/types/proto/api/v1/attachment_service_pb";
import {
buildManagedAttachmentMarkdown,
extractManagedAttachmentUIDs,
filterInlineManagedAttachments,
findInvalidManagedAttachmentReferences,
parseManagedAttachmentImageURL,
removeManagedAttachmentReferences,
resolveManagedAttachmentImageSource,
setManagedAttachmentInstanceUrl,
} from "@/utils/managed-attachment";
const attachment = (name: string, filename = "photo.png", externalLink = "") =>
create(AttachmentSchema, { name, filename, type: "image/png", externalLink });
afterEach(() => setManagedAttachmentInstanceUrl(undefined));
describe("managed attachment Markdown", () => {
it("builds canonical URLs and escapes filename alt text", () => {
expect(buildManagedAttachmentMarkdown(attachment("attachments/image-one", "garden[west]\\view.png"))).toBe(
"![garden\\[west\\]\\\\view](/file/attachments/image-one)",
);
});
it("extracts canonical, legacy, and reference-style images", () => {
const content = [
"",
"",
"![three][photo]",
"[photo]: /file/attachments/image-three",
"``",
"```md\n\n```",
].join("\n\n");
expect(Array.from(extractManagedAttachmentUIDs(content))).toEqual(["image-one", "image-two", "image-three"]);
expect(findInvalidManagedAttachmentReferences(content)).toEqual([]);
});
it("uses the first duplicate reference definition like Goldmark", () => {
const content = ["![photo][asset]", "[asset]: /file/attachments/first-image", "[asset]: /file/attachments/second-image"].join("\n\n");
expect(Array.from(extractManagedAttachmentUIDs(content))).toEqual(["first-image"]);
});
it("does not normalize path-relative images into managed attachment URLs", () => {
const source = "file/attachments/image-one";
expect(parseManagedAttachmentImageURL(source)).toBeUndefined();
expect(extractManagedAttachmentUIDs(``)).toEqual(new Set());
expect(resolveManagedAttachmentImageSource(source, [attachment("attachments/image-one")])).toBe(source);
});
// The API matches absolute URLs against the configured instance URL, not the
// browsing origin, and rejects them outright when no instance URL is set.
it("resolves absolute images against the configured instance URL", () => {
setManagedAttachmentInstanceUrl("https://memos.example.com");
const content = [
"",
``,
"",
].join("\n\n");
expect(Array.from(extractManagedAttachmentUIDs(content))).toEqual(["image-one"]);
expect(findInvalidManagedAttachmentReferences(content)).toEqual([]);
});
// Matches the API, which errors on any absolute URL under the managed route
// when it has no instance URL to compare against — whoever hosts it.
it("rejects absolute images when no instance URL is configured", () => {
const own = `${window.location.origin}/file/attachments/image-one`;
const content = [``, ""].join("\n\n");
expect(extractManagedAttachmentUIDs(content)).toEqual(new Set());
expect(findInvalidManagedAttachmentReferences(content)).toEqual([own, "https://example.com/file/attachments/image-two"]);
});
it("reports raw HTML managed images as unsupported instead of ignoring them", () => {
const raw = '
';
expect(extractManagedAttachmentUIDs(raw)).toEqual(new Set());
expect(findInvalidManagedAttachmentReferences(raw)).toEqual([raw]);
// Code spans and fences are not raw HTML, so they stay out of the way.
expect(findInvalidManagedAttachmentReferences('`
`')).toEqual([]);
});
it("rejects encoded, protocol-relative, queried, and malformed managed paths", () => {
for (const url of [
"/file/attachments/%69mage",
"//localhost/file/attachments/image",
"/file/attachments/image?token=x",
"/file/attachments/image#fragment",
"/file/attachments/image/",
"/file/attachments/image/file/extra",
]) {
expect(parseManagedAttachmentImageURL(url)).toBeUndefined();
expect(findInvalidManagedAttachmentReferences(``)).toEqual([url]);
}
});
it("removes only matching image nodes and leaves code and other content intact", () => {
const content = [
"before",
"",
"",
"",
"keep  here",
"",
"``",
].join("\n");
expect(removeManagedAttachmentReferences(content, new Set(["remove-me"]))).toBe(
["before", "", "keep  here", "", "``"].join("\n"),
);
});
it("filters the entire motion group when its still image is inline", () => {
const motion = create(MotionMediaSchema, {
family: MotionMediaFamily.APPLE_LIVE_PHOTO,
role: MotionMediaRole.STILL,
groupId: "live-one",
});
const still = create(AttachmentSchema, { ...attachment("attachments/still"), motionMedia: motion });
const video = create(AttachmentSchema, {
name: "attachments/video",
filename: "photo.mov",
type: "video/quicktime",
motionMedia: create(MotionMediaSchema, { ...motion, role: MotionMediaRole.VIDEO }),
});
const regular = attachment("attachments/regular");
expect(filterInlineManagedAttachments("", [still, video, regular])).toEqual([regular]);
});
it("filters repeated references once and never hides an unrelated attachment", () => {
const own = attachment("attachments/own");
const content = [
"",
"",
"",
].join("\n\n");
expect(filterInlineManagedAttachments(content, [own, attachment("attachments/unrelated")])).toEqual([
attachment("attachments/unrelated"),
]);
});
it("resolves managed image sources through attachment metadata", () => {
const shared = attachment("attachments/shared", "shared.png", `${window.location.origin}/file/attachments/shared?share_token=abc`);
expect(resolveManagedAttachmentImageSource("/file/attachments/shared", [shared])).toBe(shared.externalLink);
expect(resolveManagedAttachmentImageSource("https://example.com/image.png", [shared])).toBe("https://example.com/image.png");
});
});