// Tests for the invite-link fragment codec. node test/invite.test.mjs import assert from "node:assert/strict"; import { parseInviteFragment, buildInviteFragment, hasInviteFingerprint, INVITE_PREFIX, } from "../web/static/invite.js"; let failures = 0; async function test(name, fn) { try { await fn(); console.log("PASS " + name); } catch (e) { console.log("FAIL " + name + " — " + (e && e.message)); failures++; } } await test("parse: new format without name", () => { assert.deepEqual(parseInviteFragment("e1.abc123"), { T: "abc123", name: "", b: "" }); }); await test("parse: new format with name", () => { assert.deepEqual(parseInviteFragment("e1.abc123~Paul"), { T: "abc123", name: "Paul", b: "" }); }); await test("parse: legacy unprefixed without name", () => { assert.deepEqual(parseInviteFragment("abc123"), { T: "abc123", name: "", b: "" }); }); await test("parse: legacy unprefixed with name", () => { assert.deepEqual(parseInviteFragment("abc123~Paul"), { T: "abc123", name: "Paul", b: "" }); }); await test("parse: URL-encoded name", () => { assert.deepEqual(parseInviteFragment("e1.abc~Paul%20Campbell"), { T: "abc", name: "Paul Campbell", b: "" }); }); await test("parse: URL-encoded unicode name", () => { assert.deepEqual(parseInviteFragment("e1.abc~Zo%C3%AB%20%E2%9C%A8"), { T: "abc", name: "Zoë ✨", b: "" }); }); await test("parse: undecodable percent sequence -> empty name", () => { assert.deepEqual(parseInviteFragment("e1.abc~%E0%A4%A"), { T: "abc", name: "", b: "" }); }); await test("parse: empty input", () => { assert.deepEqual(parseInviteFragment(""), { T: "", name: "", b: "" }); }); await test("parse: null/undefined input", () => { assert.deepEqual(parseInviteFragment(null), { T: "", name: "", b: "" }); assert.deepEqual(parseInviteFragment(undefined), { T: "", name: "", b: "" }); }); await test("build: carries the fingerprint", () => { assert.equal(buildInviteFragment("abc123"), INVITE_PREFIX + "abc123"); assert.ok(hasInviteFingerprint(buildInviteFragment("abc123", "Paul"))); }); await test("build: round-trips without name", () => { assert.deepEqual(parseInviteFragment(buildInviteFragment("abc123")), { T: "abc123", name: "", b: "" }); }); await test("build: round-trips with name", () => { assert.deepEqual(parseInviteFragment(buildInviteFragment("abc123", "Paul Campbell")), { T: "abc123", name: "Paul Campbell", b: "", }); }); await test("build: round-trips a unicode name (incl. ~ in the name)", () => { // "~" in a name must survive: encodeURIComponent leaves it bare, but the // parser splits on the FIRST tilde, so the separator still wins. assert.deepEqual(parseInviteFragment(buildInviteFragment("T", "Zoë ~ ✨")), { T: "T", name: "Zoë ~ ✨", b: "" }); }); await test("hasInviteFingerprint: new links yes, legacy and junk no", () => { assert.equal(hasInviteFingerprint("e1.abc123"), true); assert.equal(hasInviteFingerprint("abc123"), false); assert.equal(hasInviteFingerprint(""), false); assert.equal(hasInviteFingerprint(null), false); }); await test("branding key: builds the 3-slot form and round-trips", () => { // Sealed instances put the branding key b in every minted link // (docs/no-plaintext.md); the name slot stays, possibly empty. assert.equal(buildInviteFragment("abc123", "", "k3m7p2qx4f"), "e1.abc123~~k3m7p2qx4f"); assert.deepEqual(parseInviteFragment("e1.abc123~~k3m7p2qx4f"), { T: "abc123", name: "", b: "k3m7p2qx4f" }); assert.deepEqual(parseInviteFragment(buildInviteFragment("abc123", "Paul Campbell", "k3m7p2qx4f")), { T: "abc123", name: "Paul Campbell", b: "k3m7p2qx4f", }); }); await test("branding key: old parsers still get T from a 3-slot link", () => { // Slot order is fixed (T first) so a pre-branding parser that cuts at the // first "~" still claims from a new link. const frag = buildInviteFragment("abc123", "Zoë", "k3m7p2qx4f").replace(/^e1\./, ""); assert.equal(frag.split("~")[0], "abc123"); }); await test("branding key: a legacy raw-~ name is not mistaken for a key", () => { // Old builders left "~" unescaped in names. The key slot must match the // base32 shape, so a decorative tail stays part of the name. assert.deepEqual(parseInviteFragment("e1.T~Zo%C3%AB%20~%20%E2%9C%A8"), { T: "T", name: "Zoë ~ ✨", b: "" }); }); await test("branding key: new builders escape ~ so names with ~ round-trip beside b", () => { assert.deepEqual(parseInviteFragment(buildInviteFragment("T", "Zoë ~ ✨", "k3m7p2qx4f")), { T: "T", name: "Zoë ~ ✨", b: "k3m7p2qx4f", }); }); console.log(failures === 0 ? "\nALL PASSED" : `\n${failures} FAILED`); process.exit(failures === 0 ? 0 : 1);