Files
WRNexusJS/packages/auth/test/plugin.test.ts
T
2026-07-29 12:51:10 +05:30

212 lines
6.7 KiB
TypeScript

import { expect, test } from "bun:test";
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 { getDefaultAuthRouteOptions } from "../src/runtime.ts";
test("plugin contributes components, runtime, styles, migration, and toolbar", async () => {
const metadata = new Map<string, unknown>();
const runner = createPluginRunner(
authPlugin({ includeRoutes: true, includeMigrations: true, includeMiddleware: true }),
{
root: process.cwd(),
mode: "development",
command: "dev",
metadata,
warn() {},
},
);
const contributions = await runner.contributions();
expect(contributions.componentDirs).toHaveLength(1);
expect(contributions.clientRuntimes[0]).toMatchObject({ id: "auth", singleton: true });
expect(contributions.styles[0]?.id).toBe("auth-components");
expect(contributions.migrations.map((migration) => migration.id)).toEqual([
"wrnexus-auth-001",
"wrnexus-auth-002-otp-purpose",
]);
expect(contributions.routes.length).toBeGreaterThanOrEqual(30);
expect(contributions.middleware).toHaveLength(1);
});
test("unconfigured automatic discovery fails closed for routes, middleware, and migrations", async () => {
const metadata = new Map<string, unknown>();
const runner = createPluginRunner(authPlugin(), {
root: process.cwd(),
mode: "development",
command: "dev",
metadata,
warn() {},
});
const contributions = await runner.contributions();
expect(contributions.routes).toHaveLength(0);
expect(contributions.middleware).toHaveLength(0);
expect(contributions.migrations).toHaveLength(0);
expect(contributions.componentDirs).toHaveLength(1);
expect(contributions.clientRuntimes).toHaveLength(1);
});
test("config.auth controls route groups and migrations without explicit plugin options", async () => {
const metadata = new Map<string, unknown>();
const runner = createPluginRunner(authPlugin(), {
root: process.cwd(),
mode: "development",
command: "dev",
metadata,
warn() {},
});
await runner.configure({
auth: {
engine: {} as never,
migrations: false,
routes: { enabled: true, registration: false, passkeys: false },
},
});
const contributions = await runner.contributions();
expect(contributions.migrations).toHaveLength(0);
expect(contributions.routes.some((route) => route.path === "/api/auth/register")).toBe(false);
expect(contributions.routes.some((route) => route.path.includes("/passkeys/"))).toBe(false);
expect(contributions.routes.some((route) => route.path === "/api/auth/login")).toBe(true);
});
test("config.auth resolves navigation hooks from the configured engine", async () => {
const onSignedIn = () => new Response(null, { status: 204 });
const onSignedOut = () => new Response(null, { status: 204 });
const runner = createPluginRunner(authPlugin(), {
root: process.cwd(),
mode: "development",
command: "dev",
metadata: new Map(),
warn() {},
});
await runner.configure({
auth: {
engine: { onSignedIn, onSignedOut } as never,
routes: true,
},
});
expect(getDefaultAuthRouteOptions().onSignedIn).toBe(onSignedIn);
expect(getDefaultAuthRouteOptions().onSignedOut).toBe(onSignedOut);
});
test("auth runtime contains built-in browser schemas", async () => {
const metadata = new Map<string, unknown>();
const runner = createPluginRunner(authPlugin({ includeMigrations: false }), {
root: process.cwd(),
mode: "development",
command: "dev",
metadata,
warn() {},
});
const contributions = await runner.contributions();
expect(contributions.clientRuntimes[0]?.source).toContain("auth-password-request");
expect(contributions.clientRuntimes[0]?.source).toContain("auth-register");
});
test("each package auth route uses a route-specific entry module", async () => {
const metadata = new Map<string, unknown>();
const runner = createPluginRunner(
authPlugin({
includeRoutes: true,
includeMigrations: false,
includeMiddleware: false,
}),
{
root: process.cwd(),
mode: "development",
command: "dev",
metadata,
warn() {},
},
);
const contributions = await runner.contributions();
const entries = contributions.routes.map((route) => route.entry);
const passwordRequest = contributions.routes.find(
(route) => route.path === "/api/auth/password/request",
);
expect(new Set(entries).size).toBe(entries.length);
expect(
passwordRequest?.entry.replace(/\\/g, "/").endsWith("/src/routes/api/password-request.ts"),
).toBe(true);
for (const definition of AUTH_ROUTE_DEFINITIONS) {
const route = contributions.routes.find((item) => item.path === definition.path);
expect(route).toBeDefined();
const source = readFileSync(route!.entry, "utf8");
expect(source).toContain(`invokeAuthHandler("${definition.handler}"`);
expect(source.includes("dispatchAuthRoute")).toBe(false);
for (const method of definition.methods) {
expect(source).toContain(`export function ${method}`);
}
}
});
test("config.auth registers package routes", async () => {
const metadata = new Map<string, unknown>();
const runner = createPluginRunner(authPlugin(), {
root: process.cwd(),
mode: "development",
command: "dev",
metadata,
warn() {},
});
await runner.configure({
auth: {
engine: {} as never,
routes: true,
middleware: true,
migrations: false,
},
});
const contributions = await runner.contributions();
expect(contributions.routes.some((route) => route.path === "/api/auth/password/request")).toBe(
true,
);
expect(contributions.routes.some((route) => route.path === "/api/auth/register")).toBe(true);
expect(contributions.routes.some((route) => route.path === "/api/auth/login")).toBe(true);
expect(contributions.middleware).toHaveLength(1);
expect(contributions.migrations).toHaveLength(0);
});
test("config.auth can disable route groups", async () => {
const metadata = new Map<string, unknown>();
const runner = createPluginRunner(authPlugin(), {
root: process.cwd(),
mode: "development",
command: "dev",
metadata,
warn() {},
});
await runner.configure({
auth: {
engine: {} as never,
migrations: false,
routes: {
enabled: true,
password: true,
passkeys: false,
},
},
});
const contributions = await runner.contributions();
expect(contributions.routes.some((route) => route.path === "/api/auth/password/request")).toBe(
true,
);
expect(contributions.routes.some((route) => route.path.includes("/passkeys/"))).toBe(false);
});