Files
miti99bot/internal/testutil/recording_bot_test.go
T
tiennm99 765cce549d test(handlers): integration tests + recording bot + emulator on CI
Phase 5 of the 2026-05-09 review remediation plan. Closes the
handler-layer test gap (5 modules at 0% coverage in the audit) and
ends the storage-package's CI t.Skip on Firestore emulator tests.

- internal/testutil: Update fixture builders (NewPrivateMessage,
  NewGroupMessage, NewSupergroupMessage, NewChannelMessage) plus a
  RecordingBot that wraps the real go-telegram/bot.Bot with an
  httptest server. The bot library hits the test server instead of
  Telegram; multipart form fields are captured per call. Tests assert
  on Sent() / LastSent() / AssertSentText().
- Handler tests added: misc (4), util (7), wordle (10), loldle (9),
  loldleemoji (8). Cover happy paths, error paths, auth gates,
  group-vs-private subject keying, KV side effects.
- Coverage 44.7% -> 69.8% (verified via -coverprofile). All packages
  now report coverage in CI output.
- CI: ci.yml installs cloud-firestore-emulator beta component and
  starts it on localhost:8090 before go test. Sets
  FIRESTORE_EMULATOR_HOST + GOOGLE_CLOUD_PROJECT env so the storage
  package's emulator-gated tests execute instead of skipping.

go test -race -count=1 ./... clean across all 15 packages locally.
2026-05-09 16:19:38 +07:00

79 lines
1.8 KiB
Go

package testutil
import (
"context"
"testing"
"github.com/go-telegram/bot"
)
// Smoke test: the recording bot must capture an outbound SendMessage so
// downstream handler tests can rely on Sent() / AssertSentText.
func TestRecordingBot_CapturesSendMessage(t *testing.T) {
rb := NewRecordingBot(t)
_, err := rb.Bot.SendMessage(context.Background(), &bot.SendMessageParams{
ChatID: int64(42),
Text: "hello",
})
if err != nil {
t.Fatalf("SendMessage: %v", err)
}
calls := rb.Sent()
if len(calls) != 1 {
t.Fatalf("calls = %d, want 1: %+v", len(calls), calls)
}
if calls[0].Method != "sendMessage" {
t.Errorf("method = %q, want sendMessage", calls[0].Method)
}
if calls[0].Text() != "hello" {
t.Errorf("text = %q, want hello", calls[0].Text())
}
if calls[0].ChatID() != "42" {
t.Errorf("chat_id = %q, want 42", calls[0].ChatID())
}
}
func TestRecordingBot_AssertSentText(t *testing.T) {
rb := NewRecordingBot(t)
_, err := rb.Bot.SendMessage(context.Background(), &bot.SendMessageParams{
ChatID: int64(1),
Text: "Welcome to the bot",
})
if err != nil {
t.Fatal(err)
}
rb.AssertSentText(t, "Welcome")
}
func TestRecordingBot_Reset(t *testing.T) {
rb := NewRecordingBot(t)
_, _ = rb.Bot.SendMessage(context.Background(), &bot.SendMessageParams{
ChatID: int64(1), Text: "first",
})
rb.Reset()
if got := len(rb.Sent()); got != 0 {
t.Errorf("Sent() after Reset = %d, want 0", got)
}
}
func TestUpdateBuilders_BotCommandEntity(t *testing.T) {
tests := []struct {
text string
off int
ln int
}{
{"/wordle", 0, 7},
{"/wordle apple", 0, 7},
{"/wordle@bot apple", 0, 7},
}
for _, tt := range tests {
got := botCommandEntity(tt.text)
if got.Offset != tt.off || got.Length != tt.ln {
t.Errorf("botCommandEntity(%q) = (%d,%d), want (%d,%d)",
tt.text, got.Offset, got.Length, tt.off, tt.ln)
}
}
}