import assert from "node:assert/strict"; import test from "node:test"; import { HostTabSync } from "../src/host/tab-sync.ts"; class FakeBus { channels = new Set(); messages = []; createChannel() { const channel = new FakeChannel(this); this.channels.add(channel); return channel; } deliver(sender, message) { const copy = structuredClone(message); this.messages.push(copy); for (const channel of this.channels) { if (channel !== sender) channel.receive(copy); } } replay(message) { for (const channel of this.channels) channel.receive(structuredClone(message)); } } class FakeChannel { listeners = new Set(); constructor(bus) { this.bus = bus; } postMessage(message) { this.bus.deliver(this, message); } addEventListener(type, listener) { if (type === "message") this.listeners.add(listener); } removeEventListener(type, listener) { if (type === "message") this.listeners.delete(listener); } receive(data) { for (const listener of this.listeners) listener({ data }); } close() { this.bus.channels.delete(this); this.listeners.clear(); } } test("new tabs request and receive the current Host state", () => { const bus = new FakeBus(); const firstState = hostState("http://runtime-a.test"); const received = []; const first = new HostTabSync({ tabId: "tab-a", channel: bus.createChannel(), getState: () => firstState, applyState: () => {}, }); const second = new HostTabSync({ tabId: "tab-b", channel: bus.createChannel(), getState: () => hostState("http://runtime-b.test"), applyState: (state) => received.push(state), }); assert.deepEqual(received, [firstState]); first.close(); second.close(); }); test("publishes Host state but rejects self, stale and malformed messages", () => { const bus = new FakeBus(); const received = []; const first = new HostTabSync({ tabId: "tab-a", channel: bus.createChannel(), getState: () => hostState(""), applyState: (state) => received.push(state), }); const second = new HostTabSync({ tabId: "tab-b", channel: bus.createChannel(), getState: () => hostState(""), applyState: () => {}, }); received.length = 0; const update = hostState("http://shared.test"); second.publish(update); assert.deepEqual(received, [update]); const stateMessage = bus.messages.findLast( (message) => message.type === "state" && message.sender === "tab-b", ); bus.replay(stateMessage); bus.replay({ ...stateMessage, sequence: stateMessage.sequence + 1, state: { ...stateMessage.state, connection: "invalid" }, }); assert.deepEqual(received, [update]); first.close(); second.close(); }); function hostState(apiBase) { return { snapshot: null, connection: "online", apiBase, runtimeAction: null, serviceAction: null, deploymentAction: null, }; }