Files
tiennm99 297d8cb00b feat(loldle): tunable max guesses per subject + retuned defaults
Drop classic loldle from 8 → 6 (7-axis grid leaks too much per guess for 8
to feel earned) and emoji from 5 → 4 (3 emojis are usually unmistakable).
Add a hidden /<module>_setmax <n> command per loldle module so a chat can
override its own round length (1-10). Override stored at config:<subject>
in each module's KV; getMaxGuesses() falls back to the default when unset.
2026-05-07 13:52:09 +07:00

56 lines
2.5 KiB
JavaScript

import { beforeEach, describe, expect, it } from "vitest";
import { installDispatcher } from "../../src/modules/dispatcher.js";
import { resetRegistry } from "../../src/modules/registry.js";
import { makeFakeBot } from "../fakes/fake-bot.js";
import { makeFakeKv } from "../fakes/fake-kv-namespace.js";
import { makeCommand, makeFakeImportMap, makeModule } from "../fakes/fake-modules.js";
// The dispatcher imports the registry's default static map at module-load
// time, so to keep the test hermetic we need to stub env.MODULES with names
// that resolve in the REAL map — OR we call buildRegistry directly with an
// injected map and then simulate what installDispatcher does. Since phase-04
// made loadModules accept an importMap injection but installDispatcher
// internally calls buildRegistry WITHOUT an injection, we test the same
// effect by wiring the bot manually against a registry built with a fake map.
//
// Keeping it simple: call installDispatcher against the real module map
// (util + wordle + loldle + misc) so we exercise the actual production path.
describe("installDispatcher", () => {
beforeEach(() => resetRegistry());
it("registers EVERY command via bot.command() regardless of visibility", async () => {
const bot = makeFakeBot();
const env = { MODULES: "util,wordle,loldle,misc", KV: makeFakeKv() };
const reg = await installDispatcher(bot, env);
// Expect 14 total commands (10 public + 1 protected + 3 private —
// the third private is loldle's /loldle_setmax override command).
expect(bot.commandCalls).toHaveLength(14);
expect(reg.allCommands.size).toBe(14);
const registeredNames = bot.commandCalls.map((c) => c.name).sort();
const expected = [...reg.allCommands.keys()].sort();
expect(registeredNames).toEqual(expected);
// Assert private commands ARE registered (the whole point of unified routing).
expect(registeredNames).toContain("fortytwo");
});
it("does NOT install any bot.on() middleware — dispatcher is minimal", async () => {
const bot = makeFakeBot();
const env = { MODULES: "util", KV: makeFakeKv() };
await installDispatcher(bot, env);
expect(bot.onCalls).toHaveLength(0);
});
it("each registered handler matches the source module command handler", async () => {
const bot = makeFakeBot();
const env = { MODULES: "util", KV: makeFakeKv() };
const reg = await installDispatcher(bot, env);
for (const { name, handler } of bot.commandCalls) {
expect(handler).toBe(reg.allCommands.get(name).cmd.handler);
}
});
});