mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Listing devices and services on bonob page sourced from sonos devices
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import request from "supertest";
|
||||
import makeServer from "../src/server";
|
||||
import { SONOS_DISABLED, Sonos } from "../src/sonos";
|
||||
import { SONOS_DISABLED, Sonos, Device } from "../src/sonos";
|
||||
|
||||
describe("index", () => {
|
||||
describe("when sonos integration is disabled", () => {
|
||||
@@ -9,37 +9,77 @@ describe("index", () => {
|
||||
describe("devices list", () => {
|
||||
it("should be empty", async () => {
|
||||
const res = await request(server).get("/").send();
|
||||
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).not.toMatch(/class=device/)
|
||||
expect(res.text).not.toMatch(/class=device/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const device1 : Device = {
|
||||
name: "device1",
|
||||
group: "group1",
|
||||
ip: "172.0.0.1",
|
||||
port: 4301,
|
||||
services: [
|
||||
{
|
||||
name: "s1",
|
||||
id: 1,
|
||||
},
|
||||
{
|
||||
name: "s2",
|
||||
id: 2,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const device2: Device = {
|
||||
name: "device2",
|
||||
group: "group2",
|
||||
ip: "172.0.0.2",
|
||||
port: 4302,
|
||||
services: [
|
||||
{
|
||||
name: "s3",
|
||||
id: 3,
|
||||
},
|
||||
{
|
||||
name: "s4",
|
||||
id: 4,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
describe("when sonos integration is enabled", () => {
|
||||
const fakeSonos: Sonos = {
|
||||
devices: () => [{
|
||||
name: "device1",
|
||||
group: "group1",
|
||||
ip: "172.0.0.1",
|
||||
port: 4301
|
||||
},{
|
||||
name: "device2",
|
||||
group: "group2",
|
||||
ip: "172.0.0.2",
|
||||
port: 4302
|
||||
}]
|
||||
}
|
||||
devices: () =>Promise.resolve([device1, device2]),
|
||||
};
|
||||
|
||||
const server = makeServer(fakeSonos);
|
||||
|
||||
describe("devices list", () => {
|
||||
it("should contain the devices returned from sonos", async () => {
|
||||
const res = await request(server).get("/").send();
|
||||
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch(/device1\s+\(172.0.0.1:4301\)/)
|
||||
expect(res.text).toMatch(/device2\s+\(172.0.0.2:4302\)/)
|
||||
expect(res.text).toMatch(
|
||||
/device1\s+\(172.0.0.1:4301\)/
|
||||
);
|
||||
expect(res.text).toMatch(
|
||||
/device2\s+\(172.0.0.2:4302\)/
|
||||
);
|
||||
});
|
||||
|
||||
it("should contain a list of services returned from sonos", async () => {
|
||||
const res = await request(server).get("/").send();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch(/Services\s+4/);
|
||||
expect(res.text).toMatch(/s1\s+\(1\)/);
|
||||
expect(res.text).toMatch(/s2\s+\(2\)/);
|
||||
expect(res.text).toMatch(/s3\s+\(3\)/);
|
||||
expect(res.text).toMatch(/s4\s+\(4\)/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
76
tests/music_services.ts
Normal file
76
tests/music_services.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { MusicService } from "@svrooij/sonos/lib/services";
|
||||
|
||||
export const AMAZON_MUSIC: 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: "",
|
||||
},
|
||||
};
|
||||
|
||||
export const APPLE_MUSIC: MusicService = {
|
||||
Name: "Apple Music",
|
||||
Version: "1.1",
|
||||
Uri: "https://sonos-music.apple.com/ws/SonosSoap",
|
||||
SecureUri: "https://sonos-music.apple.com/ws/SonosSoap",
|
||||
ContainerType: "MService",
|
||||
Capabilities: "3117633",
|
||||
Presentation: {
|
||||
Strings: {
|
||||
Version: "24",
|
||||
Uri: "https://sonos-music.apple.com/xml/strings.xml",
|
||||
},
|
||||
PresentationMap: {
|
||||
Version: "22",
|
||||
Uri: "http://sonos-pmap.ws.sonos.com/applemusicbrand_pmap3.xml",
|
||||
},
|
||||
},
|
||||
Id: 204,
|
||||
Policy: { Auth: "AppLink", PollInterval: 60 },
|
||||
Manifest: {
|
||||
Uri: "",
|
||||
Version: "",
|
||||
},
|
||||
};
|
||||
|
||||
export const AUDIBLE: MusicService = {
|
||||
Name: "Audible",
|
||||
Version: "1.1",
|
||||
Uri: "https://sonos.audible.com/smapi",
|
||||
SecureUri: "https://sonos.audible.com/smapi",
|
||||
ContainerType: "MService",
|
||||
Capabilities: "1095249",
|
||||
Presentation: {
|
||||
Strings: {
|
||||
Version: "5",
|
||||
Uri: "https://sonos.audible.com/smapi/strings.xml",
|
||||
},
|
||||
PresentationMap: {
|
||||
Version: "5",
|
||||
Uri: "https://sonos.audible.com/smapi/PresentationMap.xml",
|
||||
},
|
||||
},
|
||||
Id: 239,
|
||||
Policy: { Auth: "AppLink", PollInterval: 30 },
|
||||
Manifest: {
|
||||
Uri: "",
|
||||
Version: "",
|
||||
},
|
||||
};
|
||||
9
tests/setup.js
Normal file
9
tests/setup.js
Normal file
@@ -0,0 +1,9 @@
|
||||
global.console = {
|
||||
log: jest.fn(), // console.log are ignored in tests
|
||||
|
||||
// Keep native behaviour for other methods, use those to print out things in your own tests, not `console.log`
|
||||
error: console.error,
|
||||
warn: console.warn,
|
||||
info: console.info,
|
||||
debug: console.debug,
|
||||
};
|
||||
293
tests/sonos.test.ts
Normal file
293
tests/sonos.test.ts
Normal file
@@ -0,0 +1,293 @@
|
||||
import { SonosManager, SonosDevice } from "@svrooij/sonos";
|
||||
import { MusicServicesService } from "@svrooij/sonos/lib/services";
|
||||
jest.mock("@svrooij/sonos");
|
||||
|
||||
import { AMAZON_MUSIC, APPLE_MUSIC, AUDIBLE } from "./music_services";
|
||||
|
||||
import sonos, { SONOS_DISABLED, asDevice, Device, servicesFrom } from "../src/sonos";
|
||||
|
||||
const mockSonosManagerConstructor = <jest.Mock<SonosManager>>SonosManager;
|
||||
|
||||
describe("sonos", () => {
|
||||
beforeEach(() => {
|
||||
mockSonosManagerConstructor.mockClear();
|
||||
});
|
||||
|
||||
describe("asDevice", () => {
|
||||
it("should convert", async () => {
|
||||
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(await asDevice(device)).toEqual({
|
||||
name: "d1",
|
||||
group: "g1",
|
||||
ip: "127.0.0.222",
|
||||
port: 123,
|
||||
services: [
|
||||
{
|
||||
name: AMAZON_MUSIC.Name,
|
||||
id: AMAZON_MUSIC.Id,
|
||||
},
|
||||
{
|
||||
name: APPLE_MUSIC.Name,
|
||||
id: APPLE_MUSIC.Id,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function someDevice(params: Partial<Device> = {}): Device {
|
||||
const device = {
|
||||
name: "device123",
|
||||
group: "",
|
||||
ip: "127.0.0.11",
|
||||
port: 123,
|
||||
services: [],
|
||||
};
|
||||
return { ...device, ...params };
|
||||
}
|
||||
|
||||
describe("servicesFrom", () => {
|
||||
it("should only return uniq services", () => {
|
||||
const service1 = { id: 1, name: "service1" };
|
||||
const service2 = { id: 2, name: "service2" };
|
||||
const service3 = { id: 3, name: "service3" };
|
||||
const service4 = { id: 4, name: "service4" };
|
||||
|
||||
const d1 = someDevice({ services: [service1, service2] });
|
||||
const d2 = someDevice({ services: [service1, service2, service3] });
|
||||
const d3 = someDevice({ services: [service4] });
|
||||
|
||||
const devices: Device[] = [d1, d2, d3];
|
||||
|
||||
expect(servicesFrom(devices)).toEqual([service1, service2, service3, service4])
|
||||
});
|
||||
});
|
||||
|
||||
describe("when is disabled", () => {
|
||||
it("should return a disabled client", async () => {
|
||||
const disabled = sonos("disabled");
|
||||
|
||||
expect(disabled).toEqual(SONOS_DISABLED);
|
||||
expect(await disabled.devices()).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("sonos device discovery", () => {
|
||||
const device1_MusicServicesService = {
|
||||
ListAndParseAvailableServices: jest.fn(),
|
||||
};
|
||||
const device1 = {
|
||||
Name: "device1",
|
||||
GroupName: "group1",
|
||||
Host: "127.0.0.11",
|
||||
Port: 111,
|
||||
MusicServicesService: (device1_MusicServicesService as unknown) as MusicServicesService,
|
||||
} as SonosDevice;
|
||||
|
||||
const device2_MusicServicesService = {
|
||||
ListAndParseAvailableServices: jest.fn(),
|
||||
};
|
||||
const device2 = {
|
||||
Name: "device2",
|
||||
GroupName: "group2",
|
||||
Host: "127.0.0.22",
|
||||
Port: 222,
|
||||
MusicServicesService: (device2_MusicServicesService as unknown) as MusicServicesService,
|
||||
} as SonosDevice;
|
||||
|
||||
beforeEach(() => {
|
||||
device1_MusicServicesService.ListAndParseAvailableServices.mockClear();
|
||||
device2_MusicServicesService.ListAndParseAvailableServices.mockClear();
|
||||
});
|
||||
|
||||
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(undefined).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("").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(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);
|
||||
|
||||
device1_MusicServicesService.ListAndParseAvailableServices.mockResolvedValue(
|
||||
[AMAZON_MUSIC, APPLE_MUSIC]
|
||||
);
|
||||
device2_MusicServicesService.ListAndParseAvailableServices.mockResolvedValue(
|
||||
[AUDIBLE]
|
||||
);
|
||||
|
||||
const actualDevices = await sonos(undefined).devices();
|
||||
|
||||
expect(
|
||||
device1_MusicServicesService.ListAndParseAvailableServices
|
||||
).toHaveBeenCalled();
|
||||
expect(
|
||||
device2_MusicServicesService.ListAndParseAvailableServices
|
||||
).toHaveBeenCalled();
|
||||
|
||||
expect(actualDevices).toEqual([
|
||||
{
|
||||
name: device1.Name,
|
||||
group: device1.GroupName,
|
||||
ip: device1.Host,
|
||||
port: device1.Port,
|
||||
services: [
|
||||
{
|
||||
name: AMAZON_MUSIC.Name,
|
||||
id: AMAZON_MUSIC.Id,
|
||||
},
|
||||
{
|
||||
name: APPLE_MUSIC.Name,
|
||||
id: APPLE_MUSIC.Id,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: device2.Name,
|
||||
group: device2.GroupName,
|
||||
ip: device2.Host,
|
||||
port: device2.Port,
|
||||
services: [
|
||||
{
|
||||
name: AUDIBLE.Name,
|
||||
id: AUDIBLE.Id,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when initialisation returns false", () => {
|
||||
it("should return empty []", async () => {
|
||||
const initialize = jest.fn();
|
||||
const sonosManager = {
|
||||
InitializeWithDiscovery: initialize as (
|
||||
x: number
|
||||
) => Promise<boolean>,
|
||||
Devices: [device1, device2],
|
||||
} as SonosManager;
|
||||
|
||||
mockSonosManagerConstructor.mockReturnValue(sonosManager);
|
||||
initialize.mockResolvedValue(false);
|
||||
|
||||
const actualDevices = await sonos("").devices();
|
||||
|
||||
expect(SonosManager).toHaveBeenCalledTimes(1);
|
||||
expect(initialize).toHaveBeenCalledWith(10);
|
||||
|
||||
expect(actualDevices).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when getting devices fails", () => {
|
||||
it("should return empty []", async () => {
|
||||
const initialize = jest.fn();
|
||||
|
||||
const sonosManager = ({
|
||||
InitializeWithDiscovery: initialize as (
|
||||
x: number
|
||||
) => Promise<boolean>,
|
||||
Devices: () => {
|
||||
throw Error("Boom");
|
||||
},
|
||||
} as unknown) as SonosManager;
|
||||
|
||||
mockSonosManagerConstructor.mockReturnValue(sonosManager);
|
||||
initialize.mockResolvedValue(true);
|
||||
|
||||
const actualDevices = await sonos("").devices();
|
||||
|
||||
expect(SonosManager).toHaveBeenCalledTimes(1);
|
||||
expect(initialize).toHaveBeenCalledWith(10);
|
||||
|
||||
expect(actualDevices).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user