mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Add i8n support for nl-NL (#19)
This commit is contained in:
149
tests/i8n.test.ts
Normal file
149
tests/i8n.test.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import i8n, { langs, LANG, KEY, keys, asLANGs } from "../src/i8n";
|
||||
|
||||
describe("i8n", () => {
|
||||
describe("asLANGs", () => {
|
||||
describe("when the value is empty string", () => {
|
||||
it("should return an empty array", () => {
|
||||
expect(asLANGs("")).toEqual([]);
|
||||
expect(asLANGs(";q=0.9,en;q=0.8")).toEqual([]);
|
||||
});
|
||||
});
|
||||
describe("when the value is undefined", () => {
|
||||
it("should return an empty array", () => {
|
||||
expect(asLANGs(undefined)).toEqual([]);
|
||||
});
|
||||
});
|
||||
describe("when there are multiple in the accept-langauge header", () => {
|
||||
it("should split them out and return them", () => {
|
||||
expect(asLANGs("en-GB,en-US;q=0.9,en;q=0.8")).toEqual([
|
||||
"en-GB",
|
||||
"en-US",
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("langs", () => {
|
||||
it("should be all langs that are explicitly defined", () => {
|
||||
expect(langs()).toEqual(["en-US", "nl-NL"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validity of translations", () => {
|
||||
it("all langs should have same keys as US", () => {
|
||||
langs().forEach((l) => {
|
||||
expect(keys(l as LANG)).toEqual(keys("en-US"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("keys", () => {
|
||||
it("should equal the keys of en-US", () => {
|
||||
expect(keys()).toEqual(keys("en-US"));
|
||||
});
|
||||
});
|
||||
|
||||
describe("fetching translations", () => {
|
||||
describe("with a single lang", () => {
|
||||
describe("and there is no templating", () => {
|
||||
it("should return the value", () => {
|
||||
expect(i8n("foo")("en-US")("artists")).toEqual("Artists");
|
||||
expect(i8n("foo")("nl-NL")("artists")).toEqual("Artiesten");
|
||||
});
|
||||
});
|
||||
|
||||
describe("and there is templating of the service name", () => {
|
||||
it("should return the value", () => {
|
||||
expect(i8n("service123")("en-US")("AppLinkMessage")).toEqual(
|
||||
"Linking sonos with service123"
|
||||
);
|
||||
expect(i8n("service456")("nl-NL")("AppLinkMessage")).toEqual(
|
||||
"Sonos koppelen aan service456"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("with multiple langs", () => {
|
||||
describe("and the first lang is a match", () => {
|
||||
describe("and there is no templating", () => {
|
||||
it("should return the value for the first lang", () => {
|
||||
expect(i8n("foo")("en-US", "nl-NL")("artists")).toEqual("Artists");
|
||||
expect(i8n("foo")("nl-NL", "en-US")("artists")).toEqual("Artiesten");
|
||||
});
|
||||
});
|
||||
|
||||
describe("and there is templating of the service name", () => {
|
||||
it("should return the value for the firt lang", () => {
|
||||
expect(i8n("service123")("en-US", "nl-NL")("AppLinkMessage")).toEqual(
|
||||
"Linking sonos with service123"
|
||||
);
|
||||
expect(i8n("service456")("nl-NL", "en-US")("AppLinkMessage")).toEqual(
|
||||
"Sonos koppelen aan service456"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("and the first lang is not a match, however there is a match in the provided langs", () => {
|
||||
describe("and there is no templating", () => {
|
||||
it("should return the value for the first lang", () => {
|
||||
expect(i8n("foo")("something", "en-US", "nl-NL")("artists")).toEqual("Artists");
|
||||
expect(i8n("foo")("something", "nl-NL", "en-US")("artists")).toEqual("Artiesten");
|
||||
});
|
||||
});
|
||||
|
||||
describe("and there is templating of the service name", () => {
|
||||
it("should return the value for the firt lang", () => {
|
||||
expect(i8n("service123")("something", "en-US", "nl-NL")("AppLinkMessage")).toEqual(
|
||||
"Linking sonos with service123"
|
||||
);
|
||||
expect(i8n("service456")("something", "nl-NL", "en-US")("AppLinkMessage")).toEqual(
|
||||
"Sonos koppelen aan service456"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("and no lang is a match", () => {
|
||||
describe("and there is no templating", () => {
|
||||
it("should return the value for the first lang", () => {
|
||||
expect(i8n("foo")("something", "something2")("artists")).toEqual("Artists");
|
||||
});
|
||||
});
|
||||
|
||||
describe("and there is templating of the service name", () => {
|
||||
it("should return the value for the firt lang", () => {
|
||||
expect(i8n("service123")("something", "something2")("AppLinkMessage")).toEqual(
|
||||
"Linking sonos with service123"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the lang exists but the KEY doesnt", () => {
|
||||
it("should blow up", () => {
|
||||
expect(() => i8n("foo")("en-US")("foobar123" as KEY)).toThrowError(
|
||||
"No translation found for en-US:foobar123"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when the lang is not represented", () => {
|
||||
describe("and there is no templating", () => {
|
||||
it("should return the en-US value", () => {
|
||||
expect(i8n("foo")("en-AU" as LANG)("artists")).toEqual("Artists");
|
||||
});
|
||||
});
|
||||
|
||||
describe("and there is templating of the service name", () => {
|
||||
it("should return the en-US value templated", () => {
|
||||
expect(i8n("service123")("en-AU" as LANG)("AppLinkMessage")).toEqual(
|
||||
"Linking sonos with service123"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -11,11 +11,12 @@ import { SONOS_DISABLED, Sonos, Device } from "../src/sonos";
|
||||
|
||||
import { aDevice, aService } from "./builders";
|
||||
import { InMemoryMusicService } from "./in_memory_music_service";
|
||||
import { ExpiringAccessTokens } from "../src/access_tokens";
|
||||
import { InMemoryLinkCodes } from "../src/link_codes";
|
||||
import { AccessTokens, ExpiringAccessTokens } from "../src/access_tokens";
|
||||
import { InMemoryLinkCodes, LinkCodes } from "../src/link_codes";
|
||||
import { Response } from "express";
|
||||
import { Transform } from "stream";
|
||||
import url from "../src/url_builder";
|
||||
import i8n, { randomLang } from "../src/i8n";
|
||||
|
||||
describe("rangeFilterFor", () => {
|
||||
describe("invalid range header string", () => {
|
||||
@@ -163,6 +164,11 @@ describe("server", () => {
|
||||
const bonobUrlWithNoContextPath = url("http://bonob.localhost:1234");
|
||||
const bonobUrlWithContextPath = url("http://bonob.localhost:1234/aContext");
|
||||
|
||||
const langName = randomLang();
|
||||
const acceptLanguage = `le-ET,${langName};q=0.9,en;q=0.8`;
|
||||
const serviceNameForLang = "Foo Service";
|
||||
const lang = i8n(serviceNameForLang)(langName);
|
||||
|
||||
[bonobUrlWithNoContextPath, bonobUrlWithContextPath].forEach((bonobUrl) => {
|
||||
describe(`a bonobUrl of ${bonobUrl}`, () => {
|
||||
describe("/", () => {
|
||||
@@ -239,9 +245,11 @@ describe("server", () => {
|
||||
it("should contain the devices returned from sonos", async () => {
|
||||
const res = await request(server)
|
||||
.get(bonobUrl.append({ pathname: "/" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch(`<h2>${lang("devices")} \(2\)</h2>`);
|
||||
expect(res.text).toMatch(/device1\s+\(172.0.0.1:4301\)/);
|
||||
expect(res.text).toMatch(/device2\s+\(172.0.0.2:4302\)/);
|
||||
});
|
||||
@@ -251,10 +259,11 @@ describe("server", () => {
|
||||
it("should contain a list of services returned from sonos", async () => {
|
||||
const res = await request(server)
|
||||
.get(bonobUrl.append({ pathname: "/" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch(/Services\s+4/);
|
||||
expect(res.text).toMatch(`<h2>${lang("services")} \(4\)</h2>`);
|
||||
expect(res.text).toMatch(/s1\s+\(1\)/);
|
||||
expect(res.text).toMatch(/s2\s+\(2\)/);
|
||||
expect(res.text).toMatch(/s3\s+\(3\)/);
|
||||
@@ -266,9 +275,13 @@ describe("server", () => {
|
||||
it("should be not-registered", async () => {
|
||||
const res = await request(server)
|
||||
.get(bonobUrl.append({ pathname: "/" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch(/No existing service registration/);
|
||||
expect(res.text).toMatch(`<input type="submit" value="${lang("register")}">`);
|
||||
expect(res.text).toMatch(`<h3>${lang("expectedConfig")}</h3>`);
|
||||
expect(res.text).toMatch(`<h3>${lang("noExistingServiceRegistration")}</h3>`);
|
||||
expect(res.text).not.toMatch(`<input type="submit" value="${lang("removeRegistration")}">`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -301,9 +314,13 @@ describe("server", () => {
|
||||
it("should be registered", async () => {
|
||||
const res = await request(server)
|
||||
.get(bonobUrl.append({ pathname: "/" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch(/Existing service config/);
|
||||
expect(res.text).toMatch(`<input type="submit" value="${lang("register")}">`);
|
||||
expect(res.text).toMatch(`<h3>${lang("expectedConfig")}</h3>`);
|
||||
expect(res.text).toMatch(`<h3>${lang("existingServiceConfig")}</h3>`);
|
||||
expect(res.text).toMatch(`<input type="submit" value="${lang("removeRegistration")}">`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -334,8 +351,7 @@ describe("server", () => {
|
||||
service: {
|
||||
name: theService.name,
|
||||
sid: theService.sid
|
||||
}
|
||||
});
|
||||
}});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -362,10 +378,12 @@ describe("server", () => {
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: "/registration/add" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch("Successfully registered");
|
||||
expect(res.text).toMatch(`<title>${lang("success")}</title>`);
|
||||
expect(res.text).toMatch(lang("successfullyRegistered"));
|
||||
|
||||
expect(sonos.register.mock.calls.length).toEqual(1);
|
||||
expect(sonos.register.mock.calls[0][0]).toBe(theService);
|
||||
@@ -375,13 +393,15 @@ describe("server", () => {
|
||||
describe("when is unsuccessful", () => {
|
||||
it("should return a failure message", async () => {
|
||||
sonos.register.mockResolvedValue(false);
|
||||
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: "/registration/add" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
|
||||
expect(res.status).toEqual(500);
|
||||
expect(res.text).toMatch("Registration failed!");
|
||||
expect(res.text).toMatch(`<title>${lang("failure")}</title>`);
|
||||
expect(res.text).toMatch(lang("registrationFailed"));
|
||||
|
||||
expect(sonos.register.mock.calls.length).toEqual(1);
|
||||
expect(sonos.register.mock.calls[0][0]).toBe(theService);
|
||||
@@ -396,10 +416,12 @@ describe("server", () => {
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: "/registration/remove" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch("Successfully removed registration");
|
||||
expect(res.text).toMatch(`<title>${lang("success")}</title>`);
|
||||
expect(res.text).toMatch(lang("successfullyRemovedRegistration"));
|
||||
|
||||
expect(sonos.remove.mock.calls.length).toEqual(1);
|
||||
expect(sonos.remove.mock.calls[0][0]).toBe(theService.sid);
|
||||
@@ -412,10 +434,12 @@ describe("server", () => {
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: "/registration/remove" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
|
||||
expect(res.status).toEqual(500);
|
||||
expect(res.text).toMatch("Failed to remove registration!");
|
||||
expect(res.text).toMatch(`<title>${lang("failure")}</title>`);
|
||||
expect(res.text).toMatch(lang("failedToRemoveRegistration"));
|
||||
|
||||
expect(sonos.remove.mock.calls.length).toEqual(1);
|
||||
expect(sonos.remove.mock.calls[0][0]).toBe(theService.sid);
|
||||
@@ -424,6 +448,138 @@ describe("server", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("/login", () => {
|
||||
const sonos = {
|
||||
register: jest.fn(),
|
||||
remove: jest.fn(),
|
||||
};
|
||||
const theService = aService({
|
||||
name: serviceNameForLang
|
||||
});
|
||||
|
||||
const musicService = {
|
||||
generateToken: jest.fn(),
|
||||
login: jest.fn(),
|
||||
};
|
||||
const linkCodes = {
|
||||
mint: jest.fn(),
|
||||
has: jest.fn(),
|
||||
associate: jest.fn(),
|
||||
associationFor: jest.fn(),
|
||||
};
|
||||
const accessTokens = {
|
||||
mint: jest.fn(),
|
||||
authTokenFor: jest.fn(),
|
||||
};
|
||||
const clock = {
|
||||
now: jest.fn(),
|
||||
};
|
||||
|
||||
|
||||
const server = makeServer(
|
||||
sonos as unknown as Sonos,
|
||||
theService,
|
||||
bonobUrl,
|
||||
musicService as unknown as MusicService,
|
||||
linkCodes as unknown as LinkCodes,
|
||||
accessTokens as unknown as AccessTokens,
|
||||
clock
|
||||
);
|
||||
|
||||
it("should return the login page", async () => {
|
||||
sonos.register.mockResolvedValue(true);
|
||||
|
||||
const res = await request(server)
|
||||
.get(bonobUrl.append({ pathname: "/login" }).path())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.send();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.text).toMatch(`<title>${lang("login")}</title>`);
|
||||
expect(res.text).toMatch(`<h1 class="login one-word-per-line">${lang("logInToBonob")}</h1>`);
|
||||
expect(res.text).toMatch(`<label for="username">${lang("username")}:</label>`);
|
||||
expect(res.text).toMatch(`<label for="password">${lang("password")}:</label>`);
|
||||
expect(res.text).toMatch(`<input type="submit" value="${lang("login")}" id="submit">`);
|
||||
});
|
||||
|
||||
describe("when the credentials are valid", () => {
|
||||
it("should return 200 ok and have associated linkCode with user", async () => {
|
||||
const username = "jane";
|
||||
const password = "password100";
|
||||
const linkCode = `linkCode-${uuid()}`;
|
||||
const authToken = {
|
||||
authToken: `authtoken-${uuid()}`,
|
||||
userId: `${username}-uid`,
|
||||
nickname: `${username}-nickname`,
|
||||
};
|
||||
|
||||
linkCodes.has.mockReturnValue(true);
|
||||
musicService.generateToken.mockResolvedValue(authToken);
|
||||
linkCodes.associate.mockReturnValue(true);
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: "/login" }).pathname())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.type("form")
|
||||
.send({ username, password, linkCode })
|
||||
.expect(200);
|
||||
|
||||
expect(res.text).toContain(lang("loginSuccessful"));
|
||||
|
||||
expect(musicService.generateToken).toHaveBeenCalledWith({
|
||||
username,
|
||||
password,
|
||||
});
|
||||
expect(linkCodes.has).toHaveBeenCalledWith(linkCode);
|
||||
expect(linkCodes.associate).toHaveBeenCalledWith(
|
||||
linkCode,
|
||||
authToken
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when credentials are invalid", () => {
|
||||
it("should return 403 with message", async () => {
|
||||
const username = "userDoesntExist";
|
||||
const password = "password";
|
||||
const linkCode = uuid();
|
||||
const message = `Invalid user:${username}`;
|
||||
|
||||
linkCodes.has.mockReturnValue(true);
|
||||
musicService.generateToken.mockResolvedValue({ message });
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: "/login" }).pathname())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.type("form")
|
||||
.send({ username, password, linkCode })
|
||||
.expect(403);
|
||||
|
||||
expect(res.text).toContain(lang("loginFailed"));
|
||||
expect(res.text).toContain(message);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when linkCode is invalid", () => {
|
||||
it("should return 400 with message", async () => {
|
||||
const username = "jane";
|
||||
const password = "password100";
|
||||
const linkCode = "someLinkCodeThatDoesntExist";
|
||||
|
||||
linkCodes.has.mockReturnValue(false);
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: "/login" }).pathname())
|
||||
.set("accept-language", acceptLanguage)
|
||||
.type("form")
|
||||
.send({ username, password, linkCode })
|
||||
.expect(400);
|
||||
|
||||
expect(res.text).toContain(lang("invalidLinkCode"));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("/stream", () => {
|
||||
const musicService = {
|
||||
login: jest.fn(),
|
||||
|
||||
@@ -9,10 +9,9 @@ import { randomInt } from "crypto";
|
||||
|
||||
import { LinkCodes } from "../src/link_codes";
|
||||
import makeServer from "../src/server";
|
||||
import { bonobService, SONOS_DISABLED } from "../src/sonos";
|
||||
import { bonobService, SONOS_DISABLED, SONOS_LANG } from "../src/sonos";
|
||||
import {
|
||||
STRINGS_ROUTE,
|
||||
LOGIN_ROUTE,
|
||||
getMetadataResult,
|
||||
PRESENTATION_MAP_ROUTE,
|
||||
SONOS_RECOMMENDED_IMAGE_SIZES,
|
||||
@@ -68,15 +67,19 @@ describe("service config", () => {
|
||||
});
|
||||
|
||||
describe(`${stringsUrl}`, () => {
|
||||
it("should return xml for the strings", async () => {
|
||||
async function fetchStringsXml() {
|
||||
const res = await request(server).get(stringsUrl.path()).send();
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
|
||||
// removing the sonos xml ns as makes xpath queries with xpath-ts painful
|
||||
const xml = parseXML(
|
||||
return parseXML(
|
||||
res.text.replace('xmlns="http://sonos.com/sonosapi"', "")
|
||||
);
|
||||
}
|
||||
|
||||
it("should return xml for the strings", async () => {
|
||||
const xml = await fetchStringsXml();
|
||||
|
||||
const sonosString = (id: string, lang: string) =>
|
||||
xpath.select(
|
||||
@@ -87,9 +90,24 @@ describe("service config", () => {
|
||||
expect(sonosString("AppLinkMessage", "en-US")).toEqual(
|
||||
"Linking sonos with music land"
|
||||
);
|
||||
expect(sonosString("AppLinkMessage", "fr-FR")).toEqual(
|
||||
"Lier les sonos à la music land"
|
||||
expect(sonosString("AppLinkMessage", "nl-NL")).toEqual(
|
||||
"Sonos koppelen aan music land"
|
||||
);
|
||||
|
||||
// no fr-FR translation, so use en-US
|
||||
expect(sonosString("AppLinkMessage", "fr-FR")).toEqual(
|
||||
"Linking sonos with music land"
|
||||
);
|
||||
});
|
||||
|
||||
it("should return a section for all sonos supported languages", async () => {
|
||||
const xml = await fetchStringsXml();
|
||||
SONOS_LANG.forEach(lang => {
|
||||
expect(xpath.select(
|
||||
`string(/stringtables/stringtable[@xml:lang="${lang}"]/string[@stringId="AppLinkMessage"])`,
|
||||
xml
|
||||
)).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -345,83 +363,6 @@ describe("api", () => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe("pages", () => {
|
||||
describe(bonobUrl.append({ pathname: LOGIN_ROUTE }).href(), () => {
|
||||
describe("when the credentials are valid", () => {
|
||||
it("should return 200 ok and have associated linkCode with user", async () => {
|
||||
const username = "jane";
|
||||
const password = "password100";
|
||||
const linkCode = `linkCode-${uuid()}`;
|
||||
const authToken = {
|
||||
authToken: `authtoken-${uuid()}`,
|
||||
userId: `${username}-uid`,
|
||||
nickname: `${username}-nickname`,
|
||||
};
|
||||
|
||||
linkCodes.has.mockReturnValue(true);
|
||||
musicService.generateToken.mockResolvedValue(authToken);
|
||||
linkCodes.associate.mockReturnValue(true);
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: LOGIN_ROUTE }).pathname())
|
||||
.type("form")
|
||||
.send({ username, password, linkCode })
|
||||
.expect(200);
|
||||
|
||||
expect(res.text).toContain("Login successful");
|
||||
|
||||
expect(musicService.generateToken).toHaveBeenCalledWith({
|
||||
username,
|
||||
password,
|
||||
});
|
||||
expect(linkCodes.has).toHaveBeenCalledWith(linkCode);
|
||||
expect(linkCodes.associate).toHaveBeenCalledWith(
|
||||
linkCode,
|
||||
authToken
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when credentials are invalid", () => {
|
||||
it("should return 403 with message", async () => {
|
||||
const username = "userDoesntExist";
|
||||
const password = "password";
|
||||
const linkCode = uuid();
|
||||
const message = `Invalid user:${username}`;
|
||||
|
||||
linkCodes.has.mockReturnValue(true);
|
||||
musicService.generateToken.mockResolvedValue({ message });
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: LOGIN_ROUTE }).pathname())
|
||||
.type("form")
|
||||
.send({ username, password, linkCode })
|
||||
.expect(403);
|
||||
|
||||
expect(res.text).toContain(`Login failed! ${message}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when linkCode is invalid", () => {
|
||||
it("should return 400 with message", async () => {
|
||||
const username = "jane";
|
||||
const password = "password100";
|
||||
const linkCode = "someLinkCodeThatDoesntExist";
|
||||
|
||||
linkCodes.has.mockReturnValue(false);
|
||||
|
||||
const res = await request(server)
|
||||
.post(bonobUrl.append({ pathname: LOGIN_ROUTE }).pathname())
|
||||
.type("form")
|
||||
.send({ username, password, linkCode })
|
||||
.expect(400);
|
||||
|
||||
expect(res.text).toContain("Invalid linkCode!");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("soap api", () => {
|
||||
describe("getAppLink", () => {
|
||||
it("should do something", async () => {
|
||||
@@ -755,62 +696,125 @@ describe("api", () => {
|
||||
});
|
||||
|
||||
describe("asking for the root container", () => {
|
||||
it("should return it", async () => {
|
||||
const root = await ws.getMetadataAsync({
|
||||
id: "root",
|
||||
index: 0,
|
||||
count: 100,
|
||||
});
|
||||
expect(root[0]).toEqual(
|
||||
getMetadataResult({
|
||||
mediaCollection: [
|
||||
{
|
||||
itemType: "container",
|
||||
id: "artists",
|
||||
title: "Artists",
|
||||
},
|
||||
{ itemType: "albumList", id: "albums", title: "Albums" },
|
||||
{
|
||||
itemType: "playlist",
|
||||
id: "playlists",
|
||||
title: "Playlists",
|
||||
attributes: {
|
||||
readOnly: "false",
|
||||
renameable: "false",
|
||||
userContent: "true",
|
||||
},
|
||||
},
|
||||
{ itemType: "container", id: "genres", title: "Genres" },
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "randomAlbums",
|
||||
title: "Random",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "starredAlbums",
|
||||
title: "Starred",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "recentlyAdded",
|
||||
title: "Recently Added",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "recentlyPlayed",
|
||||
title: "Recently Played",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "mostPlayed",
|
||||
title: "Most Played",
|
||||
},
|
||||
],
|
||||
describe("when no accept-language header is present", () => {
|
||||
it("should return en-US", async () => {
|
||||
const root = await ws.getMetadataAsync({
|
||||
id: "root",
|
||||
index: 0,
|
||||
total: 9,
|
||||
})
|
||||
);
|
||||
count: 100,
|
||||
});
|
||||
expect(root[0]).toEqual(
|
||||
getMetadataResult({
|
||||
mediaCollection: [
|
||||
{
|
||||
itemType: "container",
|
||||
id: "artists",
|
||||
title: "Artists",
|
||||
},
|
||||
{ itemType: "albumList", id: "albums", title: "Albums" },
|
||||
{
|
||||
itemType: "playlist",
|
||||
id: "playlists",
|
||||
title: "Playlists",
|
||||
attributes: {
|
||||
readOnly: "false",
|
||||
renameable: "false",
|
||||
userContent: "true",
|
||||
},
|
||||
},
|
||||
{ itemType: "container", id: "genres", title: "Genres" },
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "randomAlbums",
|
||||
title: "Random",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "starredAlbums",
|
||||
title: "Starred",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "recentlyAdded",
|
||||
title: "Recently added",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "recentlyPlayed",
|
||||
title: "Recently played",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "mostPlayed",
|
||||
title: "Most played",
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
total: 9,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when an accept-language header is present with value nl-NL", () => {
|
||||
it("should return nl-NL", async () => {
|
||||
ws.addHttpHeader("accept-language", "nl-NL")
|
||||
const root = await ws.getMetadataAsync({
|
||||
id: "root",
|
||||
index: 0,
|
||||
count: 100,
|
||||
});
|
||||
expect(root[0]).toEqual(
|
||||
getMetadataResult({
|
||||
mediaCollection: [
|
||||
{
|
||||
itemType: "container",
|
||||
id: "artists",
|
||||
title: "Artiesten",
|
||||
},
|
||||
{ itemType: "albumList", id: "albums", title: "Albums" },
|
||||
{
|
||||
itemType: "playlist",
|
||||
id: "playlists",
|
||||
title: "Afspeellijsten",
|
||||
attributes: {
|
||||
readOnly: "false",
|
||||
renameable: "false",
|
||||
userContent: "true",
|
||||
},
|
||||
},
|
||||
{ itemType: "container", id: "genres", title: "Genres" },
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "randomAlbums",
|
||||
title: "Willekeurig",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "starredAlbums",
|
||||
title: "Favorieten",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "recentlyAdded",
|
||||
title: "Onlangs toegevoegd",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "recentlyPlayed",
|
||||
title: "Onlangs afgespeeld",
|
||||
},
|
||||
{
|
||||
itemType: "albumList",
|
||||
id: "mostPlayed",
|
||||
title: "Meest afgespeeld",
|
||||
},
|
||||
],
|
||||
index: 0,
|
||||
total: 9,
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user