Skip to content

test: cover the grammy wiring by dispatching real Updates through createBot - #313

Merged
chiliec merged 1 commit into
mainfrom
test/bot-wiring
Sep 9, 2026
Merged

test: cover the grammy wiring by dispatching real Updates through createBot#313
chiliec merged 1 commit into
mainfrom
test/bot-wiring

Conversation

@chiliec

@chiliec chiliec commented Sep 9, 2026

Copy link
Copy Markdown
Member

Closes the coverage gap flagged during the #312 dependency batch.

The hole

Every existing bot test drives a composer with a hand-rolled context stub. None of them touch grammy itself — not UpdateContext construction, not the plugin chain (session/hydrate/i18n/autoChatAction), not command routing. So a grammy or @grammyjs/types bump can break the real wiring with all 625 tests green. smoke:api can't help either: it runs STAGING=true, which skips Telegram entirely. That's why grammy 1.43 → 1.46 in #312 had to be cleared by hand.

The cover

Boots the real createBot() and pushes real Update objects through it:

  • mongodb-memory-server behind it, because attachUser genuinely hits mongo (it isn't injectable from createBot)
  • botInfo supplied so handleUpdate skips getMe
  • an api transformer answers every outgoing call locally, so the fake token is never presented to Telegram and hydrate() gets a Message-shaped result to wrap

Three cases: /start routed end to end, attachUser upserting a first-contact user into mongo, and an unknown command still reaching a handler.

The assertion is mutation-tested

The obvious version of the /start check — "a sendMessage went out with non-empty text" — passes even with startFeature unwired, because unhandledFeature answers /start too. I found that by actually deleting the protectedBot.use(startFeature) line and watching the test stay green.

It now pins the locale text and the disabled link preview, both unique to buildStartCommandHandler. Re-ran the same mutation: not ok 1, and green again on revert.

Bonus: the types trap became a compile error

BOT_INFO is checked as UserFromGetMe at the call site, so a top-level @grammyjs/types drifting from grammy's bundled copy now fails typecheck in this file — turning on supports_join_request_queries, the same field the trap has always keyed on. Writing that literal out is deliberate, not incidental.

Cost

628 tests (up from 625); suite wall time unchanged at ~7s.

Every existing bot test drives a composer with a hand-rolled context stub,
so none of them touch grammy: not Update -> Context construction, not the
plugin chain (session/hydrate/i18n/autoChatAction), not command routing. A
grammy or @grammyjs/types bump could break the real wiring with all 625
tests green — #312 had to be checked past that hole by hand, and smoke:api
cannot help because STAGING=true skips Telegram entirely.

Boots the real createBot() against mongodb-memory-server, supplies botInfo
so handleUpdate skips getMe, and answers every outgoing call with an api
transformer, so the fake token never reaches Telegram.

The start assertion pins the locale text and the disabled link preview
rather than just 'a reply happened': unhandledFeature answers /start too
when startFeature is unwired, and a bare length check passed that mutation.
Verified it now fails with startFeature removed and passes when restored.

BOT_INFO is checked as UserFromGetMe at the call site, so a top-level
@grammyjs/types that drifts from grammy's bundled copy fails typecheck here
— the same field (supports_join_request_queries) the trap turns on.
@chiliec
chiliec merged commit d92bb14 into main Sep 9, 2026
3 checks passed
@chiliec
chiliec deleted the test/bot-wiring branch September 9, 2026 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant