eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1// Tests for the WebAuthn ceremony-error copy mapping, run in Node.
2// Same harness style as home/test/serverlist.test.mjs.
3// node home/test/ceremony-errors.test.mjs
4import assert from "node:assert/strict";
5import { friendlyCeremonyError, formatCeremonyError } from "../web/static/ceremony-errors.js";
6
7let failures = 0;
8async function test(name, fn) {
9 try {
10 await fn();
11 console.log("PASS " + name);
12 } catch (e) {
13 console.log("FAIL " + name + " — " + (e && e.message));
14 failures++;
15 }
16}
17
18// A ceremony error as the browser throws it: name is a DOMException name,
19// phase is the tag backup-core.js attaches on the register path.
20const errWith = (name, phase) => Object.assign(new Error("boom"), { name, phase });
21
22await test("cancelled sign-in reads as a cancel, not an exception", () => {
23 const { message, detail } = friendlyCeremonyError(errWith("NotAllowedError"), "signin");
24 assert.equal(message, "Sign in was cancelled. If you didn't cancel, try again.");
25 assert.equal(detail, "NotAllowedError");
26});
27
28await test("cancelled create names the create intent", () => {
29 const { message } = friendlyCeremonyError(errWith("NotAllowedError"), "create");
30 assert.equal(message, "Creating your sign-in was cancelled. If you didn't cancel, try again.");
31});
32
33await test("duplicate registration bridges back to sign-in", () => {
34 const { message } = friendlyCeremonyError(errWith("InvalidStateError"), "create");
35 assert.equal(message, "That's already set up. Try signing in instead.");
36});
37
38await test("InvalidStateError during sign-in falls through to the raw message", () => {
39 const { message } = friendlyCeremonyError(errWith("InvalidStateError"), "signin");
40 assert.equal(message, "boom"); // no create-specific reading applies
41});
42
43await test("no screen lock: ConstraintError and NotSupportedError both explain it", () => {
44 for (const name of ["ConstraintError", "NotSupportedError"]) {
45 const { message } = friendlyCeremonyError(errWith(name), "signin");
46 assert.equal(message,
47 "This device needs a screen lock, PIN, fingerprint, or face unlock before it can sign in this way.");
48 }
49});
50
51await test("misconfigured RP reads as a site problem", () => {
52 const { message } = friendlyCeremonyError(errWith("SecurityError"), "signin");
53 assert.equal(message, "Sign-in isn't configured for this website address.");
54});
55
56await test("aborted ceremony asks for a retry", () => {
57 const { message } = friendlyCeremonyError(errWith("AbortError"), "signin");
58 assert.equal(message, "Sign-in was interrupted. Try again.");
59});
60
61await test("phase rides along in the detail for debugging", () => {
62 const { detail } = friendlyCeremonyError(errWith("NotAllowedError", "create"), "create");
63 assert.equal(detail, "NotAllowedError [create]");
64});
65
66await test("unknown errors pass their own message through", () => {
67 const { message, detail } = friendlyCeremonyError(new Error("HTTP 500"), "signin");
68 assert.equal(message, "HTTP 500");
69 assert.equal(detail, "Error");
70});
71
72await test("a nameless, messageless value still renders something", () => {
73 const { message, detail } = friendlyCeremonyError({}, "signin");
74 assert.equal(message, "[object Object]");
75 assert.equal(detail, "Error");
76});
77
78await test("formatCeremonyError composes sentence + parenthesised detail", () => {
79 const line = formatCeremonyError(errWith("NotAllowedError", "create"), "create");
80 assert.equal(line,
81 "Creating your sign-in was cancelled. If you didn't cancel, try again. (NotAllowedError [create])");
82});
83
84if (failures) {
85 console.error(failures + " test(s) failed");
86 process.exit(1);
87}
88console.log("ceremony-errors tests passed");
89