'Анна Петровна',
'your-tel' => '+79031234567',
'your-email' => 'anna@mail.ru',
'your-message' => 'Нужна сиделка для бабушки',
];
$classification = Classifier::classify($fields, ['reason' => 'Akismet']);
$result = MessageFormatter::build([
'fields' => $fields,
'classification' => $classification,
'site_title' => 'вашаняня.рф',
'form_title' => 'Обратная связь',
'submitted_at' => '17.04.2026 19:45',
'reason' => 'Akismet',
'ip' => '185.15.56.12',
'user_agent' => 'Mozilla/5.0',
'is_retro' => false,
]);
self::assertIsArray($result);
self::assertArrayHasKey('text', $result);
self::assertArrayHasKey('reply_markup', $result);
self::assertStringContainsString('🟢 похоже клиент', $result['text']);
self::assertStringContainsString('вашаняня.рф', $result['text']);
self::assertStringContainsString('Анна Петровна', $result['text']);
self::assertStringContainsString('+7 (903) 123-45-67', $result['text']);
self::assertStringContainsString('anna@mail.ru', $result['text']);
self::assertStringContainsString('Akismet', $result['text']);
}
public function test_reply_markup_is_null_because_tg_rejects_tel_urls(): void
{
// Telegram Bot API rejects tel: URLs in inline_keyboard with
// HTTP 400 "Wrong port number specified in the URL". We no longer
// emit any inline button; the phone number is rendered in the
// message body instead and mobile TG clients auto-linkify it.
$fields = ['your-tel' => '+79031234567', 'your-name' => 'Анна'];
$classification = Classifier::classify($fields, ['reason' => 'Akismet']);
$r = MessageFormatter::build([
'fields' => $fields, 'classification' => $classification,
'site_title' => 's.ru', 'form_title' => 'f',
'submitted_at' => '17.04.2026', 'reason' => 'Akismet',
'ip' => '', 'user_agent' => '', 'is_retro' => false,
]);
self::assertNull($r['reply_markup']);
// Phone must still be present in the text, formatted as Russian pretty.
self::assertStringContainsString('+7 (903) 123-45-67', $r['text']);
}
public function test_no_tel_button_when_no_phone(): void
{
$fields = ['your-email' => 'a@b.com'];
$classification = Classifier::classify($fields, ['reason' => 'Akismet']);
$r = MessageFormatter::build([
'fields' => $fields, 'classification' => $classification,
'site_title' => 's.ru', 'form_title' => 'f',
'submitted_at' => '17.04.2026', 'reason' => 'Akismet',
'ip' => '', 'user_agent' => '', 'is_retro' => false,
]);
self::assertNull($r['reply_markup']);
}
public function test_html_injection_in_name_is_escaped(): void
{
$fields = ['your-name' => '', 'your-tel' => '+79031234567'];
$classification = Classifier::classify($fields, ['reason' => 'Akismet']);
$r = MessageFormatter::build([
'fields' => $fields, 'classification' => $classification,
'site_title' => 's.ru', 'form_title' => 'f',
'submitted_at' => '17.04.2026', 'reason' => 'Akismet',
'ip' => '', 'user_agent' => '', 'is_retro' => false,
]);
self::assertStringNotContainsString('