114 lines
4.7 KiB
TypeScript
114 lines
4.7 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { existsSync, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
const root = join(import.meta.dir, "..");
|
|
const authPackageRoot = join(root, "..", "..", "packages", "auth");
|
|
|
|
function read(...parts: string[]): string {
|
|
return readFileSync(join(...parts), "utf8");
|
|
}
|
|
|
|
test("auth showcase contains registration, login, recovery, and protected account pages", () => {
|
|
for (const page of [
|
|
"index.wrn",
|
|
"sign-in.wrn",
|
|
"sign-up.wrn",
|
|
"recover.wrn",
|
|
"account.wrn",
|
|
"otp.wrn",
|
|
"magic-link.wrn",
|
|
"two-factor.wrn",
|
|
"authenticator.wrn",
|
|
"invitation.wrn",
|
|
"impersonation.wrn",
|
|
]) {
|
|
expect(existsSync(join(root, "app", "pages", page))).toBe(true);
|
|
}
|
|
|
|
const account = read(root, "app", "pages", "account.wrn");
|
|
const signIn = read(root, "app", "pages", "sign-in.wrn");
|
|
expect(account).toContain("PasskeyButton");
|
|
expect(account).toContain("AccountStatus");
|
|
expect(account).toContain('action="/api/auth/logout"');
|
|
expect(account).toContain('data-schema="auth-empty"');
|
|
expect(signIn).toContain("<Captcha");
|
|
expect(signIn).toContain('action="auth-login"');
|
|
expect(signIn).toContain('required="true"');
|
|
expect(signIn).toContain('resetOnError="false"');
|
|
expect(existsSync(join(root, "app", "middleware", "captcha-login.ts"))).toBe(true);
|
|
expect(existsSync(join(root, "app", "api", "captcha", "[...path].ts"))).toBe(true);
|
|
expect(read(root, "app", "middleware", "captcha-login.ts")).toContain(
|
|
"verifiedForMs: 5 * 60_000",
|
|
);
|
|
});
|
|
|
|
test("auth showcase uses package-owned routes and advanced components", () => {
|
|
const auth = read(root, "app", "lib", "auth.ts");
|
|
const config = read(root, "wrnexus.config.ts");
|
|
|
|
expect(auth).toContain("createAuthEngine");
|
|
expect(auth).toContain("onSignedIn");
|
|
expect(auth).toContain("onSignedOut");
|
|
expect(auth).toContain("onSuccessfulSignUp");
|
|
expect(auth).toContain("autoSignIn: true");
|
|
expect(config).toContain("engine: auth");
|
|
expect(config).toContain("routes: true");
|
|
expect(config).toContain("migrations: false");
|
|
expect(config).not.toContain("onSignedIn");
|
|
expect(config).not.toContain("onSignedOut");
|
|
|
|
expect(existsSync(join(root, "app", "api", "auth", "register.ts"))).toBe(false);
|
|
expect(existsSync(join(root, "app", "schemas", "auth-register.ts"))).toBe(false);
|
|
|
|
expect(read(root, "app", "pages", "otp.wrn")).toContain("OtpSignIn");
|
|
expect(read(root, "app", "pages", "magic-link.wrn")).toContain("MagicLinkSignIn");
|
|
expect(read(root, "app", "pages", "impersonation.wrn")).toContain("ImpersonationBanner");
|
|
});
|
|
|
|
test("package auth schemas are shared by browser forms and API handlers", () => {
|
|
const validation = read(authPackageRoot, "src", "validation.ts");
|
|
const plugin = read(authPackageRoot, "src", "plugin.ts");
|
|
const handlers = read(authPackageRoot, "src", "http", "index.ts");
|
|
const signUp = read(authPackageRoot, "components", "SignUp.wrn");
|
|
const forgotPassword = read(authPackageRoot, "components", "ForgotPassword.wrn");
|
|
|
|
expect(validation).toContain("export const signUpSchema");
|
|
expect(validation).toContain("export const authSchemas");
|
|
expect(validation).toContain("export const authBrowserSchemaMap");
|
|
|
|
expect(plugin).toContain("authBrowserSchemaDescriptors");
|
|
expect(plugin).toContain("setDefaultAuthEngine(value.engine)");
|
|
|
|
expect(handlers).toContain("parseBody(schemas.register, ctx.req)");
|
|
expect(handlers).toContain("parseBody(schemas.passwordResetRequest, ctx.req)");
|
|
|
|
expect(signUp).toContain('schema = "auth-register"');
|
|
expect(signUp).toContain("data-schema='{schema}'");
|
|
expect(signUp).toContain("novalidate");
|
|
|
|
expect(forgotPassword).toContain('schema = "auth-password-request"');
|
|
expect(forgotPassword).toContain("data-schema='{schema}'");
|
|
expect(forgotPassword).toContain("novalidate");
|
|
});
|
|
|
|
test("authz is connected with a real declaration and a registered middleware, not a dangling file", () => {
|
|
expect(existsSync(join(root, "app", "authz", "showcase.ts"))).toBe(true);
|
|
expect(existsSync(join(root, "app", "middleware", "authz.ts"))).toBe(true);
|
|
|
|
const declaration = read(root, "app", "authz", "showcase.ts");
|
|
expect(declaration).toContain("defineAuthz");
|
|
expect(declaration).toContain('"post:read": { title: "View posts", public: true }');
|
|
expect(declaration).toContain("bindings:");
|
|
|
|
const middleware = read(root, "app", "middleware", "authz.ts");
|
|
expect(middleware).toContain("authzMiddleware");
|
|
expect(middleware).toContain("getAuthzCatalog()");
|
|
expect(middleware).toContain("memoryPermissionStore()");
|
|
|
|
const manifest = JSON.parse(read(root, "package.json")) as {
|
|
dependencies?: Record<string, string>;
|
|
};
|
|
expect(manifest.dependencies?.["@wrnexus/authz"]).toBe("workspace:*");
|
|
});
|