Spaces:
Paused
Paused
| import { describe, expect, it } from "vitest"; | |
| import { | |
| buildTelegramThreadParams, | |
| buildTypingThreadParams, | |
| expandTextLinks, | |
| normalizeForwardedContext, | |
| resolveTelegramForumThreadId, | |
| } from "./helpers.js"; | |
| describe("resolveTelegramForumThreadId", () => { | |
| it("returns undefined for non-forum groups even with messageThreadId", () => { | |
| // Reply threads in regular groups should not create separate sessions | |
| expect(resolveTelegramForumThreadId({ isForum: false, messageThreadId: 42 })).toBeUndefined(); | |
| }); | |
| it("returns undefined for non-forum groups without messageThreadId", () => { | |
| expect( | |
| resolveTelegramForumThreadId({ isForum: false, messageThreadId: undefined }), | |
| ).toBeUndefined(); | |
| expect( | |
| resolveTelegramForumThreadId({ isForum: undefined, messageThreadId: 99 }), | |
| ).toBeUndefined(); | |
| }); | |
| it("returns General topic (1) for forum groups without messageThreadId", () => { | |
| expect(resolveTelegramForumThreadId({ isForum: true, messageThreadId: undefined })).toBe(1); | |
| expect(resolveTelegramForumThreadId({ isForum: true, messageThreadId: null })).toBe(1); | |
| }); | |
| it("returns the topic id for forum groups with messageThreadId", () => { | |
| expect(resolveTelegramForumThreadId({ isForum: true, messageThreadId: 99 })).toBe(99); | |
| }); | |
| }); | |
| describe("buildTelegramThreadParams", () => { | |
| it("omits General topic thread id for message sends", () => { | |
| expect(buildTelegramThreadParams(1)).toBeUndefined(); | |
| }); | |
| it("includes non-General topic thread ids", () => { | |
| expect(buildTelegramThreadParams(99)).toEqual({ message_thread_id: 99 }); | |
| }); | |
| it("normalizes thread ids to integers", () => { | |
| expect(buildTelegramThreadParams(42.9)).toEqual({ message_thread_id: 42 }); | |
| }); | |
| }); | |
| describe("buildTypingThreadParams", () => { | |
| it("returns undefined when no thread id is provided", () => { | |
| expect(buildTypingThreadParams(undefined)).toBeUndefined(); | |
| }); | |
| it("includes General topic thread id for typing indicators", () => { | |
| expect(buildTypingThreadParams(1)).toEqual({ message_thread_id: 1 }); | |
| }); | |
| it("normalizes thread ids to integers", () => { | |
| expect(buildTypingThreadParams(42.9)).toEqual({ message_thread_id: 42 }); | |
| }); | |
| }); | |
| describe("normalizeForwardedContext", () => { | |
| it("handles forward_origin users", () => { | |
| const ctx = normalizeForwardedContext({ | |
| forward_origin: { | |
| type: "user", | |
| sender_user: { first_name: "Ada", last_name: "Lovelace", username: "ada", id: 42 }, | |
| date: 123, | |
| }, | |
| } as any); | |
| expect(ctx).not.toBeNull(); | |
| expect(ctx?.from).toBe("Ada Lovelace (@ada)"); | |
| expect(ctx?.fromType).toBe("user"); | |
| expect(ctx?.fromId).toBe("42"); | |
| expect(ctx?.fromUsername).toBe("ada"); | |
| expect(ctx?.fromTitle).toBe("Ada Lovelace"); | |
| expect(ctx?.date).toBe(123); | |
| }); | |
| it("handles hidden forward_origin names", () => { | |
| const ctx = normalizeForwardedContext({ | |
| forward_origin: { type: "hidden_user", sender_user_name: "Hidden Name", date: 456 }, | |
| } as any); | |
| expect(ctx).not.toBeNull(); | |
| expect(ctx?.from).toBe("Hidden Name"); | |
| expect(ctx?.fromType).toBe("hidden_user"); | |
| expect(ctx?.fromTitle).toBe("Hidden Name"); | |
| expect(ctx?.date).toBe(456); | |
| }); | |
| it("handles legacy forwards with signatures", () => { | |
| const ctx = normalizeForwardedContext({ | |
| forward_from_chat: { | |
| title: "OpenClaw Updates", | |
| username: "openclaw", | |
| id: 99, | |
| type: "channel", | |
| }, | |
| forward_signature: "Stan", | |
| forward_date: 789, | |
| } as any); | |
| expect(ctx).not.toBeNull(); | |
| expect(ctx?.from).toBe("OpenClaw Updates (Stan)"); | |
| expect(ctx?.fromType).toBe("legacy_channel"); | |
| expect(ctx?.fromId).toBe("99"); | |
| expect(ctx?.fromUsername).toBe("openclaw"); | |
| expect(ctx?.fromTitle).toBe("OpenClaw Updates"); | |
| expect(ctx?.fromSignature).toBe("Stan"); | |
| expect(ctx?.date).toBe(789); | |
| }); | |
| it("handles legacy hidden sender names", () => { | |
| const ctx = normalizeForwardedContext({ | |
| forward_sender_name: "Legacy Hidden", | |
| forward_date: 111, | |
| } as any); | |
| expect(ctx).not.toBeNull(); | |
| expect(ctx?.from).toBe("Legacy Hidden"); | |
| expect(ctx?.fromType).toBe("legacy_hidden_user"); | |
| expect(ctx?.date).toBe(111); | |
| }); | |
| }); | |
| describe("expandTextLinks", () => { | |
| it("returns text unchanged when no entities are provided", () => { | |
| expect(expandTextLinks("Hello world")).toBe("Hello world"); | |
| expect(expandTextLinks("Hello world", null)).toBe("Hello world"); | |
| expect(expandTextLinks("Hello world", [])).toBe("Hello world"); | |
| }); | |
| it("returns text unchanged when there are no text_link entities", () => { | |
| const entities = [ | |
| { type: "mention", offset: 0, length: 5 }, | |
| { type: "bold", offset: 6, length: 5 }, | |
| ]; | |
| expect(expandTextLinks("@user hello", entities)).toBe("@user hello"); | |
| }); | |
| it("expands a single text_link entity", () => { | |
| const text = "Check this link for details"; | |
| const entities = [{ type: "text_link", offset: 11, length: 4, url: "https://example.com" }]; | |
| expect(expandTextLinks(text, entities)).toBe( | |
| "Check this [link](https://example.com) for details", | |
| ); | |
| }); | |
| it("expands multiple text_link entities", () => { | |
| const text = "Visit Google or GitHub for more"; | |
| const entities = [ | |
| { type: "text_link", offset: 6, length: 6, url: "https://google.com" }, | |
| { type: "text_link", offset: 16, length: 6, url: "https://github.com" }, | |
| ]; | |
| expect(expandTextLinks(text, entities)).toBe( | |
| "Visit [Google](https://google.com) or [GitHub](https://github.com) for more", | |
| ); | |
| }); | |
| it("handles adjacent text_link entities", () => { | |
| const text = "AB"; | |
| const entities = [ | |
| { type: "text_link", offset: 0, length: 1, url: "https://a.example" }, | |
| { type: "text_link", offset: 1, length: 1, url: "https://b.example" }, | |
| ]; | |
| expect(expandTextLinks(text, entities)).toBe("[A](https://a.example)[B](https://b.example)"); | |
| }); | |
| it("preserves offsets from the original string", () => { | |
| const text = " Hello world"; | |
| const entities = [{ type: "text_link", offset: 1, length: 5, url: "https://example.com" }]; | |
| expect(expandTextLinks(text, entities)).toBe(" [Hello](https://example.com) world"); | |
| }); | |
| }); | |