Ctrl K
ComunidadGuías…

server/commands/documentCreator.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { DocumentHelper } from "@server/models/helpers/DocumentHelper";
import { ProsemirrorHelper } from "@server/models/helpers/ProsemirrorHelper";
import {
  buildUser,
  buildCollection,
  buildDocument,
  buildFileOperation,
  buildTemplate,
} from "@server/test/factories";
import { withAPIContext } from "@server/test/support";
import documentCreator from "./documentCreator";

describe("documentCreator", () => {
  it("should attribute Markdown mentions to the authenticated writer", async () => {
    const user = await buildUser();
    const mentioned = await buildUser({ teamId: user.teamId });
    const document = await withAPIContext(user, (ctx) =>
      documentCreator(ctx, {
        title: "Mentions",
        text: `@[${mentioned.name}](mention://user/${mentioned.id})`,
      })
    );

    await document.reload();
    expect(DocumentHelper.parseMentions(document)).toEqual([
      expect.objectContaining({ modelId: mentioned.id, actorId: user.id }),
    ]);
  });

  describe("content vs text priority", () => {
    it("should prioritize content over text when both are provided", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const testText = "This is plain text";
      const testContent = ProsemirrorHelper.toProsemirror(
        "This is rich content"
      ).toJSON();

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Test Document",
          text: testText,
          content: testContent,
          collectionId: collection.id,
        })
      );

      expect(document.content).toEqual(testContent);
      expect(document.text).toContain("This is rich content");
      expect(document.text).not.toContain("This is plain text");
    });

    it("should use text when content is not provided", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const testText = "This is plain text";

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Test Document",
          text: testText,
          collectionId: collection.id,
        })
      );

      expect(document.text).toContain("This is plain text");
    });

    it("should create empty document when neither content nor text is provided", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Empty Document",
          collectionId: collection.id,
        })
      );

      expect(document.text).toBe("");
      expect(document.title).toBe("Empty Document");
    });
  });

  describe("basic document creation", () => {
    it("should create a basic document", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Test Document",
          text: "This is a test document",
          collectionId: collection.id,
        })
      );

      expect(document.title).toBe("Test Document");
      expect(document.text).toContain("This is a test document");
      expect(document.collectionId).toBe(collection.id);
      expect(document.createdById).toBe(user.id);
      expect(document.lastModifiedById).toBe(user.id);
      expect(document.teamId).toBe(user.teamId);
    });

    it("should create document with custom properties", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Custom Document",
          text: "Custom content",
          icon: "📄",
          color: "#FF0000",
          fullWidth: true,
          collectionId: collection.id,
        })
      );

      expect(document.icon).toBe("📄");
      expect(document.color).toBe("#FF0000");
      expect(document.fullWidth).toBe(true);
    });

    it("should create document as draft when publish is false", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Draft Document",
          text: "Draft content",
          collectionId: collection.id,
          publish: false,
        })
      );

      expect(document.publishedAt).toBeNull();
    });

    it("should publish document when publish is true", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Published Document",
          text: "Published content",
          collectionId: collection.id,
          publish: true,
        })
      );

      expect(document.publishedAt).toBeInstanceOf(Date);
    });

    it("should throw error when trying to publish without collection", async () => {
      const user = await buildUser();

      await expect(
        withAPIContext(user, (ctx) =>
          documentCreator(ctx, {
            title: "Invalid Document",
            text: "Content",
            publish: true,
          })
        )
      ).rejects.toThrow("Collection ID is required to publish");
    });
  });

  describe("template document handling", () => {
    it("should create document from template", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const template = await buildTemplate({
        title: "Template Document",
        text: "Template content",
        icon: "📋",
        color: "#00FF00",
        fullWidth: true,
        userId: user.id,
        teamId: user.teamId,
        collectionId: collection.id,
      });

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "From Template",
          template,
          collectionId: collection.id,
        })
      );

      expect(document.title).toBe("From Template");
      expect(document.icon).toBe("📋");
      expect(document.color).toBe("#00FF00");
      expect(document.fullWidth).toBe(true);
    });

    it("should use template title when no title provided", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const template = await buildTemplate({
        title: "Template Title",
        text: "Template content",
        userId: user.id,
        teamId: user.teamId,
        collectionId: collection.id,
      });

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          template,
          collectionId: collection.id,
        })
      );

      expect(document.title).toBe("Template Title");
    });

    it("should throw error when state is provided with template", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const template = await buildTemplate({
        title: "Template Document",
        text: "Template content",
        userId: user.id,
        teamId: user.teamId,
        collectionId: collection.id,
      });

      await expect(
        withAPIContext(user, (ctx) =>
          documentCreator(ctx, {
            template,
            state: Buffer.from("some state"),
            collectionId: collection.id,
          })
        )
      ).rejects.toThrow(
        "State cannot be set when creating a document from a template"
      );
    });
  });

  describe("parent document handling", () => {
    it("should create child document", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const parentDocument = await buildDocument({
        title: "Parent Document",
        text: "Parent content",
        userId: user.id,
        teamId: user.teamId,
        collectionId: collection.id,
      });

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Child Document",
          text: "Child content",
          parentDocumentId: parentDocument.id,
          collectionId: collection.id,
        })
      );

      expect(document.parentDocumentId).toBe(parentDocument.id);
    });
  });

  describe("import handling", () => {
    it("should handle import metadata", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const fileOperation = await buildFileOperation({
        teamId: user.teamId,
      });

      const sourceMetadata = { fileName: "test" };

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "fileOperation Document",
          text: "fileOperation content",
          importId: fileOperation.id,
          sourceMetadata,
          collectionId: collection.id,
        })
      );

      expect(document.importId).toBe(fileOperation.id);
      expect(document.sourceMetadata).toEqual(sourceMetadata);
    });
  });

  describe("custom emoji handling", () => {
    it("should not escape custom emoji UUIDs in text", async () => {
      const user = await buildUser();
      const collection = await buildCollection({
        userId: user.id,
        teamId: user.teamId,
      });

      const customEmojiId = "550e8400-e29b-41d4-a716-446655440000";
      const text = `Check this :${customEmojiId}: custom emoji`;

      const document = await withAPIContext(user, (ctx) =>
        documentCreator(ctx, {
          title: "Custom Emoji Test",
          text,
          collectionId: collection.id,
        })
      );

      // The custom emoji should be preserved in the text without escaping
      expect(document.text).toContain(`:${customEmojiId}:`);
      expect(document.text).not.toContain(`\\:${customEmojiId}:`);
      expect(document.text).not.toContain(`\\:${customEmojiId}\\:`);

      // The JSON content should include an emoji node with the UUID
      expect(document.content).toBeDefined();
      const contentStr = JSON.stringify(document.content);
      expect(contentStr).toContain('"type":"emoji"');
      expect(contentStr).toContain(`"data-name":"${customEmojiId}"`);
    });
  });
});