Files
outline/server/models/helpers/TextHelper.test.ts
T
Tom Moor 793804cd0d feat: Strip comments from presentation mode (#11860)
* feat: Strip comment marks from documents in presentation mode

Move removeMarks to shared ProsemirrorHelper and use it to strip comment
marks before rendering slides. Make server ProsemirrorHelper extend the
shared class to eliminate duplication and remove SharedProsemirrorHelper
imports from server code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: Use Set for mark lookup and cloneDeep for browser compat

Use a Set for O(1) mark lookups in removeMarks traversal. Replace
structuredClone with lodash/cloneDeep to support older browsers
that lack the native API.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: Add tests for ProsemirrorHelper.removeMarks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 20:21:43 -04:00

171 lines
4.3 KiB
TypeScript

import { createContext } from "@server/context";
import { buildProseMirrorDoc, buildUser } from "@server/test/factories";
import { ProsemirrorHelper } from "./ProsemirrorHelper";
jest.mock("@server/storage/files");
describe("ProsemirrorHelper", () => {
describe("replaceImagesWithAttachments", () => {
it("should return the same document when there are no images", async () => {
const user = await buildUser();
const ctx = createContext({ user });
const doc = buildProseMirrorDoc([
{
type: "paragraph",
content: [{ type: "text", text: "No images here" }],
},
]);
const result = await ProsemirrorHelper.replaceImagesWithAttachments(
ctx,
doc,
user
);
expect(result.toJSON()).toEqual(doc.toJSON());
});
it("should correctly identify images in a document", () => {
const doc = buildProseMirrorDoc([
{
type: "paragraph",
content: [
{
type: "image",
attrs: {
src: "https://example.com/image.png",
alt: "Test image",
},
},
],
},
]);
const images = ProsemirrorHelper.getImages(doc);
expect(images.length).toBe(1);
expect(images[0].attrs.src).toBe("https://example.com/image.png");
expect(images[0].attrs.alt).toBe("Test image");
});
it("should skip images with invalid URLs", async () => {
const user = await buildUser();
const ctx = createContext({ user });
const doc = buildProseMirrorDoc([
{
type: "paragraph",
content: [
{
type: "image",
attrs: {
src: "not-a-valid-url",
alt: "Invalid",
},
},
],
},
]);
const result = await ProsemirrorHelper.replaceImagesWithAttachments(
ctx,
doc,
user
);
// Document should remain unchanged since URL is invalid
expect(result.toJSON()).toEqual(doc.toJSON());
});
it("should skip images with internal URLs", async () => {
const user = await buildUser();
const ctx = createContext({ user });
const doc = buildProseMirrorDoc([
{
type: "paragraph",
content: [
{
type: "image",
attrs: {
src: "/api/attachments.redirect?id=existing-id",
alt: "Internal",
},
},
],
},
]);
const result = await ProsemirrorHelper.replaceImagesWithAttachments(
ctx,
doc,
user
);
// Document should remain unchanged since URL is internal
expect(result.toJSON()).toEqual(doc.toJSON());
});
it("should handle document with multiple node types", async () => {
const user = await buildUser();
const ctx = createContext({ user });
const doc = buildProseMirrorDoc([
{
type: "heading",
attrs: { level: 1 },
content: [{ type: "text", text: "Title" }],
},
{
type: "paragraph",
content: [{ type: "text", text: "Some text" }],
},
{
type: "paragraph",
content: [
{
type: "image",
attrs: {
src: "invalid-url",
alt: "Image",
},
},
],
},
]);
const result = await ProsemirrorHelper.replaceImagesWithAttachments(
ctx,
doc,
user
);
// Document structure should be preserved
expect(result.content.childCount).toBe(3);
expect(result.content.child(0).type.name).toBe("heading");
expect(result.content.child(1).type.name).toBe("paragraph");
expect(result.content.child(2).type.name).toBe("paragraph");
});
it("should handle empty document", async () => {
const user = await buildUser();
const ctx = createContext({ user });
const doc = buildProseMirrorDoc([
{
type: "paragraph",
content: [],
},
]);
const result = await ProsemirrorHelper.replaceImagesWithAttachments(
ctx,
doc,
user
);
expect(result.toJSON()).toEqual(doc.toJSON());
});
});
});