mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
867 lines
25 KiB
TypeScript
867 lines
25 KiB
TypeScript
import qs from "querystring"
|
|
import { SonosManager, SonosDevice } from "@svrooij/sonos";
|
|
import {
|
|
MusicServicesService,
|
|
MusicService,
|
|
} from "@svrooij/sonos/lib/services";
|
|
jest.mock("@svrooij/sonos");
|
|
|
|
import axios from "axios";
|
|
jest.mock("axios");
|
|
|
|
import { v4 as uuid } from 'uuid';
|
|
|
|
import { AMAZON_MUSIC, APPLE_MUSIC, AUDIBLE } from "./music_services";
|
|
|
|
import sonos, {
|
|
SONOS_DISABLED,
|
|
asDevice,
|
|
asService,
|
|
asCustomdForm,
|
|
bonobService,
|
|
Service,
|
|
PRESENTATION_AND_STRINGS_VERSION,
|
|
BONOB_CAPABILITIES,
|
|
asRemoveCustomdForm,
|
|
} from "../src/sonos";
|
|
|
|
import { aSonosDevice, aService } from "./builders";
|
|
import url from "../src/url_builder";
|
|
|
|
const mockSonosManagerConstructor = <jest.Mock<SonosManager>>SonosManager;
|
|
|
|
describe("sonos", () => {
|
|
beforeEach(() => {
|
|
mockSonosManagerConstructor.mockClear();
|
|
});
|
|
|
|
describe("asService", () => {
|
|
it("should convert", () => {
|
|
const musicService: MusicService = {
|
|
Name: "Amazon Music",
|
|
Version: "1.1",
|
|
Uri: "https://sonos.amazonmusic.com/",
|
|
SecureUri: "https://sonos.amazonmusic.com/",
|
|
ContainerType: "MService",
|
|
Capabilities: "2208321",
|
|
Presentation: {
|
|
Strings: {
|
|
Version: "23",
|
|
Uri: "https://sonos.amazonmusic.com/strings.xml",
|
|
},
|
|
PresentationMap: {
|
|
Version: "17",
|
|
Uri: "https://sonos.amazonmusic.com/PresentationMap.xml",
|
|
},
|
|
},
|
|
Id: 201,
|
|
Policy: { Auth: "DeviceLink", PollInterval: 60 },
|
|
Manifest: {
|
|
Uri: "",
|
|
Version: "",
|
|
},
|
|
};
|
|
|
|
expect(asService(musicService)).toEqual({
|
|
name: "Amazon Music",
|
|
sid: 201,
|
|
uri: "https://sonos.amazonmusic.com/",
|
|
secureUri: "https://sonos.amazonmusic.com/",
|
|
strings: {
|
|
uri: "https://sonos.amazonmusic.com/strings.xml",
|
|
version: "23",
|
|
},
|
|
presentation: {
|
|
uri: "https://sonos.amazonmusic.com/PresentationMap.xml",
|
|
version: "17",
|
|
},
|
|
pollInterval: 60,
|
|
authType: "DeviceLink",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("asDevice", () => {
|
|
it("should convert", () => {
|
|
const musicServicesService = {
|
|
ListAndParseAvailableServices: jest.fn(),
|
|
};
|
|
const device = {
|
|
Name: "d1",
|
|
GroupName: "g1",
|
|
Host: "127.0.0.222",
|
|
Port: 123,
|
|
MusicServicesService: (musicServicesService as unknown) as MusicServicesService,
|
|
} as SonosDevice;
|
|
|
|
musicServicesService.ListAndParseAvailableServices.mockResolvedValue([
|
|
AMAZON_MUSIC,
|
|
APPLE_MUSIC,
|
|
]);
|
|
|
|
expect(asDevice(device)).toEqual({
|
|
name: "d1",
|
|
group: "g1",
|
|
ip: "127.0.0.222",
|
|
port: 123,
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("bonobService", () => {
|
|
describe("when the bonob url does not have a trailing /", () => {
|
|
it("should return a valid bonob service", () => {
|
|
expect(
|
|
bonobService("some-bonob", 876, url("http://bonob.example.com"))
|
|
).toEqual({
|
|
name: "some-bonob",
|
|
sid: 876,
|
|
uri: `http://bonob.example.com/ws/sonos`,
|
|
secureUri: `http://bonob.example.com/ws/sonos`,
|
|
strings: {
|
|
uri: `http://bonob.example.com/sonos/strings.xml`,
|
|
version: PRESENTATION_AND_STRINGS_VERSION,
|
|
},
|
|
presentation: {
|
|
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
|
version: PRESENTATION_AND_STRINGS_VERSION,
|
|
},
|
|
pollInterval: 1200,
|
|
authType: "AppLink",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when the bonob url does have a trailing /", () => {
|
|
it("should return a valid bonob service", () => {
|
|
expect(
|
|
bonobService("some-bonob", 876, url("http://bonob.example.com/"))
|
|
).toEqual({
|
|
name: "some-bonob",
|
|
sid: 876,
|
|
uri: `http://bonob.example.com/ws/sonos`,
|
|
secureUri: `http://bonob.example.com/ws/sonos`,
|
|
strings: {
|
|
uri: `http://bonob.example.com/sonos/strings.xml`,
|
|
version: PRESENTATION_AND_STRINGS_VERSION,
|
|
},
|
|
presentation: {
|
|
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
|
version: PRESENTATION_AND_STRINGS_VERSION,
|
|
},
|
|
pollInterval: 1200,
|
|
authType: "AppLink",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when the bonob url has a context of /some-context", () => {
|
|
it("should return a valid bonob service", () => {
|
|
expect(
|
|
bonobService("some-bonob", 876, url("http://bonob.example.com/some-context"))
|
|
).toEqual({
|
|
name: "some-bonob",
|
|
sid: 876,
|
|
uri: `http://bonob.example.com/some-context/ws/sonos`,
|
|
secureUri: `http://bonob.example.com/some-context/ws/sonos`,
|
|
strings: {
|
|
uri: `http://bonob.example.com/some-context/sonos/strings.xml`,
|
|
version: PRESENTATION_AND_STRINGS_VERSION,
|
|
},
|
|
presentation: {
|
|
uri: `http://bonob.example.com/some-context/sonos/presentationMap.xml`,
|
|
version: PRESENTATION_AND_STRINGS_VERSION,
|
|
},
|
|
pollInterval: 1200,
|
|
authType: "AppLink",
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when authType is specified", () => {
|
|
it("should return a valid bonob service", () => {
|
|
expect(
|
|
bonobService("some-bonob", 876, url("http://bonob.example.com"), 'DeviceLink')
|
|
).toEqual({
|
|
name: "some-bonob",
|
|
sid: 876,
|
|
uri: `http://bonob.example.com/ws/sonos`,
|
|
secureUri: `http://bonob.example.com/ws/sonos`,
|
|
strings: {
|
|
uri: `http://bonob.example.com/sonos/strings.xml`,
|
|
version: PRESENTATION_AND_STRINGS_VERSION,
|
|
},
|
|
presentation: {
|
|
uri: `http://bonob.example.com/sonos/presentationMap.xml`,
|
|
version: PRESENTATION_AND_STRINGS_VERSION,
|
|
},
|
|
pollInterval: 1200,
|
|
authType: "DeviceLink",
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("asCustomdForm", () => {
|
|
describe("when all values specified", () => {
|
|
it("should return a form", () => {
|
|
const csrfToken = uuid();
|
|
const service: Service = {
|
|
name: "the new service",
|
|
sid: 888,
|
|
uri: "http://aa.example.com",
|
|
secureUri: "https://aa.example.com",
|
|
strings: { uri: "http://strings.example.com", version: "26" },
|
|
presentation: {
|
|
uri: "http://presentation.example.com",
|
|
version: "27",
|
|
},
|
|
pollInterval: 5600,
|
|
authType: "UserId",
|
|
};
|
|
|
|
expect(asCustomdForm(csrfToken, service)).toEqual({
|
|
csrfToken,
|
|
sid: "888",
|
|
name: "the new service",
|
|
uri: "http://aa.example.com",
|
|
secureUri: "https://aa.example.com",
|
|
pollInterval: "5600",
|
|
authType: "UserId",
|
|
stringsVersion: "26",
|
|
stringsUri: "http://strings.example.com",
|
|
presentationMapVersion: "27",
|
|
presentationMapUri: "http://presentation.example.com",
|
|
containerType: "MService",
|
|
caps: BONOB_CAPABILITIES
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when pollInterval undefined", () => {
|
|
it("should default to 1200", () => {
|
|
const service: Service = aService({ pollInterval: undefined });
|
|
expect(asCustomdForm(uuid(), service).pollInterval).toEqual("1200");
|
|
});
|
|
});
|
|
|
|
describe("when strings and presentation are undefined", () => {
|
|
it("should default to 1200", () => {
|
|
const service: Service = aService({
|
|
strings: { uri: undefined, version: undefined },
|
|
presentation: { uri: undefined, version: undefined },
|
|
});
|
|
const form = asCustomdForm(uuid(), service)
|
|
expect(form.stringsUri).toEqual("");
|
|
expect(form.stringsVersion).toEqual("0");
|
|
expect(form.presentationMapUri).toEqual("");
|
|
expect(form.presentationMapVersion).toEqual("0");
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("asRemoveCustomdForm", () => {
|
|
it("should return a form", () => {
|
|
const csrfToken = uuid();
|
|
const sid = 123;
|
|
|
|
expect(asRemoveCustomdForm(csrfToken, sid)).toEqual({
|
|
csrfToken,
|
|
sid: "123"
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when is disabled", () => {
|
|
it("should return a disabled client", async () => {
|
|
const disabled = sonos({ auto: false });
|
|
|
|
expect(disabled).toEqual(SONOS_DISABLED);
|
|
expect(await disabled.devices()).toEqual([]);
|
|
expect(await disabled.services()).toEqual([]);
|
|
expect(await disabled.register(aService())).toEqual(true);
|
|
});
|
|
});
|
|
|
|
describe("sonos device discovery", () => {
|
|
const device1 = {
|
|
Name: "device1",
|
|
GroupName: "group1",
|
|
Host: "127.0.0.11",
|
|
Port: 111,
|
|
} as SonosDevice;
|
|
|
|
const device2 = {
|
|
Name: "device2",
|
|
GroupName: "group2",
|
|
Host: "127.0.0.22",
|
|
Port: 222,
|
|
} as SonosDevice;
|
|
|
|
describe("when no sonos seed host is provided", () => {
|
|
it("should perform auto-discovery", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const actualDevices = await sonos({ auto: true }).devices();
|
|
|
|
expect(SonosManager).toHaveBeenCalledTimes(1);
|
|
expect(sonosManager.InitializeWithDiscovery).toHaveBeenCalledWith(10);
|
|
|
|
expect(actualDevices).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("when sonos seed host is empty string", () => {
|
|
it("should perform auto-discovery", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const actualDevices = await sonos({ auto: true, seedHost: "" }).devices();
|
|
|
|
expect(SonosManager).toHaveBeenCalledTimes(1);
|
|
expect(sonosManager.InitializeWithDiscovery).toHaveBeenCalledWith(10);
|
|
|
|
expect(actualDevices).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("when a sonos seed host is provided", () => {
|
|
it("should perform auto-discovery", async () => {
|
|
const seedHost = "theSeedsOfLife";
|
|
|
|
const sonosManager = {
|
|
InitializeFromDevice: jest.fn(),
|
|
Devices: [],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeFromDevice.mockResolvedValue(true);
|
|
|
|
const actualDevices = await sonos({ auto: true, seedHost }).devices();
|
|
|
|
expect(SonosManager).toHaveBeenCalledTimes(1);
|
|
expect(sonosManager.InitializeFromDevice).toHaveBeenCalledWith(
|
|
seedHost
|
|
);
|
|
|
|
expect(actualDevices).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("when some devices are found", () => {
|
|
it("should be able to return them", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const actualDevices = await sonos({ auto: true, seedHost: undefined }).devices();
|
|
|
|
expect(actualDevices).toEqual([
|
|
{
|
|
name: device1.Name,
|
|
group: device1.GroupName,
|
|
ip: device1.Host,
|
|
port: device1.Port,
|
|
},
|
|
{
|
|
name: device2.Name,
|
|
group: device2.GroupName,
|
|
ip: device2.Host,
|
|
port: device2.Port,
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("when SonosManager initialisation returns false", () => {
|
|
it("should return no devices", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(false);
|
|
|
|
expect(await sonos({ auto: true, seedHost: "" }).devices()).toEqual([]);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("sonos service discovery", () => {
|
|
const device1 = {
|
|
Name: "device1",
|
|
GroupName: "group1",
|
|
Host: "127.0.0.11",
|
|
Port: 111,
|
|
MusicServicesService: {
|
|
ListAndParseAvailableServices: jest.fn(),
|
|
},
|
|
};
|
|
|
|
const device2 = {
|
|
Name: "device2",
|
|
GroupName: "group2",
|
|
Host: "127.0.0.22",
|
|
Port: 222,
|
|
};
|
|
|
|
beforeEach(() => {
|
|
device1.MusicServicesService.ListAndParseAvailableServices.mockClear();
|
|
});
|
|
|
|
describe("when there are no devices", () => {
|
|
it("should return no services", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const services = await sonos().services();
|
|
|
|
expect(SonosManager).toHaveBeenCalledTimes(1);
|
|
expect(sonosManager.InitializeWithDiscovery).toHaveBeenCalledWith(10);
|
|
|
|
expect(services).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("when there are some devices", () => {
|
|
it("should return the services from the first device", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
device1.MusicServicesService.ListAndParseAvailableServices.mockResolvedValue(
|
|
[AMAZON_MUSIC, APPLE_MUSIC, AUDIBLE]
|
|
);
|
|
|
|
const services = await sonos().services();
|
|
|
|
expect(SonosManager).toHaveBeenCalledTimes(1);
|
|
expect(sonosManager.InitializeWithDiscovery).toHaveBeenCalledWith(10);
|
|
|
|
expect(services).toEqual([
|
|
asService(AMAZON_MUSIC),
|
|
asService(APPLE_MUSIC),
|
|
asService(AUDIBLE),
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("when SonosManager initialisation returns false", () => {
|
|
it("should return no devices", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(false);
|
|
|
|
const services = await sonos().services();
|
|
|
|
expect(SonosManager).toHaveBeenCalledTimes(1);
|
|
expect(sonosManager.InitializeWithDiscovery).toHaveBeenCalledWith(10);
|
|
|
|
expect(services).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("when getting devices fails", () => {
|
|
it("should return no devices", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: () => {
|
|
throw Error("Boom");
|
|
},
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const services = await sonos().services();
|
|
|
|
expect(SonosManager).toHaveBeenCalledTimes(1);
|
|
expect(sonosManager.InitializeWithDiscovery).toHaveBeenCalledWith(10);
|
|
|
|
expect(services).toEqual([]);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("registering a service", () => {
|
|
const device1 = aSonosDevice({
|
|
Name: "d1",
|
|
Host: "127.0.0.11",
|
|
Port: 111,
|
|
});
|
|
|
|
const device2 = aSonosDevice({
|
|
Name: "d2",
|
|
});
|
|
|
|
const POST_CONFIG = {
|
|
headers: {
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
};
|
|
|
|
const serviceToAdd = aService({
|
|
name: "new service",
|
|
sid: 123,
|
|
});
|
|
|
|
const mockGet = jest.fn();
|
|
const mockPost = jest.fn();
|
|
|
|
beforeEach(() => {
|
|
mockGet.mockClear();
|
|
mockPost.mockClear();
|
|
|
|
axios.get = mockGet;
|
|
axios.post = mockPost;
|
|
});
|
|
|
|
describe("when successful", () => {
|
|
it("should post the service into the first found sonos device, returning true", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const csrfToken = `csrfToken-${uuid()}`;
|
|
|
|
mockGet.mockResolvedValue({
|
|
status: 200,
|
|
data: `<html><input name='csrfToken' value='${csrfToken}'></html>`,
|
|
});
|
|
mockPost.mockResolvedValue({ status: 200, data: "" });
|
|
|
|
const result = await sonos().register(serviceToAdd);
|
|
|
|
expect(mockGet).toHaveBeenCalledWith(
|
|
`http://${device1.Host}:${device1.Port}/customsd`
|
|
);
|
|
|
|
expect(mockPost).toHaveBeenCalledWith(
|
|
`http://${device1.Host}:${device1.Port}/customsd`,
|
|
new URLSearchParams(qs.stringify(asCustomdForm(csrfToken, serviceToAdd))),
|
|
POST_CONFIG
|
|
);
|
|
|
|
expect(result).toEqual(true);
|
|
});
|
|
});
|
|
|
|
describe("when cannot find any devices", () => {
|
|
it("should return false", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const result = await sonos().register(serviceToAdd);
|
|
|
|
expect(mockGet).not.toHaveBeenCalled();
|
|
expect(mockPost).not.toHaveBeenCalled();
|
|
|
|
expect(result).toEqual(false);
|
|
});
|
|
});
|
|
|
|
describe("when cannot get csrfToken", () => {
|
|
describe("when the token is missing", () => {
|
|
it("should return false", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
mockGet.mockResolvedValue({
|
|
status: 200,
|
|
data: `<html></html>`,
|
|
});
|
|
|
|
const result = await sonos().register(serviceToAdd);
|
|
|
|
expect(mockPost).not.toHaveBeenCalled();
|
|
|
|
expect(result).toEqual(false);
|
|
});
|
|
});
|
|
|
|
describe("when the token call returns a non 200", () => {
|
|
it("should return false", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
mockGet.mockResolvedValue({
|
|
status: 400,
|
|
data: `<html></html>`,
|
|
});
|
|
|
|
const result = await sonos().register(serviceToAdd);
|
|
|
|
expect(mockPost).not.toHaveBeenCalled();
|
|
|
|
expect(result).toEqual(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when posting in the service definition fails", () => {
|
|
it("should return false", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const csrfToken = `csrfToken-${uuid()}`;
|
|
|
|
mockGet.mockResolvedValue({
|
|
status: 200,
|
|
data: `<html><input name='csrfToken' value='${csrfToken}'></html>`,
|
|
});
|
|
mockPost.mockResolvedValue({ status: 500, data: "" });
|
|
|
|
const result = await sonos().register(serviceToAdd);
|
|
|
|
expect(result).toEqual(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("removing a service", () => {
|
|
const device1 = aSonosDevice({
|
|
Name: "d1",
|
|
Host: "127.0.0.11",
|
|
Port: 111,
|
|
});
|
|
|
|
const device2 = aSonosDevice({
|
|
Name: "d2",
|
|
});
|
|
|
|
const POST_CONFIG = {
|
|
headers: {
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
};
|
|
|
|
const sidToRemove = 333;
|
|
|
|
const mockGet = jest.fn();
|
|
const mockPost = jest.fn();
|
|
|
|
beforeEach(() => {
|
|
mockGet.mockClear();
|
|
mockPost.mockClear();
|
|
|
|
axios.get = mockGet;
|
|
axios.post = mockPost;
|
|
});
|
|
|
|
describe("when successful", () => {
|
|
it("should post the remove into the first found sonos device, returning true", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const csrfToken = `csrfToken-${uuid()}`;
|
|
|
|
mockGet.mockResolvedValue({
|
|
status: 200,
|
|
data: `<html><input name='csrfToken' value='${csrfToken}'></html>`,
|
|
});
|
|
mockPost.mockResolvedValue({ status: 200, data: "" });
|
|
|
|
const result = await sonos().remove(sidToRemove);
|
|
|
|
expect(mockGet).toHaveBeenCalledWith(
|
|
`http://${device1.Host}:${device1.Port}/customsd`
|
|
);
|
|
|
|
expect(mockPost).toHaveBeenCalledWith(
|
|
`http://${device1.Host}:${device1.Port}/customsd`,
|
|
new URLSearchParams(qs.stringify(asRemoveCustomdForm(csrfToken, sidToRemove))),
|
|
POST_CONFIG
|
|
);
|
|
|
|
expect(result).toEqual(true);
|
|
});
|
|
});
|
|
|
|
describe("when cannot find any devices", () => {
|
|
it("should return false", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const result = await sonos().remove(sidToRemove);
|
|
|
|
expect(mockGet).not.toHaveBeenCalled();
|
|
expect(mockPost).not.toHaveBeenCalled();
|
|
|
|
expect(result).toEqual(false);
|
|
});
|
|
});
|
|
|
|
describe("when cannot get csrfToken", () => {
|
|
describe("when the token is missing", () => {
|
|
it("should return false", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
mockGet.mockResolvedValue({
|
|
status: 200,
|
|
data: `<html></html>`,
|
|
});
|
|
|
|
const result = await sonos().remove(sidToRemove);
|
|
|
|
expect(mockPost).not.toHaveBeenCalled();
|
|
|
|
expect(result).toEqual(false);
|
|
});
|
|
});
|
|
|
|
describe("when the token call returns a non 200", () => {
|
|
it("should return false", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
mockGet.mockResolvedValue({
|
|
status: 400,
|
|
data: `<html></html>`,
|
|
});
|
|
|
|
const result = await sonos().remove(sidToRemove);
|
|
|
|
expect(mockPost).not.toHaveBeenCalled();
|
|
|
|
expect(result).toEqual(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("when posting in the sid to delete fails", () => {
|
|
it("should return false", async () => {
|
|
const sonosManager = {
|
|
InitializeWithDiscovery: jest.fn(),
|
|
Devices: [device1, device2],
|
|
};
|
|
|
|
mockSonosManagerConstructor.mockReturnValue(
|
|
(sonosManager as unknown) as SonosManager
|
|
);
|
|
sonosManager.InitializeWithDiscovery.mockResolvedValue(true);
|
|
|
|
const csrfToken = `csrfToken-${uuid()}`;
|
|
|
|
mockGet.mockResolvedValue({
|
|
status: 200,
|
|
data: `<html><input name='csrfToken' value='${csrfToken}'></html>`,
|
|
});
|
|
mockPost.mockResolvedValue({ status: 500, data: "" });
|
|
|
|
const result = await sonos().remove(sidToRemove);
|
|
|
|
expect(result).toEqual(false);
|
|
});
|
|
});
|
|
});
|
|
});
|