import { describe, expect, it } from "vitest"; import { z } from "zod"; import { routes, type RouteDef } from "../src/index"; const entries = Object.entries(routes) as [string, RouteDef][]; describe("route catalog", () => { it("lists every base-game endpoint", () => { expect(Object.keys(routes).sort()).toEqual( [ "getServerTime", "createGuest", "getPlayerState", "getContractBoard", "getTutorialBoard", "createDispatch", "buyShip", "leaseBay", "hirePilot", "assignPilot", "unassignPilot", "restPilot", "startUpgrade", "spendSkillPoint", "acknowledgeSummaries", "acceptDeal", "getBackupCode", "createBackupCode", "restoreCompany", "devAdvanceClock", "devAddCredits", "devPilot", "devShip", "devDiscoverAll", "newCompany", "renameCompany", "repayLoan", "claimGoal", ].sort(), ); }); it.each(entries)("%s has request and response schemas", (_name, route) => { expect(route.request).toBeInstanceOf(z.ZodType); expect(route.response).toBeInstanceOf(z.ZodType); }); it("never gives two endpoints the same method and path", () => { const keys = entries.map(([, r]) => `${r.method} ${r.path}`); expect(new Set(keys).size).toBe(keys.length); }); it("keeps every path under /api", () => { for (const [, route] of entries) { expect(route.path.startsWith("/api/")).toBe(true); } }); it.each(entries)("%s declares each path parameter in its request schema", (_name, route) => { const params = [...route.path.matchAll(/:(\w+)/g)].map((m) => m[1]!); if (params.length === 0) return; expect(route.request).toBeInstanceOf(z.ZodObject); const shape = (route.request as z.ZodObject).shape; for (const param of params) { expect(shape).toHaveProperty(param); } }); it("requires a session everywhere except server time, guest creation and restore", () => { const open = entries.filter(([, r]) => !r.auth).map(([name]) => name); // Restoring signs a device in, so it runs without a session (CR-011). expect(open.sort()).toEqual(["createGuest", "getServerTime", "restoreCompany"]); }); });