deadhead-space-freight-tycoon/packages/schema/test/routes.test.ts

65 lines
1.9 KiB
TypeScript

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",
"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 and guest creation", () => {
const open = entries.filter(([, r]) => !r.auth).map(([name]) => name);
expect(open.sort()).toEqual(["createGuest", "getServerTime"]);
});
});