69 lines
3.0 KiB
TypeScript
69 lines
3.0 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { readdirSync, readFileSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
|
|
const directory = join(import.meta.dir, "..", "components");
|
|
|
|
test("all authentication components use theme tokens and Tailwind utilities", () => {
|
|
const files = readdirSync(directory).filter((file) => file.endsWith(".wrn"));
|
|
expect(files.length).toBeGreaterThanOrEqual(16);
|
|
for (const file of files) {
|
|
const source = readFileSync(join(directory, file), "utf8");
|
|
expect(source).toContain("component ");
|
|
expect(source).toContain("--wire-");
|
|
expect(source).not.toContain("<style");
|
|
}
|
|
});
|
|
|
|
test("passkey component declares the automatic package runtime", () => {
|
|
const source = readFileSync(join(directory, "PasskeyButton.wrn"), "utf8");
|
|
expect(source).toContain('data-wrnexus-runtime="auth"');
|
|
expect(source).not.toContain("<script");
|
|
});
|
|
|
|
test("SignIn exposes a slot for CAPTCHA and application-specific controls", () => {
|
|
const source = readFileSync(join(directory, "SignIn.wrn"), "utf8");
|
|
expect(source).toContain("<slot></slot>");
|
|
expect(source.indexOf("<slot></slot>")).toBeLessThan(source.indexOf('data-error="_form"'));
|
|
});
|
|
|
|
test("packaged auth forms use built-in schemas instead of native browser validation", () => {
|
|
const files = readdirSync(directory).filter((file) => file.endsWith(".wrn"));
|
|
for (const file of files) {
|
|
const source = readFileSync(join(directory, file), "utf8");
|
|
if (!source.includes("<form")) continue;
|
|
expect(source).not.toContain(" required");
|
|
for (const form of source.matchAll(/<form[\s\S]*?>/g)) {
|
|
if (!form[0].includes("data-schema")) continue;
|
|
expect(form[0]).toContain("novalidate");
|
|
}
|
|
}
|
|
});
|
|
|
|
test("passwordless and passkey components preserve MFA continuation metadata", () => {
|
|
const otp = readFileSync(join(directory, "OtpSignIn.wrn"), "utf8");
|
|
const passkey = readFileSync(join(directory, "PasskeyButton.wrn"), "utf8");
|
|
const signIn = readFileSync(join(directory, "SignIn.wrn"), "utf8");
|
|
expect(otp).toContain("data-mfa-href");
|
|
expect(passkey).toContain("data-mfa-href");
|
|
expect(signIn).toContain("mfaHref='{mfaHref}'");
|
|
expect(signIn).toContain('name="deviceFingerprint"');
|
|
expect(signIn).toContain('name="deviceName"');
|
|
});
|
|
|
|
test("verification components can resend without application-owned schema files", () => {
|
|
const email = readFileSync(join(directory, "VerifyEmail.wrn"), "utf8");
|
|
const phone = readFileSync(join(directory, "VerifyPhone.wrn"), "utf8");
|
|
for (const source of [email, phone]) {
|
|
expect(source).toContain('name="identifier"');
|
|
expect(source).toContain("auth-verification-request");
|
|
expect(source).toContain("novalidate");
|
|
}
|
|
});
|
|
|
|
test("auth browser runtime refuses cross-origin navigation targets", () => {
|
|
const source = readFileSync(join(directory, "..", "assets", "client", "auth.js"), "utf8");
|
|
expect(source).toContain("if (url.origin !== location.origin) return false");
|
|
expect(source).toContain("!window.AbortController");
|
|
});
|