Something went wrong. Try again.
Web frontend and supporting services for lance.blue
Something went wrong. Try again.
3.7 kB · 116 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117/** * The signed-out-visitor splash's stash: carrying "#lobby/<id>" across the * OAuth redirect the same way camo/editor.ts carries an in-progress camo. * * Real code against a fake localStorage, the same shape lobby-client.test.mjs * uses for WebSocket - this is genuine logic (peek without consuming, then * consume once), not the source-regex kind the rest of the lobby screens get * (see lobby-screen.test.mjs's own doc for why those stay structural). * * Run with `npm test`. */import { test, beforeEach } from "node:test";import assert from "node:assert/strict";import { readFile } from "node:fs/promises";import { fileURLToPath } from "node:url";
class MemoryStorage { constructor() { this.store = new Map(); } getItem(key) { return this.store.has(key) ? this.store.get(key) : null; } setItem(key, value) { this.store.set(key, String(value)); } removeItem(key) { this.store.delete(key); }}globalThis.localStorage = new MemoryStorage();
const { hasPendingLobbyInvite, stashLobbyInvite, takePendingLobbyInvite } = await import("../src/lobby-invite-stash.ts");
beforeEach(() => { globalThis.localStorage.store.clear();});
test("nothing is pending before anything stashes", () => { assert.equal(hasPendingLobbyInvite(), false); assert.equal(takePendingLobbyInvite(), null);});
test("stashing makes it pending, and peeking does not consume it", () => { stashLobbyInvite("lobby-1"); assert.equal(hasPendingLobbyInvite(), true); assert.equal( hasPendingLobbyInvite(), true, "a peek must not consume the stash", );});
test("taking returns the stashed id exactly once", () => { stashLobbyInvite("lobby-1"); assert.equal(takePendingLobbyInvite(), "lobby-1"); assert.equal(hasPendingLobbyInvite(), false, "the stash was not cleared"); assert.equal( takePendingLobbyInvite(), null, "a second take must find nothing", );});
test("a later stash simply replaces an earlier, un-taken one", () => { stashLobbyInvite("lobby-1"); stashLobbyInvite("lobby-2"); assert.equal(takePendingLobbyInvite(), "lobby-2");});
test("a storage failure is swallowed, not thrown", () => { const real = globalThis.localStorage; globalThis.localStorage = { getItem() { throw new Error("blocked"); }, setItem() { throw new Error("blocked"); }, removeItem() { throw new Error("blocked"); }, }; try { assert.doesNotThrow(() => stashLobbyInvite("lobby-1")); assert.equal(hasPendingLobbyInvite(), false); assert.equal(takePendingLobbyInvite(), null); } finally { globalThis.localStorage = real; }});
// --- the splash screen's wiring (structural - see this file's own doc) ---
const web = fileURLToPath(new URL("../", import.meta.url));const source = await readFile(`${web}src/screens/lobby-invite.ts`, "utf8");
test("lobbyInviteScreen stashes the id it was given, right before the redirect", () => { assert.match( source, /onBeforeConnect:\s*\(\)\s*=>\s*stashLobbyInvite\(matchId\)/, "the splash's sign-in form no longer stashes matchId before the OAuth redirect", );});
// The splash's headline was guarded here as a placeholder — CLAUDE.md keeps// prominent prose a human's to write, and the check failed the moment the// words read like real copy. They do now, so the guard has done its job and// is gone: kept, it would fail on every build for the rest of the project's// life, and a test that fails because the work it was waiting for arrived is// not a test any more.//// Nothing replaces it. There is no assertion to make about a sentence a human// chose, and the placeholder rule is about who writes the words rather than// about what they say.