import { describe, expect, it } from "@suaveplan/testing/runner"; import type { Auth } from "better-auth"; import { flushTestMetrics } from "../../tests/setup/polyfills.js"; import { resetAuthInstruments } from "../otel/instruments.js"; import { buildAuthRoutes } from "./build-routes.js"; function makeAuthStub(status = 200): Auth { return { handler: async () => new Response(JSON.stringify({ ok: true }), { status, headers: { "content-type": "application/json" }, }), } as unknown as Auth; } describe("buildAuthRoutes", () => { it("returns 9 route entries", { timeout: 5000 }, () => { const entries = buildAuthRoutes(makeAuthStub()); expect(entries).toHaveLength(9); }); it("every route has typed body/query/response", { timeout: 5000, }, () => { const entries = buildAuthRoutes(makeAuthStub()); for (const { route } of entries) { expect(typeof route.method).toBe("string"); expect(typeof route.path).toBe("string"); // responses[200] schema exists const ok = ( route.responses as Record< string | number, { content?: { "application/json"?: { schema: unknown } }; } > )["200"]; expect(ok?.content?.["application/json"]?.schema).toBeDefined(); } }); it("POST routes carry a body schema", { timeout: 5000 }, () => { const entries = buildAuthRoutes(makeAuthStub()); const bodyRoutes = [ "/sign-up", "/sign-in", "/forgot-password", "/reset-password", "/verify-email", ]; for (const path of bodyRoutes) { const entry = entries.find((e) => e.route.path === path); expect(entry).toBeDefined(); const req = entry?.route.request as | { body?: { content?: { "application/json"?: unknown } } } | undefined; expect(req?.body?.content?.["application/json"]).toBeDefined(); } }); it("OAuth routes carry params + query schemas", { timeout: 5000 }, () => { const entries = buildAuthRoutes(makeAuthStub()); const callback = entries.find( (e) => e.route.path === "/oauth/{provider}/callback" ); const req = callback?.route.request as | { params?: unknown; query?: unknown } | undefined; expect(req?.params).toBeDefined(); expect(req?.query).toBeDefined(); }); it("sign-up handler emits signups_total counter on success", { timeout: 10_000, }, async () => { resetAuthInstruments(); const entries = buildAuthRoutes(makeAuthStub(200)); const signUp = entries.find((e) => e.route.path === "/sign-up"); const res = await signUp!.handler({ req: { raw: new Request("http://x.test/sign-up") }, } as never); expect(res).toBeInstanceOf(Response); const metrics = await flushTestMetrics(); const names = metrics .flatMap((m) => m.scopeMetrics) .flatMap((s) => s.metrics) .map((m) => m.descriptor.name); expect(names).toContain("auth.signups_total"); }); it("sign-up handler skips signups counter on non-2xx", { timeout: 10_000, }, async () => { resetAuthInstruments(); const entries = buildAuthRoutes(makeAuthStub(400)); const signUp = entries.find((e) => e.route.path === "/sign-up"); const res = await signUp!.handler({ req: { raw: new Request("http://x.test/sign-up") }, } as never); expect(res).toBeInstanceOf(Response); }); it("sign-in handler emits failure outcome on non-2xx", { timeout: 10_000, }, async () => { resetAuthInstruments(); const entries = buildAuthRoutes(makeAuthStub(401)); const signIn = entries.find((e) => e.route.path === "/sign-in"); const res = await signIn!.handler({ req: { raw: new Request("http://x.test/sign-in") }, } as never); expect(res.status).toBe(401); const metrics = await flushTestMetrics(); const names = metrics .flatMap((m) => m.scopeMetrics) .flatMap((s) => s.metrics) .map((m) => m.descriptor.name); expect(names).toContain("auth.signins_total"); }); it("session handler delegates to auth.handler", { timeout: 5000, }, async () => { const entries = buildAuthRoutes(makeAuthStub(200)); const session = entries.find((e) => e.route.path === "/session"); const res = await session!.handler({ req: { raw: new Request("http://x.test/session") }, } as never); expect(res.status).toBe(200); }); it("sign-in handler emits success outcome on 2xx", { timeout: 10_000, }, async () => { resetAuthInstruments(); const entries = buildAuthRoutes(makeAuthStub(200)); const signIn = entries.find((e) => e.route.path === "/sign-in"); const res = await signIn!.handler({ req: { raw: new Request("http://x.test/sign-in") }, } as never); expect(res.status).toBe(200); }); });