test(auth): restore plugin engine-hook coverage via invokeAuthHandler
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,45 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import type { Context } from "@wrnexus/core";
|
||||
import { createPluginRunner } from "@wrnexus/plugin";
|
||||
import { authPlugin } from "../src/plugin.ts";
|
||||
import { AUTH_ROUTE_DEFINITIONS } from "../src/routes/definitions.ts";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { createAuthEngine } from "../src/engine.ts";
|
||||
import { MemoryAuthStore } from "../src/stores/memory.ts";
|
||||
import { invokeAuthHandler } from "../src/routes/api.ts";
|
||||
|
||||
function routeContext(request: Request): Context {
|
||||
const values = new Map<string, unknown>();
|
||||
return {
|
||||
req: request,
|
||||
url: new URL(request.url),
|
||||
params: {},
|
||||
locals: {},
|
||||
lang: "en",
|
||||
t: (key: string) => key,
|
||||
ip: "127.0.0.1",
|
||||
user: null,
|
||||
cookies: {
|
||||
get: (name: string) => (name === "wrn-csrf" ? "plugin-test-csrf-token" : undefined),
|
||||
} as Context["cookies"],
|
||||
localStorage: {} as Context["localStorage"],
|
||||
session: {
|
||||
id: () => "plugin-test-session",
|
||||
get: <T>(key: string) => values.get(key) as T | undefined,
|
||||
getAll: () => Object.fromEntries(values),
|
||||
set: (key: string, value: unknown) => {
|
||||
values.set(key, value);
|
||||
},
|
||||
delete: (key: string) => {
|
||||
values.delete(key);
|
||||
},
|
||||
regenerate: () => {},
|
||||
clear: () => {
|
||||
values.clear();
|
||||
},
|
||||
},
|
||||
} as Context;
|
||||
}
|
||||
|
||||
test("plugin contributes components, runtime, styles, migration, and toolbar", async () => {
|
||||
const metadata = new Map<string, unknown>();
|
||||
@@ -69,6 +106,71 @@ test("config.auth controls route groups and migrations without explicit plugin o
|
||||
expect(contributions.routes.some((route) => route.path === "/api/auth/login")).toBe(true);
|
||||
});
|
||||
|
||||
test("a hook set on config.auth.engine fires when a request goes through the route layer", async () => {
|
||||
const calls: string[] = [];
|
||||
const engine = createAuthEngine({
|
||||
store: new MemoryAuthStore(),
|
||||
secret: "plugin-navigation-hooks-secret-longer-than-thirty-two-characters",
|
||||
onSignedIn(ctx, returnTo) {
|
||||
calls.push(`in:${returnTo}`);
|
||||
return Response.redirect(new URL(returnTo ?? "/account", ctx.url), 303);
|
||||
},
|
||||
onSignedOut(ctx) {
|
||||
calls.push("out");
|
||||
return Response.redirect(new URL("/sign-in", ctx.url), 303);
|
||||
},
|
||||
});
|
||||
await engine.register({
|
||||
email: "plugin-navigation@example.com",
|
||||
password: "StrongPassword123",
|
||||
});
|
||||
|
||||
const runner = createPluginRunner(authPlugin(), {
|
||||
root: process.cwd(),
|
||||
mode: "development",
|
||||
command: "dev",
|
||||
metadata: new Map(),
|
||||
warn() {},
|
||||
});
|
||||
|
||||
await runner.configure({
|
||||
auth: { engine, routes: true },
|
||||
});
|
||||
|
||||
const loginResponse = await invokeAuthHandler(
|
||||
"login",
|
||||
routeContext(
|
||||
new Request("https://example.test/api/auth/login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
"x-csrf-token": "plugin-test-csrf-token",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
identifier: "plugin-navigation@example.com",
|
||||
password: "StrongPassword123",
|
||||
returnTo: "/dashboard",
|
||||
}),
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(loginResponse.status).toBe(303);
|
||||
expect(loginResponse.headers.get("location")).toBe("https://example.test/dashboard");
|
||||
|
||||
const logoutResponse = await invokeAuthHandler(
|
||||
"logout",
|
||||
routeContext(
|
||||
new Request("https://example.test/api/auth/logout", {
|
||||
method: "POST",
|
||||
headers: { "x-csrf-token": "plugin-test-csrf-token" },
|
||||
}),
|
||||
),
|
||||
);
|
||||
expect(logoutResponse.status).toBe(303);
|
||||
expect(logoutResponse.headers.get("location")).toBe("https://example.test/sign-in");
|
||||
expect(calls).toEqual(["in:/dashboard", "out"]);
|
||||
});
|
||||
|
||||
test("auth runtime contains built-in browser schemas", async () => {
|
||||
const metadata = new Map<string, unknown>();
|
||||
const runner = createPluginRunner(authPlugin({ includeMigrations: false }), {
|
||||
|
||||
Reference in New Issue
Block a user