mirror of
https://github.com/tiennm99/miti99bot.git
synced 2026-04-28 10:20:35 +00:00
08ff72985a
Telegram commands /semantle, /semantle_new, /semantle_giveup, /semantle_stats. Round starts with /random pick from hosted word2sim; each guess scored via /similarity. Unlimited guesses; solve on case-insensitive exact match. New env var WORD2SIM_API_URL (wrangler.toml, .env.deploy). Includes module README and 90 unit tests covering api-client, state, format, render, and handlers.
4.3 KiB
4.3 KiB
Phase 3 — Tests & Documentation
Ship-ready polish: unit-test coverage with fake KV + stubbed fetch, module README,
/help integration verification.
Context links
- Overview:
./plan.md - Prior phases:
./phase-01-foundation.md,./phase-02-gameplay.md - Test pattern:
tests/modules/wordle/andtests/modules/trading/(fetch-stubbing examples) - Fakes:
tests/fakes/{fake-kv-namespace,fake-bot,fake-modules}.js
Files to create
tests/modules/semantle/api-client.test.js (~50 LOC)
Stub global.fetch with vi.fn():
- asserts query-string building (rank filters, URL encoding)
- asserts
Word2SimErroron non-2xx - asserts AbortController timeout path (simulate slow upstream)
tests/modules/semantle/state.test.js (~60 LOC)
Using fake-kv-namespace:
- load/save round-trip preserves shape
- clearGame removes entry
- recordResult increments played/solved/totalGuesses correctly
- bestGuessCount is
min(prev, current)only when solved - loadStats returns defaults when empty
tests/modules/semantle/format.test.js (~25 LOC)
Pure-function coverage:
- formatWarmth signed/rounded
- warmthEmoji buckets boundary cases
tests/modules/semantle/render.test.js (~40 LOC)
- renderBoard empty state renders "round ready" prompt
- renderBoard sorts by similarity desc (verify first row = highest score)
- renderBoard caps to top 15 when >15 guesses
- renderGuess escapes HTML-unsafe chars in the word
tests/modules/semantle/handlers.test.js (~130 LOC)
Integration-ish: fake KV + stubbed client (not real fetch).
- happy path: round start → guess → guess → solve (case-insensitive) → stats updated
- OOV guess: not appended, no state mutation
- _giveup reveals target and clears game
- _new abandons prior round + clears, records non-solve
- error from client surfaces a user-friendly message; state unchanged
- case sensitivity: guess "APPLE" against target "apple" solves the round
Files to create (docs)
src/modules/semantle/README.md
Mirror src/modules/loldle/README.md shape. Sections:
- Commands table (from
plan.md) - Data source — point at
tiennm99/word2simhosted instance - Architecture — list of files and what each does
- Storage — KV layout table (
game:<subject>,stats:<subject>) - Config —
WORD2SIM_API_URLenv var - Credits — word2vec / GoogleNews pretrained vectors
Files to edit
docs/adding-a-module.md
No change expected unless the word2sim env-var pattern is the first of its kind.
If so, add a short note about [vars] config for external API bases.
scripts/register.js
Verify setMyCommands picks up the new public commands automatically (no code
change expected — registry is the source of truth).
Todo
api-client.test.jsstate.test.jsformat.test.jsrender.test.jshandlers.test.jssrc/modules/semantle/README.md- Run
npm test— all pass - Run
npm run lint && npm run format— clean npm run register:dry— confirms/semantle,/semantle_giveup,/semantle_new,/semantle_statsappear in the command payload- Optional:
docs/adding-a-module.mdone-paragraph addition if env-var pattern is novel
Success criteria
- Test coverage for all new files (>80% line coverage, pragmatic thresholds).
- No biome/eslint warnings (project enforces 100-char line width, sorted imports, trailing commas).
npm run register:dryoutput includes all public/semantle*commands.src/modules/semantle/README.mdparallel to loldle's in shape and depth.
Risk
- Fetch stub drift — if word2sim adds fields, tests may not catch breaking response-shape changes in prod. Mitigation: add a single optional integration test (guarded by env flag) that hits the real URL; skip by default.
- Flaky timing tests — avoid real
setTimeoutin the AbortController test; usevi.useFakeTimers()if needed.
Security
- Tests must not commit real TELEGRAM tokens or call Telegram.
.dev.varsis gitignored; never add secrets to.dev.vars.example.
Next
- Deploy via
npm run deploy(handles webhook + setMyCommands). - Monitor the first day of usage via CF Worker logs; look for upstream errors.
- Potential follow-ups (separate plans):
- Daily shared secret (Semantle-classic mode)
- Leaderboard module integration
- Webhook-side warm-up cron to keep word2sim hot