123import { describe, expect, it, vi } from "vitest";4import {5 discoverPeachSync,6 parsePeachSyncService,7 type MdnsApi,8 type MdnsServiceRecord,9} from "./desktop-pairing-mdns";1011const VALID_RECORD: MdnsServiceRecord = {12 serviceName: "peach-sync-223e15d3._peach-sync._tcp.local",13 serviceHostPort: "kyoshi.local:8765",14 ipAddress: "192.168.4.230",15 serviceData: ["version=0.4.0", "id=223e15d3", "sync-port=8765", "pair-port=49142"],16};1718describe("parsePeachSyncService", () => {19 it("maps a full peach-sync record to ip + both ports + version", () => {20 expect(parsePeachSyncService(VALID_RECORD)).toEqual({21 ip: "192.168.4.230",22 syncPort: 8765,23 pairPort: 49142,24 version: "0.4.0",25 });26 });2728 it("ignores records for other service types", () => {29 expect(30 parsePeachSyncService({ ...VALID_RECORD, serviceName: "_googlecast._tcp.local" }),31 ).toBeNull();32 });3334 it("rejects a record with no usable IPv4 address", () => {35 expect(parsePeachSyncService({ ...VALID_RECORD, ipAddress: undefined })).toBeNull();36 expect(parsePeachSyncService({ ...VALID_RECORD, ipAddress: "kyoshi.local" })).toBeNull();37 });3839 it("falls back to the SRV port and default pair port when TXT omits them", () => {40 const svc = parsePeachSyncService({ ...VALID_RECORD, serviceData: [] });41 expect(svc).toEqual({ ip: "192.168.4.230", syncPort: 8765, pairPort: 49142, version: undefined });42 });4344 it("prefers the TXT sync-port over the SRV host:port", () => {45 const svc = parsePeachSyncService({46 ...VALID_RECORD,47 serviceHostPort: "kyoshi.local:9999",48 serviceData: ["sync-port=8765", "pair-port=49142"],49 });50 expect(svc?.syncPort).toBe(8765);51 });52});5354describe("discoverPeachSync", () => {55 it("resolves null when chrome.mdns is unavailable", async () => {56 await expect(discoverPeachSync({ mdns: null })).resolves.toBeNull();57 });5859 it("resolves the first peach-sync service from a service list", async () => {60 let captured: ((services: MdnsServiceRecord[]) => void) | null = null;61 const removeListener = vi.fn();62 const api: MdnsApi = {63 onServiceList: {64 addListener: (cb) => {65 captured = cb;66 },67 removeListener,68 },69 forceDiscovery: (cb) => cb(),70 };7172 const promise = discoverPeachSync({ mdns: api, timeoutMs: 1000 });73 captured!([{ serviceName: "_other._tcp.local" }, VALID_RECORD]);7475 await expect(promise).resolves.toEqual({76 ip: "192.168.4.230",77 syncPort: 8765,78 pairPort: 49142,79 version: "0.4.0",80 });81 expect(removeListener).toHaveBeenCalledTimes(1);82 });8384 it("resolves null and unsubscribes when nothing answers before the timeout", async () => {85 vi.useFakeTimers();86 try {87 const removeListener = vi.fn();88 const api: MdnsApi = {89 onServiceList: { addListener: () => undefined, removeListener },90 };91 const promise = discoverPeachSync({ mdns: api, timeoutMs: 3000 });92 await vi.advanceTimersByTimeAsync(3000);93 await expect(promise).resolves.toBeNull();94 expect(removeListener).toHaveBeenCalledTimes(1);95 } finally {96 vi.useRealTimers();97 }98 });99});