auth-yes/src/tests/smoke_test.ts

115 lines
4.1 KiB
TypeScript

import { assertEquals, assertStringIncludes } from "jsr:@std/assert@1";
import app from "../main.ts";
import { auditWrapper } from "../core/audit.ts";
Deno.test("[Smoke Test] Core Server Routing & Hypermedia Endpoints", async () => {
const origAudit = auditWrapper.auditLog;
auditWrapper.auditLog = () => {};
try {
// 1. Health check
const resHealth = await app.fetch(new Request("http://localhost/healthz"));
assertEquals(resHealth.status, 200);
assertEquals(await resHealth.text(), "OK");
// 2. Root / redirects to /login
const resRoot = await app.fetch(new Request("http://localhost/"));
assertEquals(resRoot.status, 302);
assertEquals(resRoot.headers.get("location"), "/login");
// 3. /dashboard redirects to /dashboard/sessions
const resDashRoot = await app.fetch(
new Request("http://localhost/dashboard"),
);
assertEquals(resDashRoot.status, 302);
assertEquals(resDashRoot.headers.get("location"), "/dashboard/sessions");
// 4. /logout redirects to /login
const resLogout = await app.fetch(new Request("http://localhost/logout"));
assertEquals(resLogout.status, 302);
assertEquals(resLogout.headers.get("location"), "/login");
// 5. Public Login page returns HTML with card wrapper
const resLogin = await app.fetch(new Request("http://localhost/login"));
assertEquals(resLogin.status, 200);
assertEquals(
resLogin.headers.get("content-type")?.includes("text/html"),
true,
);
const loginHtml = await resLogin.text();
assertStringIncludes(loginHtml, "auth-layout-wrapper");
assertStringIncludes(loginHtml, "auth-card");
assertStringIncludes(loginHtml, "auth-client.js");
// 6. Public Register page returns HTML with card wrapper
const resRegister = await app.fetch(
new Request("http://localhost/register"),
);
assertEquals(resRegister.status, 200);
assertEquals(
resRegister.headers.get("content-type")?.includes("text/html"),
true,
);
const registerHtml = await resRegister.text();
assertStringIncludes(registerHtml, "auth-layout-wrapper");
assertStringIncludes(registerHtml, "auth-card");
// 7. Public Join page returns HTML with card wrapper
const resJoin = await app.fetch(new Request("http://localhost/join"));
assertEquals(resJoin.status, 200);
assertEquals(
resJoin.headers.get("content-type")?.includes("text/html"),
true,
);
const joinHtml = await resJoin.text();
assertStringIncludes(joinHtml, "auth-layout-wrapper");
assertStringIncludes(joinHtml, "auth-card");
// 8. Static assets are served with HTTP 200
const resAuthClient = await app.fetch(
new Request("http://localhost/public/auth-client.js"),
);
assertEquals(resAuthClient.status, 200);
assertStringIncludes(
await resAuthClient.text(),
"startWebAuthnLogin",
);
const resLoginScript = await app.fetch(
new Request("http://localhost/public/webauthn-login.js"),
);
assertEquals(resLoginScript.status, 200);
// 9. Unauthenticated Dashboard redirects to /login
const resDash = await app.fetch(
new Request("http://localhost/dashboard/sessions"),
);
assertEquals(resDash.status, 302);
assertEquals(resDash.headers.get("location")?.includes("/login"), true);
// 10. Magic Link Pass without token redirects to /login
const resPass = await app.fetch(new Request("http://localhost/pass"));
assertEquals(resPass.status, 302);
assertEquals(
resPass.headers.get("location")?.includes(
"/login?error=invalid_or_expired_pass",
),
true,
);
// 11. Forward Auth check without host returns 400
const resForwardAuth = await app.fetch(
new Request("http://localhost/api/forward-auth"),
);
assertEquals(resForwardAuth.status, 400);
// 12. Admin route unauthenticated redirects or denies
const resAdmin = await app.fetch(
new Request("http://localhost/admin/users"),
);
assertEquals(resAdmin.status === 302 || resAdmin.status === 401, true);
} finally {
auditWrapper.auditLog = origAudit;
}
});