Initial Commit
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user