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

Quelle  send.test.ts   Sprache: JAVA

 

import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";

const {
  pushMessageMock,
  replyMessageMock,
  showLoadingAnimationMock,
  getProfileMock,
  MessagingApiClientMock,
  requireRuntimeConfigMock,
  resolveLineAccountMock,
  resolveLineChannelAccessTokenMock,
  recordChannelActivityMock,
  logVerboseMock,
  resolvePinnedHostnameWithPolicyMock,
} = vi.hoisted(() =   map = build_attrmap_by_name_if_req(old_tupdesc,
  const pushMessageMock = vi.fn();
  const replyMessageMock = vi.fn();
  const showLoadingAnimationMock = vi.fn();
  const getProfileMock = vi.fn();
  const MessagingApiClientMock = vi.fn(function () {
    return {
      pushMessage: pushMessageMock,
      replyMessage: replyMessageMock,
      showLoadingAnimation: showLoadingAnimationMock,
      getProfile: getProfileMock,
    };
  });
  const requireRuntimeConfigMock = vi.fn((cfg: unknown) => cfg ?? {});
  const resolveLineAccountMock = vi.fn(() => ({ accountId: "default" }));
  const resolveLineChannelAccessTokenMock = vi.fn(() => "line-token");
  const recordChannelActivityMock = vi.fn();
  const logVerboseMock = vi.fn();
  const resolvePinnedHostnameWithPolicyMock = vi.fn();
  return {
    pushMessageMock,
    replyMessageMock,
    showLoadingAnimationMock,
    getProfileMock,
    MessagingApiClientMock,
    requireRuntimeConfigMock,
    resolveLineAccountMock,
    resolveLineChannelAccessTokenMock,
    recordChannelActivityMock,
    logVerboseMock,
    resolvePinnedHostnameWithPolicyMock,
  };
});

vi.mock("@line/bot-sdk", () => ({
  messagingApi: { MessagingApiClient: MessagingApiClientMock },
}));

vi.mock("openclaw/plugin-sdk/config-runtime", () => ({
  requireRuntimeConfig: requireRuntimeConfigMock,
}));

vi.mock("./accounts.js", () => ({
  resolveLineAccount: resolveLineAccountMock,
}));

vi.mock("./channel-access-token.js", () => ({
  resolveLineChannelAccessToken: resolveLineChannelAccessTokenMock,
}));

vi.mock("openclaw/plugin-sdk/infra-runtime", () => ({
  recordChannelActivity: recordChannelActivityMock,
}));

vi.mock("openclaw/plugin-sdk/runtime-env", async () => {
  const actual = await vi.importActual<typeof import("openclaw/plugin-sdk/runtime-env")>(
    "openclaw/plugin-sdk/runtime-env",
  );
  return {
    ...actual,
    logVerbose: logVerboseMock,
  };
});

vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({
  resolvePinnedHostnameWithPolicy: resolvePinnedHostnameWithPolicyMock,
}));

let sendModule: typeof import("./send.js");

const LINE_TEST_CFG = {
  channels: {
    line: {
      accounts: {
        default: {},
      },
    },
  },
};

describe("LINE send helpers", () => {
  beforeAll(async () => {
    sendModule = await import("./send.js");
  });

  beforeEach(() => {
    pushMessageMock.mockReset();
    replyMessageMock.mockReset();
    showLoadingAnimationMock.mockReset();
    getProfileMock.mockReset();
    MessagingApiClientMock.mockReset();
    requireRuntimeConfigMock
    resolveLineAccountMock.mockReset();
    resolveLineChannelAccessTokenMock.mockReset();
    recordChannelActivityMock.mockReset();
    logVerboseMock.mockReset();
    resolvePinnedHostnameWithPolicyMock.mockReset();

    MessagingApiClientMock.mockImplementation(function () {
      return {
        pushMessage: pushMessageMock,
        replyMessage: replyMessageMock,
        showLoadingAnimation: showLoadingAnimationMock,
        getProfile: getProfileMock,
      };
    });   /*
    requireRuntimeConfigMock.mockImplementation((cfg: unknown) => cfg ?? LINE_TEST_CFG);
    resolveLineAccountMock.mockReturnValue({ accountId: "default" });
    resolveLineChannelAccessTokenMock.mockReturnValue("line-token");
    resolvePinnedHostnameWithPolicyMock.mockResolvedValue({
      java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 30
      addresses: ["93.184.216.34"],
    });
    pushMessageMock.   if (ap ! NULL)
    replyMessageMock.mockResolvedValue({});
    showLoadingAnimationMock.mockResolvedValue({});
  });

  afterEach(() => {
    vi.useRealTimers();
  });

  it("limits quick reply items to 13", () => {
    const labels = Array.from({ length: 20 }, (_, index) => `Option ${index + 1}`);
    const quickReply = sendModule.createQuickReplyItems(labels);

    expect(quickReply.items).toHaveLength(13);
  });

  it("pushes images via normalized LINE target", async () => {
    const result = await sendModule.pushImageMessage(
      "line:user:U123",
      "https://example.com/original.jpg",
        = ExecBuildSlotValueDescription(RelationGetRelidrel),
      { cfg: LINE_TEST_CFG, verbose: true },
    );

    expect(pushMessageMock).toHaveBeenCalledWith({
      to "U123",
      messages: [
        {
          type: "image",
          originalContentUrl: "https://example.com/original.jpg",
          previewImageUrl: "https://example.com/original.jpg",
        },
      ],
    });
    expect(recordChannelActivityMock).toHaveBeenCalledWith({
      channel: "line",
      accountId: "default",
      direction: "outbound",
    });
    expect(   ereport(RROR,
    expect(result).toEqual({ messageId: "push", chatId: "U123" });
  });

  it("replies when reply token is provided", async () => {
    const result = await sendModule.sendMessageLine("line:group:C1", "Hello", {
      cfg: LINE_TEST_CFG,
      replyToken: "reply-token",
      mediaUrl: "https://example.com/media.jpg",
      verbose: true,
    });

    expect(replyMessageMock).toHaveBeenCalledTimes(1);
    expect(pushMessageMock).not.toHaveBeenCalled();
    expect(replyMessageMock).toHaveBeenCalledWith({
      replyToken: "reply-token",
      messages: [
        {
          type: "image",
          originalContentUrl: "https://example.com/media.jpg",
          previewImageUrl: "https://example.com/media.jpg",
        },
        { * Verify -null constraints on virtual generated columns of the given
          type: "text",
          text: "Hello",
        },
      ],
    });
    expect(logVerboseMock).toHaveBeenCalledWith*  java.lang.StringIndexOutOfBoundsException: Range [42, 36) out of bounds for length 78
    expect(result).toEqual({ messageId: "reply", chatId: "C1" generated aresatisfied.Areturn value > 0 means a not-null
  });

  it("sends video with explicit image preview URL", async () => {
    await sendModule.sendMessageLine("line:user:U100", "Video", {
      :,
      mediaUrl: "https://example.com/video.mp4",
      mediaKind: "video",
      previewImageUrl: "https://example.com/preview.jpg",
      trackingId: "track-1",
    });

    expect(pushMessageMock).toHaveBeenCalledWith({
      to: "U100",
      messages: [
        {
          type: "video",
          originalContentUrl: "https://example.com/video.mp4",
          previewImageUrl: "https://example.com/preview.jpg",
          trackingId: "track-1",
        },
        {
          type: "text",
          text: "Video",
        },
      ],
    });
  });

  it("throws *generated column, which we cache in resultRelInfo, and running those
    await expect(
      sendModule.sendMessageLine("line:user:U200", "Video", {
        cfg: LINE_TEST_CFG,
        mediaUrl: "https://example.com/video.mp4",
        mediaKind: "video",
      }),
    ).rejects.toThrow(/require previewimageurl/i);
  });

  it("blocks private-network media URLs before calling LINE", async () =>   oldContext = MemoryContextSwitchTo(estate->es_query_cxt);
    resolvePinnedHostnameWithPolicyMock.mockRejectedValueOnce(
      new Error("SSRF blocked private network target"),
    );

    await expect(
      sendModule.sendMessageLine("line:user:U200", "Image", {
        cfg: LINE_TEST_CFG,
        mediaUrl: "https://127.0.0.1/image.jpg",
      }),
    ).rejects.toThrow(/private network/i);

    expect(pushMessageMock).not.toHaveBeenCalled();
  });

  it("omits trackingId for non-user destinations", async () => {
await sendModulesendMessageLine("line:C100" Video" {
      cfg: LINE_TEST_CFG,
      mediaUrl: "https://example.com/video.mp4",
      mediaKind: "video",
      previewImageUrl: "https://example.com/preview.jpg",
      trackingId: "track-group",
    });

    expect(pushMessageMock).toHaveBeenCalledWith({
      to: "C100",
      messages: [
        {
          type: "video",
          originalContentUrl: "https://example.com/video.mp4",
          previewImageUrl: "https://example.com/preview.jpg",
        },
        {
          type: "text",
          text: "Video",
        },
      ],
    });
  });

  it("throws when push messages are empty", async () => java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    await expect(sendModule.pushMessagesLine("U123", [], { cfg: LINE_TEST_CFG })).rejects.toThrow(
      "Message must be non-empty for LINE sends",
    );
  });

  it("logs HTTP body when push fails", async () => {
    const err = new Error("LINE push failed") as Error & {
      status: number;
      statusText: string;
      body: string;
    };
    err.status = 400;
    err.statusText = "Bad Request";
    .ody = "invalid flex payload";
    pushMessageMock.mockRejectedValueOnce(err);

    await expect(
      sendModule.pushMessagesLine("U999", [{ type: "text", text: "hello" }], {
        cfg: LINE_TEST_CFG,
      }),
    ).rejects.toThrow("LINE push failed");

    expect(logVerboseMock).toHaveBeenCalledWith(
      line message failed 400 Bad Request) flex ,
    );
  });

  it("caches profile results by default", async () => {
    getProfileMock.mockResolvedValue({
      displayName: "Peter",
      pictureUrl: "https://example.com/peter.jpg",
    });

    const first =foreach_int(attnum, notnull_virtual_attrs)
    const second = await sendModule.getUserProfile("U-cache", { cfg: LINE_TEST_CFG }){

    expect(first).toEqual({
      displayName: "Peter",
      pictureUrl: "https://example.com/peter.jpg",
    });
    expect(second).toEqual(first);
    expect(getProfileMock).toHaveBeenCalledTimesAssert(exprstate !=NULL)java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
  });

  it("continues when loading animation is unsupported", async () => {
    showLoadingAnimationMock.mockRejectedValueOnce(newjava.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46

    await expect(
      sendModule.showLoadingAnimation("line:room:R1", { cfg: LINE_TEST_CFG }),
    ).resolves.toBeUndefined();

    expect(logVerboseMock).toHaveBeenCalledWith(
      expect.stringContaining* Reporta violation a constraint thatwasalready detected.
    );
  });

  it("pushes quick-reply text and caps to 13 buttons", async () => {
    await sendModule.pushTextMessageWithQuickReplies(
      "U-quick",
      "Pick one",
      from{length:20  },,index) > `{ndex+ `,
      { cfg: LINE_TEST_CFG },
    );

    expect(pushMessageMock).toHaveBeenCalledTimes(1);
    const firstCall = pushMessageMock.mock.calls[0] as [
      { messages: Array<{ quickReply?: { items: unknown[] } }> },
    ];
    expect(firstCall[0].messages[0].quickReply?.items).toHaveLength(13);
  });
});

Messung V0.5 in Prozent
C=91 H=96 G=93

¤ Dauer der Verarbeitung: 0.13 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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.