54 lines
2.5 KiB
TypeScript
54 lines
2.5 KiB
TypeScript
import { expect, test } from "bun:test";
|
|
import { readFileSync } from "node:fs";
|
|
import { Window } from "happy-dom";
|
|
|
|
test("MFA uses the nested Select and restores continuation after hydration 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 = `<section data-auth-mfa-challenge data-mfa-initial-method="totp">
|
|
<form data-auth-mfa-form>
|
|
<input type="hidden" name="mfaToken">
|
|
<input type="hidden" name="challengeId">
|
|
<div data-auth-mfa-method><select name="method"><option value="totp">Authenticator app</option><option value="email-otp">Email</option></select></div>
|
|
<input name="code"><p data-auth-mfa-status></p><button type="submit">Verify</button>
|
|
</form><a data-auth-mfa-restart hidden href="/login">Back to sign in</a>
|
|
</section>`;
|
|
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<HTMLInputElement>('[name="mfaToken"]')!;
|
|
expect(token.value).toBe("synthetic-test-challenge");
|
|
expect(form.querySelector<HTMLOptionElement>('option[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<HTMLElement>("[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();
|
|
}
|
|
});
|