// Tests for the signup-first join page's pure decision helpers (prejoin.js). import test from "node:test"; import assert from "node:assert/strict"; import { PREJOIN_STASH_KEY, offerPrejoin, prejoinStash, readPrejoinReturn, homeSigninURL, autoEnrolOnClaim, } from "../web/static/prejoin.js"; const HOME = "https://home.example.com"; const base = { kind: "join", homeOrigin: HOME, embed: false, native: false, signedUp: false }; test("offerPrejoin: fresh join/setup kinds with a home server", () => { assert.equal(offerPrejoin(base), true); assert.equal(offerPrejoin({ ...base, kind: "setup" }), true); }); test("offerPrejoin: never for established or unsupported contexts", () => { for (const kind of ["device", "adopt", "adopt-admin"]) { assert.equal(offerPrejoin({ ...base, kind }), false); } assert.equal(offerPrejoin({ ...base, homeOrigin: "" }), false); assert.equal(offerPrejoin({ ...base, homeOrigin: "__HOME_ORIGIN__" }), false); assert.equal(offerPrejoin({ ...base, embed: true }), false); assert.equal(offerPrejoin({ ...base, native: true }), false); assert.equal(offerPrejoin({ ...base, signedUp: true }), false); }); // The create-a-space journey: home hands over /join/setup?src=home moments // after a sign-in there (and having already saved the space to that account). // Leading with the sign-in door again reads as the flow forgetting. test("offerPrejoin: a setup link from a signed-in home page never leads with sign-in", () => { assert.equal(offerPrejoin({ ...base, kind: "setup", fromHome: true }), false); assert.equal(offerPrejoin({ ...base, kind: "join", fromHome: true }), false); assert.equal(offerPrejoin({ ...base, kind: "setup", fromHome: false }), true); }); // One sign-in per space: an arrival that already signed in on the way here // enrols itself at claim time, so nothing asks again later. test("autoEnrolOnClaim: the two already-signed-in arrivals, and nobody else", () => { const at = { homeOrigin: HOME, embed: false }; assert.equal(autoEnrolOnClaim({ ...at, signedUp: true }), true); assert.equal(autoEnrolOnClaim({ ...at, fromHome: true }), true); assert.equal(autoEnrolOnClaim({ ...at }), false, "a cold joiner still meets the ask"); assert.equal(autoEnrolOnClaim({ ...at, fromHome: true, embed: true }), false); assert.equal(autoEnrolOnClaim({ signedUp: true, fromHome: true, homeOrigin: "", embed: false }), false); assert.equal(autoEnrolOnClaim({ signedUp: true, homeOrigin: "__HOME_ORIGIN__", embed: false }), false); }); test("round trip: stash then read back on a genuine return", () => { const now = 1_000_000; const stored = prejoinStash({ frag: "e1.SECRET~Ann~bkey", nonce: "n0nce", now }); const r = readPrejoinReturn({ search: "?su=n0nce", storedJSON: stored, now: now + 5000 }); assert.deepEqual(r, { signedUp: true, frag: "e1.SECRET~Ann~bkey" }); }); test("readPrejoinReturn: no marker, forged nonce, stale stash, clock skew", () => { const now = 1_000_000; const stored = prejoinStash({ frag: "f", nonce: "good", now }); assert.deepEqual(readPrejoinReturn({ search: "", storedJSON: stored, now }), { signedUp: false, frag: "" }); assert.deepEqual(readPrejoinReturn({ search: "?su=evil", storedJSON: stored, now }), { signedUp: false, frag: "" }); assert.deepEqual(readPrejoinReturn({ search: "?su=good", storedJSON: stored, now: now + 61 * 60 * 1000 }), { signedUp: false, frag: "" }); assert.deepEqual(readPrejoinReturn({ search: "?su=good", storedJSON: stored, now: now - 1000 }), { signedUp: false, frag: "" }); assert.deepEqual(readPrejoinReturn({ search: "?su=good", storedJSON: "not json", now }), { signedUp: false, frag: "" }); assert.deepEqual(readPrejoinReturn({ search: "?su=good", storedJSON: "", now }), { signedUp: false, frag: "" }); }); test("homeSigninURL: return URL rides the fragment, encoded, no invite secret", () => { const url = homeSigninURL(HOME, "https://chat.example.com", "/join/abc", "n+once"); assert.equal(url, HOME + "/#joinret=" + encodeURIComponent("https://chat.example.com/join/abc?su=" + encodeURIComponent("n+once"))); assert.equal(homeSigninURL(HOME + "/", "https://c.example.com", "/join/x", "n"), HOME + "/#joinret=" + encodeURIComponent("https://c.example.com/join/x?su=n")); }); test("stash key is stable", () => assert.equal(PREJOIN_STASH_KEY, "lchat_prejoin"));