// Tests for mDNS discovery of the peach-sync desktop helper. import { describe, expect, it, vi } from "vitest"; import { discoverPeachSync, parsePeachSyncService, type MdnsApi, type MdnsServiceRecord, } from "./desktop-pairing-mdns"; const VALID_RECORD: MdnsServiceRecord = { serviceName: "peach-sync-223e15d3._peach-sync._tcp.local", serviceHostPort: "kyoshi.local:8765", ipAddress: "192.168.4.230", serviceData: ["version=0.4.0", "id=223e15d3", "sync-port=8765", "pair-port=49142"], }; describe("parsePeachSyncService", () => { it("maps a full peach-sync record to ip + both ports + version", () => { expect(parsePeachSyncService(VALID_RECORD)).toEqual({ ip: "192.168.4.230", syncPort: 8765, pairPort: 49142, version: "0.4.0", }); }); it("ignores records for other service types", () => { expect( parsePeachSyncService({ ...VALID_RECORD, serviceName: "_googlecast._tcp.local" }), ).toBeNull(); }); it("rejects a record with no usable IPv4 address", () => { expect(parsePeachSyncService({ ...VALID_RECORD, ipAddress: undefined })).toBeNull(); expect(parsePeachSyncService({ ...VALID_RECORD, ipAddress: "kyoshi.local" })).toBeNull(); }); it("falls back to the SRV port and default pair port when TXT omits them", () => { const svc = parsePeachSyncService({ ...VALID_RECORD, serviceData: [] }); expect(svc).toEqual({ ip: "192.168.4.230", syncPort: 8765, pairPort: 49142, version: undefined }); }); it("prefers the TXT sync-port over the SRV host:port", () => { const svc = parsePeachSyncService({ ...VALID_RECORD, serviceHostPort: "kyoshi.local:9999", serviceData: ["sync-port=8765", "pair-port=49142"], }); expect(svc?.syncPort).toBe(8765); }); }); describe("discoverPeachSync", () => { it("resolves null when chrome.mdns is unavailable", async () => { await expect(discoverPeachSync({ mdns: null })).resolves.toBeNull(); }); it("resolves the first peach-sync service from a service list", async () => { let captured: ((services: MdnsServiceRecord[]) => void) | null = null; const removeListener = vi.fn(); const api: MdnsApi = { onServiceList: { addListener: (cb) => { captured = cb; }, removeListener, }, forceDiscovery: (cb) => cb(), }; const promise = discoverPeachSync({ mdns: api, timeoutMs: 1000 }); captured!([{ serviceName: "_other._tcp.local" }, VALID_RECORD]); await expect(promise).resolves.toEqual({ ip: "192.168.4.230", syncPort: 8765, pairPort: 49142, version: "0.4.0", }); expect(removeListener).toHaveBeenCalledTimes(1); }); it("resolves null and unsubscribes when nothing answers before the timeout", async () => { vi.useFakeTimers(); try { const removeListener = vi.fn(); const api: MdnsApi = { onServiceList: { addListener: () => undefined, removeListener }, }; const promise = discoverPeachSync({ mdns: api, timeoutMs: 3000 }); await vi.advanceTimersByTimeAsync(3000); await expect(promise).resolves.toBeNull(); expect(removeListener).toHaveBeenCalledTimes(1); } finally { vi.useRealTimers(); } }); });