my-sea voice: persist the call across in-sea reloads via auto-rejoin; pngquant the RWS card back — TDD
Voice-persistence follow-up (user-spec item 6). Every my-sea navigation is a full page reload that kills the WebSocket + peer connections; true no-reload nav would need an SPA refactor of the heavily-tested draw IIFEs. Instead we auto-rejoin: bindVoiceBtn remembers the active room in sessionStorage on join and silently re-joins it on the next my-sea page if voice is still available there (mic permission persists for the session, so no prompt). Same user- visible result (a brief reconnect, not seamless) with no risk to the draw flows. - burger-btn.js: sessionStorage 'mysea-voice-room' remember/forget helpers + window.mySeaVoiceForget; bindVoiceBtn refactored to startCall()/withVoiceRoom() and auto-rejoins on bind when the remembered room === the active btn's room. A failed join (e.g. INSECURE_CONTEXT) forgets the room so it doesn't retry. - _my_sea_gear.html: the NVM-disconnect guard confirm + BYE forget the room (and leave the mesh) — an explicit leave shouldn't auto-rejoin. - BurgerSpec: +4 auto-rejoin specs (match / different-sea / inactive / remember + forget). 438 Jasmine specs green. Also (bundled, user's parallel work): pngquant the resaved RWS deck card back (tarot-rider-waite-smith-back.png) from 733KB truecolor+a to a 264KB 8-bit palette PNG, matching its companion card faces. Dimensions preserved (the rotated 401x694). Code architected by Disco DeDisco <discodedisco@outlook.com> Git commit message Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -249,3 +249,57 @@ describe("Burger", () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Voice persistence across my_sea reloads — bindVoiceBtn remembers the active
|
||||
// room in sessionStorage + silently re-joins it on the next page if voice is
|
||||
// still available (2026-05-29).
|
||||
describe("voice auto-rejoin", () => {
|
||||
let vbtn, origVR, joinSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
try { sessionStorage.removeItem("mysea-voice-room"); } catch (e) {}
|
||||
vbtn = document.createElement("button");
|
||||
vbtn.id = "id_voice_btn";
|
||||
vbtn.classList.add("active");
|
||||
vbtn.setAttribute("data-room-id", "mysea-abc");
|
||||
document.body.appendChild(vbtn);
|
||||
origVR = window.VoiceRoom;
|
||||
joinSpy = jasmine.createSpy("join").and.returnValue(Promise.resolve());
|
||||
window.VoiceRoom = { join: joinSpy };
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
window.VoiceRoom = origVR;
|
||||
vbtn.remove();
|
||||
try { sessionStorage.removeItem("mysea-voice-room"); } catch (e) {}
|
||||
});
|
||||
|
||||
it("rejoins when the remembered room matches the active voice btn", () => {
|
||||
sessionStorage.setItem("mysea-voice-room", "mysea-abc");
|
||||
bindVoiceBtn();
|
||||
expect(joinSpy).toHaveBeenCalledWith("mysea-abc");
|
||||
});
|
||||
|
||||
it("does NOT rejoin when the remembered room is a different sea", () => {
|
||||
sessionStorage.setItem("mysea-voice-room", "mysea-other");
|
||||
bindVoiceBtn();
|
||||
expect(joinSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does NOT rejoin when voice is unavailable (btn inactive)", () => {
|
||||
vbtn.classList.remove("active");
|
||||
sessionStorage.setItem("mysea-voice-room", "mysea-abc");
|
||||
bindVoiceBtn();
|
||||
expect(joinSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("remembers the room on a manual join; mySeaVoiceForget clears it", () => {
|
||||
bindVoiceBtn();
|
||||
expect(joinSpy).not.toHaveBeenCalled(); // nothing remembered yet
|
||||
vbtn.click();
|
||||
expect(joinSpy).toHaveBeenCalledWith("mysea-abc");
|
||||
expect(sessionStorage.getItem("mysea-voice-room")).toBe("mysea-abc");
|
||||
window.mySeaVoiceForget();
|
||||
expect(sessionStorage.getItem("mysea-voice-room")).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user