Анкета: телефон обязателен, кнопка «Отправить мой номер»
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
2da10169b8
commit
7fdabd07a4
6 files changed
+91
-23
No files matched your search
@@ -0,0 +1,25 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { HttpTelegram, REMOVE_KEYBOARD } from './client.ts';
|
||||
|
||||
/** Что ушло в Bot API в поле reply_markup. */
|
||||
const sentMarkup = async (keyboard: Parameters<HttpTelegram['sendMessage']>[2]) => {
|
||||
let body: { reply_markup?: unknown } = {};
|
||||
const fetchFn = (async (_url: string, init: { body: string }) => {
|
||||
body = JSON.parse(init.body);
|
||||
return new Response(JSON.stringify({ ok: true, result: { message_id: 1 } }));
|
||||
}) as unknown as typeof fetch;
|
||||
await new HttpTelegram('t', fetchFn).sendMessage(1, 'x', keyboard);
|
||||
return body.reply_markup;
|
||||
};
|
||||
|
||||
describe('клавиатуры Bot API', () => {
|
||||
it('кнопки под сообщением, «поделиться номером» и её удаление', async () => {
|
||||
expect(await sentMarkup([[{ text: 'Да', callback: 'yes' }, { text: 'Сайт', url: 'https://x.am' }]])).toEqual({
|
||||
inline_keyboard: [[{ text: 'Да', callback_data: 'yes' }, { text: 'Сайт', url: 'https://x.am' }]],
|
||||
});
|
||||
expect(await sentMarkup([[{ text: 'Отправить мой номер', requestContact: true }]])).toEqual({
|
||||
keyboard: [[{ text: 'Отправить мой номер', request_contact: true }]], resize_keyboard: true, one_time_keyboard: true,
|
||||
});
|
||||
expect(await sentMarkup(REMOVE_KEYBOARD)).toEqual({ remove_keyboard: true });
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,14 @@
|
||||
/** Кнопка под сообщением: callback — нажатие обрабатывает бот; url — ссылка; webApp — открыть Mini App. */
|
||||
export type Button = { text: string } & ({ callback: string } | { url: string } | { webApp: string });
|
||||
/**
|
||||
* Кнопка под сообщением: callback — нажатие обрабатывает бот; url — ссылка; webApp — открыть Mini App.
|
||||
* requestContact — кнопка внизу экрана «поделиться номером» (обычная клавиатура, не под сообщением);
|
||||
* removeKeyboard — убрать такую клавиатуру.
|
||||
*/
|
||||
export type Button = { text: string } & ({ callback: string } | { url: string } | { webApp: string } | { requestContact: true } | { removeKeyboard: true });
|
||||
export type Keyboard = Button[][];
|
||||
|
||||
/** Клавиатура, которая убирает кнопку «поделиться номером». */
|
||||
export const REMOVE_KEYBOARD: Keyboard = [[{ text: '', removeKeyboard: true }]];
|
||||
|
||||
export interface SentMessage {
|
||||
chatId: number;
|
||||
messageId: number;
|
||||
@@ -58,17 +65,30 @@ export interface TelegramApi {
|
||||
getUpdates(offset: number, timeoutSec: number): Promise<TgUpdate[]>;
|
||||
}
|
||||
|
||||
const markup = (keyboard?: Keyboard) => ({
|
||||
inline_keyboard: (keyboard ?? []).map((row) =>
|
||||
row.map((b) =>
|
||||
'callback' in b
|
||||
? { text: b.text, callback_data: b.callback }
|
||||
: 'url' in b
|
||||
? { text: b.text, url: b.url }
|
||||
: { text: b.text, web_app: { url: b.webApp } },
|
||||
const markup = (keyboard?: Keyboard) => {
|
||||
const buttons = (keyboard ?? []).flat();
|
||||
if (buttons.some((b) => 'removeKeyboard' in b)) return { remove_keyboard: true };
|
||||
if (buttons.some((b) => 'requestContact' in b)) {
|
||||
return {
|
||||
keyboard: (keyboard ?? []).map((row) => row.map((b) => ({ text: b.text, ...('requestContact' in b ? { request_contact: true } : {}) }))),
|
||||
resize_keyboard: true,
|
||||
one_time_keyboard: true,
|
||||
};
|
||||
}
|
||||
return {
|
||||
inline_keyboard: (keyboard ?? []).map((row) =>
|
||||
row.flatMap((b): Record<string, unknown>[] =>
|
||||
'callback' in b
|
||||
? [{ text: b.text, callback_data: b.callback }]
|
||||
: 'url' in b
|
||||
? [{ text: b.text, url: b.url }]
|
||||
: 'webApp' in b
|
||||
? [{ text: b.text, web_app: { url: b.webApp } }]
|
||||
: [],
|
||||
),
|
||||
),
|
||||
),
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export class HttpTelegram implements TelegramApi {
|
||||
constructor(
|
||||
|
||||
Reference in new issue
Block a user