Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openclaw/extensions/msteams/src/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 7 kB image not shown  

Quelle  mentions.test.ts

  Sprache: JAVA
 

import { describe, expect, it } from "vitest";
import { buildMentionEntities, formatMentionText, parseMentions } from "./mentions.js";

function requireFirstEntity(result: ReturnType<typeof parseMentions>) {
  const entity = result.entities[0];
  if (!entity) {
    throw new Error("expected parseMentions to return at least one entity");
  }
  return entity;
}

function requireOnlyEntity(result: ReturnType<typeof parseMentions>) {
  expect(result.entities).toHaveLength(1);
  return requireFirstEntity(result);
}

describe("parseMentions", () => {
  it("parses single mention", () => {
    const result = parseMentions("Hello @[John Doe](28:a1b2c3-d4e5f6)!");

    expect(result.text).toBe("Hello <at>John Doe</at>!");
    expect(requireOnlyEntity(result)).toEqual({
      type: "mention",
      text: "<at>John Doe</at>",
      mentioned: {
        id: "28:a1b2c3-d4e5f6",
        name: "John Doe",
      },
    });
  });

  it("parses multiple mentions", () => {
    const result = parseMentions("Hey @[Alice](28:aaa) and @[Bob](28:bbb), can you review this?");

    expect(result.text).toBe("Hey <at>Alice</at> and <at>Bob</at>, can you review this?");
    expect(result.entities).toHaveLength(2);
    expect(result.entities[0]).toEqual({
      type: "mention",
      text: "<at>Alice</at>",
      mentioned: {
        id: "28:aaa",
        name: "Alice",
      },
    });
    expect(result.entities[1]).toEqual({
      type: "mention",
      text: "<at>Bob</at>",
      mentioned: {
        id: "28:bbb",
        name: "Bob",
      },
    });
  });

  it("handles text without mentions", () => {
    const result = parseMentions("Hello world!");

    expect(result.text).toBe("Hello world!");
    expect(result.entities).toHaveLength(0);
  });

  it("handles empty text", () => {
    const result = parseMentions("");

    expect(result.text).toBe("");
    expect(result.entities).toHaveLength(0);
  });

  it("handles mention with spaces in name", () => {
    const result = parseMentions("@[John Peter Smith](28:a1b2c3)");

    expect(result.text).toBe("<at>John Peter Smith</at>");
    expect(requireFirstEntity(result).mentioned.name).toBe("John Peter Smith");
  });

  it("trims whitespace from id and name", () => {
    const result = parseMentions("@[ John Doe ]( 28:a1b2c3 )");

    expect(requireOnlyEntity(result)).toEqual({
      type: "mention",
      text: "<at>John Doe</at>",
      mentioned: {
        id: "28:a1b2c3",
        name: "John Doe",
      },
    });
  });

  it("handles Japanese characters in mention at start of message", () => {
    const input = "@[タナカ タロウ](a1b2c3d4-e5f6-7890-abcd-ef1234567890) スキル化完了しました!";
    const result = parseMentions(input);

    expect(result.text).toBe("<at>タナカ タロウ</at> スキル化完了しました!");
    expect(requireOnlyEntity(result)).toEqual({
      type: "mention",
      text: "<at>タナカ タロウ</at>",
      mentioned: {
        id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
        name: "タナカ タロウ",
      },
    });

    // Verify entity text exactly matches what's in the formatted text
    const entityText = requireFirstEntity(result).text;
    expect(result.text).toContain(entityText);
    expect(result.text.indexOf(entityText)).toBe(0);
  });

  it("skips mention-like patterns with non-Teams IDs (e.g. in code blocks)", () => {
    // This reproduces the actual failing payload: the message contains a real mention
    // plus `@[表示名](ユーザーID)` as documentation text inside backticks.
    const input =
      "@[タナカ タロウ](a1b2c3d4-e5f6-7890-abcd-ef1234567890) スキル化完了しました!��\n\n" +
      "**作成したスキル:** `teams-mention`\n" +
      "- 機能: Teamsでのメンション形式 `@[表示名](ユーザーID)`\n\n" +
      "**追加対応:**\n" +
      "- ユーザーのID `a1b2c3d4-e5f6-7890-abcd-ef1234567890` を登録済み";
    const result = parseMentions(input);

    // Only the real mention should be parsed; the documentation example should be left as-is
    const firstEntity = requireOnlyEntity(result);
    expect(firstEntity.mentioned.id).toBe("a1b2c3d4-e5f6-7890-abcd-ef1234567890");
    expect(firstEntity.mentioned.name).toBe("タナカ タロウ");

    // The documentation pattern must remain untouched in the text
    expect(result.text).toContain("`@[表示名](ユーザーID)`");
  });

  it("accepts Bot Framework IDs (28:xxx)", () => {
    const result = parseMentions("@[Bot](28:abc-123)");
    expect(requireOnlyEntity(result).mentioned.id).toBe("28:abc-123");
  });

  it("accepts Bot Framework IDs with non-hex payloads (29:xxx)", () => {
    const result = parseMentions("@[Bot](29:08q2j2o3jc09au90eucae)");
    expect(requireOnlyEntity(result).mentioned.id).toBe("29:08q2j2o3jc09au90eucae");
  });

  it("accepts org-scoped IDs with extra segments (8:orgid:...)", () => {
    const result = parseMentions("@[User](8:orgid:2d8c2d2c-1111-2222-3333-444444444444)");
    expect(requireOnlyEntity(result).mentioned.id).toBe(
      "8:orgid:2d8c2d2c-1111-2222-3333-444444444444",
    );
  });

  it("accepts AAD object IDs (UUIDs)", () => {
    const result = parseMentions("@[User](a1b2c3d4-e5f6-7890-abcd-ef1234567890)");
    expect(requireOnlyEntity(result).mentioned.id).toBe("a1b2c3d4-e5f6-7890-abcd-ef1234567890");
  });

  it("rejects non-ID strings as mention targets", () => {
    const result = parseMentions("See @[docs](https://example.com) for details");
    expect(result.entities).toHaveLength(0);
    // Original text preserved
    expect(result.text).toBe("See @[docs](https://example.com) for details");
  });
});

describe("buildMentionEntities", () => {
  it("builds entities from mention info", () => {
    const mentions = [
      { id: "28:aaa", name: "Alice" },
      { id: "28:bbb", name: "Bob" },
    ];

    const entities = buildMentionEntities(mentions);

    expect(entities).toHaveLength(2);
    expect(entities[0]).toEqual({
      type: "mention",
      text: "<at>Alice</at>",
      mentioned: {
        id: "28:aaa",
        name: "Alice",
      },
    });
    expect(entities[1]).toEqual({
      type: "mention",
      text: "<at>Bob</at>",
      mentioned: {
        id: "28:bbb",
        name: "Bob",
      },
    });
  });

  it("handles empty list", () => {
    const entities = buildMentionEntities([]);
    expect(entities).toHaveLength(0);
  });
});

describe("formatMentionText", () => {
  it("formats text with single mention", () => {
    const text = "Hello @John!";
    const mentions = [{ id: "28:xxx", name: "John" }];

    const result = formatMentionText(text, mentions);

    expect(result).toBe("Hello <at>John</at>!");
  });

  it("formats text with multiple mentions", () => {
    const text = "Hey @Alice and @Bob";
    const mentions = [
      { id: "28:aaa", name: "Alice" },
      { id: "28:bbb", name: "Bob" },
    ];

    const result = formatMentionText(text, mentions);

    expect(result).toBe("Hey <at>Alice</at> and <at>Bob</at>");
  });

  it("handles case-insensitive matching", () => {
    const text = "Hey @alice and @ALICE";
    const mentions = [{ id: "28:aaa", name: "Alice" }];

    const result = formatMentionText(text, mentions);

    expect(result).toBe("Hey <at>Alice</at> and <at>Alice</at>");
  });

  it("handles text without mentions", () => {
    const text = "Hello world";
    const mentions = [{ id: "28:xxx", name: "John" }];

    const result = formatMentionText(text, mentions);

    expect(result).toBe("Hello world");
  });

  it("escapes regex metacharacters in names", () => {
    const text = "Hey @John(Test) and @Alice.Smith";
    const mentions = [
      { id: "28:xxx", name: "John(Test)" },
      { id: "28:yyy", name: "Alice.Smith" },
    ];

    const result = formatMentionText(text, mentions);

    expect(result).toBe("Hey <at>John(Test)</at> and <at>Alice.Smith</at>");
  });
});

Messung V0.5 in Prozent
C=99 H=99 G=98

¤ Dauer der Verarbeitung: 0.27 Sekunden  (vorverarbeitet am  2026-05-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.