multi-room groups, addressed by MAC (derived from the `lms-{mac}` device id).
92 lines
3.4 KiB
TypeScript
92 lines
3.4 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
import { get } from "svelte/store";
|
|
import type { Session } from "$lib/api/types";
|
|
|
|
const mockInvoke = vi.fn();
|
|
vi.mock("$lib/api/bindings", () => ({
|
|
commands: {
|
|
lmsGetSyncGroups: () => mockInvoke("lms_get_sync_groups"),
|
|
lmsCreateSyncGroup: (masterMac: string, slaveMacs: string[]) =>
|
|
mockInvoke("lms_create_sync_group", { masterMac, slaveMacs }),
|
|
lmsUnsyncPlayer: (mac: string) => mockInvoke("lms_unsync_player", { mac }),
|
|
lmsDissolveSyncGroup: (masterMac: string) =>
|
|
mockInvoke("lms_dissolve_sync_group", { masterMac }),
|
|
},
|
|
}));
|
|
|
|
import { lmsSync, isLmsSession, macForSession } from "./lmsSync";
|
|
|
|
function session(deviceId: string | null): Session {
|
|
return { id: "s", deviceId } as unknown as Session;
|
|
}
|
|
|
|
describe("LMS session detection", () => {
|
|
it("detects LMS zones by the lms- device-id prefix", () => {
|
|
expect(isLmsSession(session("lms-aa:bb:cc:dd:ee:ff"))).toBe(true);
|
|
expect(isLmsSession(session("chromecast-123"))).toBe(false);
|
|
expect(isLmsSession(session(null))).toBe(false);
|
|
expect(isLmsSession(null)).toBe(false);
|
|
});
|
|
|
|
it("recovers the MAC from an LMS session, null otherwise", () => {
|
|
expect(macForSession(session("lms-aa:bb:cc:dd:ee:ff"))).toBe("aa:bb:cc:dd:ee:ff");
|
|
expect(macForSession(session("web-xyz"))).toBeNull();
|
|
expect(macForSession(null)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("lmsSync store", () => {
|
|
beforeEach(() => {
|
|
mockInvoke.mockReset();
|
|
lmsSync.reset();
|
|
});
|
|
|
|
it("fusing preserves existing slaves and adds the new zone", async () => {
|
|
// Initial group: master M with slave A.
|
|
mockInvoke.mockResolvedValueOnce([{ masterMac: "M", masterName: "M", slaveMacs: ["A"], slaveNames: [] }]);
|
|
await lmsSync.refresh();
|
|
|
|
// create returns void; refresh after returns the updated group.
|
|
mockInvoke.mockResolvedValueOnce(undefined);
|
|
mockInvoke.mockResolvedValueOnce([{ masterMac: "M", masterName: "M", slaveMacs: ["A", "B"], slaveNames: [] }]);
|
|
|
|
await lmsSync.fuseZone("M", "B");
|
|
|
|
expect(mockInvoke).toHaveBeenCalledWith("lms_create_sync_group", {
|
|
masterMac: "M",
|
|
slaveMacs: ["A", "B"],
|
|
});
|
|
expect(get(lmsSync).groups[0].slaveMacs).toEqual(["A", "B"]);
|
|
});
|
|
|
|
it("decoupling a slave unsyncs just that player", async () => {
|
|
mockInvoke.mockResolvedValueOnce([{ masterMac: "M", masterName: "M", slaveMacs: ["A"], slaveNames: [] }]);
|
|
await lmsSync.refresh();
|
|
|
|
mockInvoke.mockResolvedValueOnce(undefined); // unsync
|
|
mockInvoke.mockResolvedValueOnce([{ masterMac: "M", masterName: "M", slaveMacs: [], slaveNames: [] }]);
|
|
|
|
await lmsSync.decoupleZone("A");
|
|
|
|
expect(mockInvoke).toHaveBeenCalledWith("lms_unsync_player", { mac: "A" });
|
|
});
|
|
|
|
it("decoupling the master dissolves the whole group", async () => {
|
|
mockInvoke.mockResolvedValueOnce([{ masterMac: "M", masterName: "M", slaveMacs: ["A"], slaveNames: [] }]);
|
|
await lmsSync.refresh();
|
|
|
|
mockInvoke.mockResolvedValueOnce(undefined); // dissolve
|
|
mockInvoke.mockResolvedValueOnce([]);
|
|
|
|
await lmsSync.decoupleZone("M");
|
|
|
|
expect(mockInvoke).toHaveBeenCalledWith("lms_dissolve_sync_group", { masterMac: "M" });
|
|
});
|
|
|
|
it("treats a missing plugin (refresh error) as no groups, not fatal", async () => {
|
|
mockInvoke.mockRejectedValueOnce(new Error("404"));
|
|
await lmsSync.refresh();
|
|
expect(get(lmsSync).groups).toEqual([]);
|
|
});
|
|
});
|