import { expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { Window, type HTMLInputElement, type HTMLElement } from "happy-dom";
test("selecting delivery radios sends once, ignores stale responses, and never sends for local methods", async () => {
const window = new Window({ url: "https://sso.example.test/mfa" });
try {
window.sessionStorage.setItem(
"wrnexus.auth.mfa",
JSON.stringify({ mfaToken: "synthetic-test-challenge" }),
);
window.document.body.innerHTML = ``;
const requests: Array<{ method: string; resolve: (response: Response) => void }> = [];
window.fetch = ((_: unknown, init: RequestInit) =>
new Promise((resolve) => {
requests.push({ method: JSON.parse(String(init.body)).method, resolve });
})) as any;
window.eval(readFileSync(new URL("../assets/client/auth.js", import.meta.url), "utf8"));
(window as any).WRNexusAuth.mount(window.document);
const form = window.document.querySelector("form")!;
const field = (name: string) => form.querySelector(`[name=${name}]`)!;
const choose = (value: string) => {
const radio = form.querySelector(`[name=method][value="${value}"]`)!;
radio.checked = true;
radio.dispatchEvent(new window.Event("change", { bubbles: true }));
};
choose("recovery-code");
expect(requests).toHaveLength(0);
field("recoveryCode").value = "abc123-def456";
form.dispatchEvent(new window.Event("submit", { bubbles: true, cancelable: true }));
expect(field("code").value).toBe("abc123-def456");
choose("email-otp");
choose("email-otp");
expect(requests.map((x) => x.method)).toEqual(["email-otp"]);
choose("sms-otp");
expect(requests.map((x) => x.method)).toEqual(["email-otp", "sms-otp"]);
requests[0]!.resolve(Response.json({ id: "email-challenge" }));
await new Promise((resolve) => setTimeout(resolve, 0));
expect(field("challengeId").value).toBe("");
requests[1]!.resolve(Response.json({ id: "sms-challenge" }));
await new Promise((resolve) => setTimeout(resolve, 0));
expect(field("challengeId").value).toBe("sms-challenge");
choose("totp");
expect(field("challengeId").value).toBe("");
expect(requests).toHaveLength(2);
field("otpCode").value = "123456";
form.dispatchEvent(new window.Event("submit", { bubbles: true, cancelable: true }));
expect(field("code").value).toBe("123456");
} finally {
await window.happyDOM.close();
}
});
test("MFA radios preserve allowed methods and restore continuation without reviving expired challenges", async () => {
const window = new Window({ url: "https://sso.example.test/mfa" });
try {
window.sessionStorage.setItem(
"wrnexus.auth.mfa",
JSON.stringify({
mfaToken: "synthetic-test-challenge",
requires: { mfa: ["totp"] },
}),
);
window.document.body.innerHTML = ``;
window.eval(readFileSync(new URL("../assets/client/auth.js", import.meta.url), "utf8"));
(window as any).WRNexusAuth.mount(window.document);
const form = window.document.querySelector("form")!;
const token = form.querySelector('[name="mfaToken"]')!;
expect(token.value).toBe("synthetic-test-challenge");
expect(form.querySelector('input[value="email-otp"]')!.disabled).toBe(true);
token.value = ""; // Hydration reapplies the component's initial empty prop.
form.dispatchEvent(new window.Event("submit", { bubbles: true, cancelable: true }));
expect(token.value).toBe("synthetic-test-challenge");
form.dispatchEvent(
new window.CustomEvent("wrn:error", { bubbles: true, detail: { code: "mfa-invalid" } }),
);
expect(token.value).toBe("synthetic-test-challenge");
form.dispatchEvent(
new window.CustomEvent("wrn:error", {
bubbles: true,
detail: { code: "mfa-transaction-expired" },
}),
);
expect(window.sessionStorage.getItem("wrnexus.auth.mfa")).toBeNull();
expect(window.document.querySelector("[data-auth-mfa-restart]")!.hidden).toBe(
false,
);
const retry = new window.Event("submit", { bubbles: true, cancelable: true });
form.dispatchEvent(retry);
expect(retry.defaultPrevented).toBe(true);
expect(token.value).toBe("");
} finally {
await window.happyDOM.close();
}
});