/** * Regression tests for Telegram settings menu helpers * Exercises settings text/markup, callback mutations, stale-message fallback, and runtime wiring */ import assert from "node:assert/strict"; import test from "node:test"; import { buildProactivePushSettingsReplyMarkup, buildProactivePushSettingsText, buildAssistantRenderingSettingsReplyMarkup, buildAssistantRenderingSettingsText, buildDraftPreviewsSettingsReplyMarkup, buildDraftPreviewsSettingsText, buildTelegramSettingsMenuReplyMarkup, buildTelegramSettingsMenuText, buildTimeInjectionModeSettingsReplyMarkup, buildVoiceReplyModeSettingsReplyMarkup, createTelegramSettingsMenuRuntime, handleTelegramSettingsMenuCallbackAction, } from "../lib/menu-settings.ts"; test("Settings menu text and reply markup expose built-in controls", () => { assert.equal(buildTelegramSettingsMenuText(), "โš™๏ธ Settings:"); const markup = buildTelegramSettingsMenuReplyMarkup( true, false, "manual", "hidden", undefined, false, ); assert.deepEqual( markup.inline_keyboard.map((row) => row[0]?.callback_data), [ "menu:back", "settings:open:voice-reply", "settings:open:time-injection", "settings:open:draft-previews", "settings:open:assistant-rendering", "settings:open:proactive", ], ); assert.equal(markup.inline_keyboard[1]?.[0]?.text, "๐Ÿ‘„ Voice reply: hidden"); assert.equal( markup.inline_keyboard[2]?.[0]?.text, "๐Ÿ•’ Time injection: hidden", ); assert.equal(markup.inline_keyboard[3]?.[0]?.text, "๐Ÿ“ Draft previews: off"); assert.equal(markup.inline_keyboard[4]?.[0]?.text, "๐Ÿงพ Rendering: rich"); assert.equal(markup.inline_keyboard[5]?.[0]?.text, "๐Ÿ“Œ Proactive push: on"); }); test("Settings detail markups show active values", () => { assert.match(buildProactivePushSettingsText(true), /on<\/code>/); assert.match(buildDraftPreviewsSettingsText(false), /off<\/code>/); assert.equal( buildDraftPreviewsSettingsReplyMarkup(true).inline_keyboard[1]?.[0]?.text, "๐ŸŸข On", ); assert.match(buildAssistantRenderingSettingsText("html"), /html<\/code>/); assert.equal( buildAssistantRenderingSettingsReplyMarkup("rich").inline_keyboard[1]?.[0] ?.text, "๐ŸŸข rich", ); assert.equal( buildProactivePushSettingsReplyMarkup(false).inline_keyboard[1]?.[1]?.text, "๐ŸŸก Off", ); assert.equal( buildTimeInjectionModeSettingsReplyMarkup("interval") .inline_keyboard[3]?.[0]?.text, "๐ŸŸข interval", ); assert.equal( buildVoiceReplyModeSettingsReplyMarkup("mirror", true) .inline_keyboard[3]?.[0]?.text, "๐ŸŸข mirror", ); assert.equal( buildVoiceReplyModeSettingsReplyMarkup("manual", false) .inline_keyboard[1]?.[0]?.text, "๐ŸŸข hidden", ); }); test("Settings callback action mutates voice, time, and proactive settings", async () => { const calls: string[] = []; const deps = { isProactivePushEnabled: () => false, getVoiceReplyMode: () => "manual" as const, isVoiceReplyModeConfigured: () => true, getTimeInjectionMode: () => "hidden" as const, areDraftPreviewsEnabled: () => false, getAssistantRenderingMode: () => "rich" as const, setProactivePushEnabled: async (enabled: boolean) => { calls.push(`proactive:${enabled}`); }, setDraftPreviewsEnabled: async (enabled: boolean) => { calls.push(`draft-previews:${enabled}`); }, setAssistantRenderingMode: async (mode: "rich" | "html") => { calls.push(`rendering:${mode}`); }, setVoiceReplyMode: async ( mode: "manual" | "mirror" | "always" | undefined, ) => { calls.push(`voice:${mode ?? "hidden"}`); }, setTimeInjectionMode: async (mode: "hidden" | "always" | "interval") => { calls.push(`time:${mode}`); }, updateSettingsMessage: async (text: string) => { calls.push(`update:${text.split("\n")[0]}`); }, answerCallbackQuery: async (_id: string, text?: string) => { calls.push(`answer:${text ?? ""}`); }, }; assert.equal( await handleTelegramSettingsMenuCallbackAction( "q1", "settings:set:voice-reply:hidden", deps, ), true, ); assert.equal( await handleTelegramSettingsMenuCallbackAction( "q2", "settings:set:time:off", deps, ), true, ); assert.equal( await handleTelegramSettingsMenuCallbackAction( "q3", "settings:set:draft-previews:on", deps, ), true, ); assert.equal( await handleTelegramSettingsMenuCallbackAction( "q4", "settings:set:assistant-rendering:html", deps, ), true, ); assert.equal( await handleTelegramSettingsMenuCallbackAction( "q5", "settings:set:proactive:on", deps, ), true, ); assert.equal( await handleTelegramSettingsMenuCallbackAction("q6", "other", deps), false, ); assert.deepEqual(calls, [ "voice:hidden", "update:๐Ÿ‘„ Voice reply mode: manual", "answer:Voice reply mode: hidden", "time:hidden", "update:๐Ÿ•’ Time injection mode: hidden", "answer:Time injection: hidden", "draft-previews:true", "update:๐Ÿ“ Draft previews: off", "answer:Draft previews enabled", "rendering:html", "update:๐Ÿงพ Assistant rendering: rich", "answer:Rendering: html", "proactive:true", "update:๐Ÿ“Œ Proactive push: off", "answer:Proactive push enabled", ]); }); test("Settings runtime opens menus and applies stale-message fallback toggles", async () => { const state: any = { chatId: 1, messageId: 2, mode: "status", page: 0, scope: "all", scopedModels: [], allModels: [], }; const calls: string[] = []; const runtime = createTelegramSettingsMenuRuntime({ isProactivePushEnabled: () => true, getVoiceReplyMode: () => "manual", isVoiceReplyModeConfigured: () => true, getTimeInjectionMode: () => "hidden", areDraftPreviewsEnabled: () => false, getAssistantRenderingMode: () => "rich", setProactivePushEnabled: async (enabled) => { calls.push(`proactive:${enabled}`); }, setDraftPreviewsEnabled: async (enabled) => { calls.push(`draft-previews:${enabled}`); }, setAssistantRenderingMode: async (mode) => { calls.push(`rendering:${mode}`); }, setVoiceReplyMode: async (mode) => { calls.push(`voice:${mode ?? "hidden"}`); }, setTimeInjectionMode: async (mode) => { calls.push(`time:${mode}`); }, getModelMenuState: async () => state, getStoredModelMenuState: () => undefined, storeModelMenuState: (nextState) => calls.push(`store:${nextState.mode}`), editInteractiveMessage: async () => { calls.push("edit"); }, sendInteractiveMessage: async (_chatId, _text, mode) => { calls.push(`send:${mode}`); return 99; }, answerCallbackQuery: async (_id, text) => { calls.push(`answer:${text ?? ""}`); }, }); await runtime.openSettingsMenu(1, 2, "ctx"); assert.equal(state.messageId, 99); assert.equal(state.mode, "settings"); assert.equal( await runtime.handleCallbackQuery( { id: "q1", data: "settings:set:voice-reply:always" }, "ctx", ), true, ); assert.equal( await runtime.handleCallbackQuery( { id: "q2", data: "settings:set:time:off" }, "ctx", ), true, ); assert.deepEqual(calls, [ "send:html", "store:settings", "voice:always", "answer:Voice reply mode: always", "time:hidden", "answer:Time injection: hidden", ]); });