Stage 16: connector test-env via UseTestEnvironment; pin it in the test contour
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 10s
CI / ui (pull_request) Successful in 20s
CI / deploy (pull_request) Successful in 30s

- bot.New now selects Telegram's test environment with the library's native
  tgbot.UseTestEnvironment() instead of a token += "/test" hack (functionally
  identical URL /bot<token>/test/METHOD, but idiomatic) + a bot test asserting
  the getMe path for both test and prod.
- ci.yaml pins TELEGRAM_TEST_ENV=true for the test contour (it IS the test
  environment) instead of a TEST_TELEGRAM_TEST_ENV variable: removes the
  confusing double-TEST, telegram-specific, prefixed operator knob and the
  secret-vs-variable footgun. Prod (Stage 17) leaves it false.
- deploy/README.md + PLAN.md updated.
This commit is contained in:
Ilia Denisov
2026-06-05 16:44:10 +02:00
parent ee8d4fd85e
commit 0ea35fe991
5 changed files with 43 additions and 10 deletions
+5 -8
View File
@@ -43,21 +43,18 @@ func New(cfg Config, log *zap.Logger) (*Bot, error) {
}
t := &Bot{miniAppURL: cfg.MiniAppURL, log: log}
token := cfg.Token
if cfg.TestEnv {
// The Bot API test environment lives under /bot<token>/test/METHOD; the
// client builds <host>/bot<token>/<method>, so suffixing the token with
// "/test" injects the test segment without a custom host.
token += "/test"
}
opts := []tgbot.Option{
tgbot.WithDefaultHandler(t.handleStart),
tgbot.WithMessageTextHandler("/start", tgbot.MatchTypePrefix, t.handleStart),
}
if cfg.TestEnv {
// Route to the Bot API test environment (.../bot<token>/test/METHOD).
opts = append(opts, tgbot.UseTestEnvironment())
}
if cfg.APIBaseURL != "" {
opts = append(opts, tgbot.WithServerURL(cfg.APIBaseURL))
}
api, err := tgbot.New(token, opts...)
api, err := tgbot.New(cfg.Token, opts...)
if err != nil {
return nil, err
}
@@ -75,6 +75,34 @@ func TestSendTextHasNoMarkup(t *testing.T) {
}
}
// getMePathFor captures the path bot.New's getMe call hits for the given TestEnv,
// so the test environment routing is covered (a misroute is exactly what makes a
// test-environment token fail with "getMe unauthorized").
func getMePathFor(t *testing.T, testEnv bool) string {
t.Helper()
var path string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if strings.HasSuffix(r.URL.Path, "/getMe") {
path = r.URL.Path
}
io.WriteString(w, `{"ok":true,"result":{"id":1,"is_bot":true,"first_name":"t","username":"tb"}}`)
}))
t.Cleanup(srv.Close)
if _, err := New(Config{Token: "123:ABC", APIBaseURL: srv.URL, TestEnv: testEnv, MiniAppURL: "https://example.com/"}, zap.NewNop()); err != nil {
t.Fatalf("new bot (testEnv=%v): %v", testEnv, err)
}
return path
}
func TestTestEnvironmentRoutesGetMe(t *testing.T) {
if got, want := getMePathFor(t, true), "/bot123:ABC/test/getMe"; got != want {
t.Errorf("TestEnv getMe path = %q, want %q", got, want)
}
if got, want := getMePathFor(t, false), "/bot123:ABC/getMe"; got != want {
t.Errorf("prod getMe path = %q, want %q", got, want)
}
}
func TestStartPayload(t *testing.T) {
cases := map[string]string{
"/start g123": "g123",