Files
hyperframes/packages/player/src/slideshow/test-setup.ts
T
Vance IngallsandClaude Opus 4.8 7af3eb8f80 feat(player): slideshow controller + <hyperframes-slideshow> component (#1581)
DOM-free SlideshowController (discrete nav, fragment holds, branch stack)
driving the existing player; <hyperframes-slideshow> web component with a
unified mute+nav capsule (conditional prev/next), floating hotspot overlays,
presenter mode (BroadcastChannel), keyboard/touch, and a scenes getter fed
via the runtime message handler.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 01:31:27 -07:00

47 lines
1.2 KiB
TypeScript

/**
* Vitest setup: install a minimal in-memory BroadcastChannel polyfill so that
* happy-dom tests can exercise the presenter/audience channel code path.
* This polyfill is intentionally NOT shipped in production code.
*/
type MsgHandler = (event: MessageEvent) => void;
const registry = new Map<string, Set<InMemoryBroadcastChannel>>();
class InMemoryBroadcastChannel {
onmessage: MsgHandler | null = null;
readonly name: string;
private _closed = false;
constructor(name: string) {
this.name = name;
let set = registry.get(name);
if (!set) {
set = new Set();
registry.set(name, set);
}
set.add(this);
}
// fallow-ignore-next-line complexity
postMessage(data: unknown): void {
if (this._closed) return;
const peers = registry.get(this.name);
if (!peers) return;
for (const peer of peers) {
if (peer === this) continue;
peer.onmessage?.(new MessageEvent("message", { data }));
}
}
close(): void {
if (this._closed) return;
this._closed = true;
registry.get(this.name)?.delete(this);
}
}
if (typeof globalThis.BroadcastChannel === "undefined") {
(globalThis as Record<string, unknown>)["BroadcastChannel"] = InMemoryBroadcastChannel;
}