Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 1 addition & 35 deletions src/__tests__/bot-commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,6 @@ describe("parseCommand", () => {
it("rejects /launch without slug", () => {
expect(parseCommand("/launch").tag).toBe("launch-missing");
});
it("parses /lang without arg as lang-help", () => {
expect(parseCommand("/lang")).toEqual({ tag: "lang-help" });
});
it("parses /lang en", () => {
expect(parseCommand("/lang en")).toEqual({ tag: "lang-set", locale: "en" });
});
it("parses /lang ru", () => {
expect(parseCommand("/lang ru")).toEqual({ tag: "lang-set", locale: "ru" });
});
it("parses unknown /lang code as lang-invalid", () => {
expect(parseCommand("/lang de")).toEqual({ tag: "lang-invalid", arg: "de" });
});
it("parses /getToken", () => {
expect(parseCommand("/getToken")).toEqual({ tag: "get-token" });
});
Expand All @@ -50,28 +38,8 @@ describe("parseCommand", () => {
});

describe("bot messages", () => {
it("createdMessage (ru) includes bootstrap steps without links", () => {
const message = createdMessage(
"ru",
"demo-app",
"npx @spawn-dock/create --token pair_demo",
);

expect(message).toContain("Проект demo-app создан.");
expect(message).toContain("1. Запусти bootstrap-команду локально:");
expect(message).toContain("npx @spawn-dock/create --token pair_demo");
expect(message).toContain("Эту команду можно запускать повторно для этого проекта.");
expect(message).toContain("2. После bootstrap запусти:");
expect(message).toContain("pnpm run dev");
expect(message).not.toContain("Preview URL:");
expect(message).not.toContain("Telegram Link:");
expect(message).not.toContain("TMA URL:");
expect(message).not.toContain("Ссылки:");
});

it("createdMessage (en) uses English bootstrap copy", () => {
it("createdMessage uses English bootstrap copy", () => {
const message = createdMessage(
"en",
"demo-app",
"npx @spawn-dock/create --token pair_demo",
);
Expand All @@ -86,7 +54,6 @@ describe("bot messages", () => {

it("includes TMA, preview, and telegram links in launchMessage", () => {
const message = launchMessage(
"en",
"demo-app",
"connected",
"https://example.com/tma?tgWebAppStartParam=demo-app",
Expand All @@ -103,7 +70,6 @@ describe("bot messages", () => {

it("previewReadyMessage keeps all links", () => {
const message = previewReadyMessage(
"ru",
"demo-app",
"https://example.com/preview/demo-app",
"https://t.me/rustgpt_bot/tma?startapp=demo-app",
Expand Down
4 changes: 3 additions & 1 deletion src/__tests__/bot-telegram.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ describe("setMyCommands", () => {
for (const cmd of body.commands) {
expect(cmd.command).toMatch(/^[a-z0-9_]+$/);
}
expect(body.commands.map((c) => c.command)).toContain("gettoken");
const commandNames = body.commands.map((c) => c.command);
expect(commandNames).toContain("gettoken");
expect(commandNames).not.toContain("lang");
});
});
1 change: 0 additions & 1 deletion src/__tests__/mcp-auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const state: StoreState = {
revokedAt: null,
}],
tunnelSessions: [],
userLocales: {},
};

describe("readMcpApiKey", () => {
Expand Down
39 changes: 4 additions & 35 deletions src/__tests__/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ process.env.TELEGRAM_MINI_APP_SHORT_NAME ??= "tma";

function createRuntime(): Runtime {
return {
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [], userLocales: {} },
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [] },
connectionsBySlug: new Map(),
pendingResponses: new Map(),
};
Expand All @@ -49,7 +49,6 @@ function createAuthorizedRuntime(): Runtime {
revokedAt: null,
}],
tunnelSessions: [],
userLocales: {},
},
};
}
Expand All @@ -59,7 +58,7 @@ const authorizedHeaders = {
};

const mockRuntime: Runtime = {
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [], userLocales: {} },
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [] },
connectionsBySlug: new Map(),
pendingResponses: new Map(),
};
Expand Down Expand Up @@ -116,7 +115,7 @@ describe("Express server", () => {

it("POST /v1/bootstrap/claim returns flat bootstrap fields", async () => {
const app = createApp({
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [], userLocales: {} },
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [] },
connectionsBySlug: new Map(),
pendingResponses: new Map(),
});
Expand Down Expand Up @@ -172,7 +171,7 @@ describe("Express server", () => {

it("POST /v1/bootstrap/claim replays the same credential when the token was already claimed", async () => {
const app = createApp({
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [], userLocales: {} },
state: { projects: [], pairingTokens: [], deviceCredentials: [], tunnelSessions: [] },
connectionsBySlug: new Map(),
pendingResponses: new Map(),
});
Expand Down Expand Up @@ -209,35 +208,6 @@ describe("Express server", () => {
expect(res.body.error).toBe("bot_unauthorized");
});

it("POST /api/bot/user-locale/sync stores locale from Telegram language_code", async () => {
const runtime = createRuntime();
const app = createApp(runtime);

const res = await request(app)
.post("/api/bot/user-locale/sync")
.set(botHeaders)
.send({ ownerTelegramId: 99, telegramLanguageCode: "ru-RU" });

expect(res.status).toBe(200);
expect(res.body.locale).toBe("ru");
expect(runtime.state.userLocales["99"]).toBe("ru");
});

it("POST /api/bot/user-locale/set updates explicit locale", async () => {
const runtime = createRuntime();
runtime.state.userLocales["5"] = "ru";
const app = createApp(runtime);

const res = await request(app)
.post("/api/bot/user-locale/set")
.set(botHeaders)
.send({ ownerTelegramId: 5, locale: "en" });

expect(res.status).toBe(200);
expect(res.body.locale).toBe("en");
expect(runtime.state.userLocales["5"]).toBe("en");
});

it("POST /projects accepts bot-authorized creation without /api prefix", async () => {
const app = createApp(createRuntime());

Expand Down Expand Up @@ -314,7 +284,6 @@ describe("Express server", () => {
pairingTokens: [],
deviceCredentials: [],
tunnelSessions: [],
userLocales: {},
},
connectionsBySlug: new Map(),
pendingResponses: new Map(),
Expand Down
12 changes: 0 additions & 12 deletions src/bot/commands.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
// src/bot/commands.ts
import type { BotLocale } from "../types.js";
import { isBotLocale } from "./user-lang.js";

export type BotCommand =
| { tag: "start" }
| { tag: "help" }
| { tag: "new"; title: string }
| { tag: "launch"; slug: string }
| { tag: "launch-missing" }
| { tag: "lang-help" }
| { tag: "lang-set"; locale: BotLocale }
| { tag: "lang-invalid"; arg: string }
| { tag: "get-token" }
| { tag: "unknown"; input: string };

Expand All @@ -30,12 +24,6 @@ export function parseCommand(input: string): BotCommand {
const text = normalizeTelegramCommandText(input);
if (text === "/start") return { tag: "start" };
if (text === "/help") return { tag: "help" };
if (text.startsWith("/lang")) {
const rest = text.slice(5).trim().toLowerCase();
if (!rest) return { tag: "lang-help" };
if (isBotLocale(rest)) return { tag: "lang-set", locale: rest };
return { tag: "lang-invalid", arg: rest };
}
if (text.startsWith("/new")) {
const title = text.slice(4).trim();
return { tag: "new", title: title || "SpawnDock App" };
Expand Down
Loading