115 lines
4.1 KiB
TypeScript
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;
|
|
}
|
|
});
|