diff --git a/client/js/libs/handlebars/roundBadgeNumber.js b/client/js/libs/handlebars/roundBadgeNumber.js
index 97c50afa..34c18c96 100644
--- a/client/js/libs/handlebars/roundBadgeNumber.js
+++ b/client/js/libs/handlebars/roundBadgeNumber.js
@@ -2,7 +2,7 @@
module.exports = function(count) {
if (count < 1000) {
- return count;
+ return count.toString();
}
return (count / 1000).toFixed(2).slice(0, -1) + "k";
diff --git a/client/js/libs/handlebars/tojson.js b/client/js/libs/handlebars/tojson.js
index 418ac8c4..0078fbff 100644
--- a/client/js/libs/handlebars/tojson.js
+++ b/client/js/libs/handlebars/tojson.js
@@ -1,5 +1,5 @@
"use strict";
-module.exports = function(context) {
- return window.JSON.stringify(context);
+module.exports = function tojson(context) {
+ return JSON.stringify(context);
};
diff --git a/test/client/js/constantsTest.js b/test/client/js/constantsTest.js
new file mode 100644
index 00000000..5c44253f
--- /dev/null
+++ b/test/client/js/constantsTest.js
@@ -0,0 +1,61 @@
+"use strict";
+
+const expect = require("chai").expect;
+const constants = require("../../../client/js/constants");
+
+describe("client-side constants", function() {
+ describe(".colorCodeMap", function() {
+ it("should be a non-empty array", function() {
+ expect(constants.colorCodeMap).to.be.an("array").of.length(16);
+ });
+
+ it("should be made of pairs of strings", function() {
+ constants.colorCodeMap.forEach((tuple) => { // TODO: In Node v6+, use `[code, name]`
+ expect(tuple[0]).to.be.a("string").that.match(/[0-9]{2}/);
+ expect(tuple[1]).to.be.a("string");
+ });
+ });
+ });
+
+ describe(".commands", function() {
+ it("should be a non-empty array", function() {
+ expect(constants.commands).to.be.an("array").that.is.not.empty;
+ });
+
+ it("should only contain strings with no whitespaces and starting with /", function() {
+ constants.commands.forEach((command) => {
+ expect(command).to.be.a("string").that.does.not.match(/\s/);
+ expect(command[0]).to.equal("/");
+ });
+ });
+ });
+
+ describe(".actionTypes", function() {
+ it("should be a non-empty array", function() {
+ expect(constants.actionTypes).to.be.an("array").that.is.not.empty;
+ });
+
+ it("should only contain strings with no whitespaces", function() {
+ constants.actionTypes.forEach((type) => {
+ expect(type).to.be.a("string").that.does.not.match(/\s/);
+ });
+ });
+ });
+
+ describe(".condensedTypes", function() {
+ it("should be a non-empty array", function() {
+ expect(constants.condensedTypes).to.be.an("array").that.is.not.empty;
+ });
+
+ it("should be a subset of `actionTypes`", function() {
+ expect(constants.actionTypes).to.include.members(constants.condensedTypes);
+ });
+ });
+
+ describe(".timeFormats", function() {
+ it("should be objects of strings", function() {
+ expect(constants.timeFormats.msgDefault).to.be.an("string").that.is.not.empty;
+ expect(constants.timeFormats.msgWithSeconds).to.be.an("string").that.is.not.empty;
+ });
+ });
+});
diff --git a/test/client/js/libs/handlebars/localedateTest.js b/test/client/js/libs/handlebars/localedateTest.js
new file mode 100644
index 00000000..f7cacc30
--- /dev/null
+++ b/test/client/js/libs/handlebars/localedateTest.js
@@ -0,0 +1,19 @@
+"use strict";
+
+const expect = require("chai").expect;
+const localedate = require("../../../../../client/js/libs/handlebars/localedate");
+
+describe("localedate Handlebars helper", function() {
+ it("should render a human-readable date", function() {
+ // 12PM in UTC time
+ const date = new Date("2014-05-22T12:00:00Z");
+
+ // Offset between UTC and local timezone
+ const offset = date.getTimezoneOffset() * 60 * 1000;
+
+ // Pretend local timezone is UTC by moving the clock of that offset
+ const time = date.getTime() + offset;
+
+ expect(localedate(time)).to.equal("22 May 2014");
+ });
+});
diff --git a/test/client/js/libs/handlebars/modesTest.js b/test/client/js/libs/handlebars/modesTest.js
new file mode 100644
index 00000000..f0a18016
--- /dev/null
+++ b/test/client/js/libs/handlebars/modesTest.js
@@ -0,0 +1,23 @@
+"use strict";
+
+const expect = require("chai").expect;
+const modes = require("../../../../../client/js/libs/handlebars/modes");
+
+describe("modes Handlebars helper", function() {
+ it("should return text modes based on symbols", function() {
+ expect(modes("~")).to.equal("owner");
+ expect(modes("&")).to.equal("admin");
+ expect(modes("!")).to.equal("admin");
+ expect(modes("@")).to.equal("op");
+ expect(modes("%")).to.equal("half-op");
+ expect(modes("+")).to.equal("voice");
+ });
+
+ it("should return no special mode when given an empty string", function() {
+ expect(modes("")).to.equal("normal");
+ });
+
+ it("should return nothing if the symbol does not exist", function() {
+ expect(modes("?")).to.be.undefined;
+ });
+});
diff --git a/test/client/js/libs/handlebars/parse.js b/test/client/js/libs/handlebars/parse.js
index 8b168780..2d26976f 100644
--- a/test/client/js/libs/handlebars/parse.js
+++ b/test/client/js/libs/handlebars/parse.js
@@ -203,44 +203,57 @@ describe("parse Handlebars helper", () => {
expect(actual).to.deep.equal(expected);
});
- it("should style like mirc", () => {
- const testCases = [{
- input: "\x02bold",
- expected: 'bold',
- }, {
- input: "\x038yellowText",
- expected: 'yellowText',
- }, {
- input: "\x030,0white,white",
- expected: 'white,white',
- }, {
- input: "\x034,8yellowBGredText",
- expected: 'yellowBGredText',
- }, {
- input: "\x1ditalic",
- expected: 'italic',
- }, {
- input: "\x1funderline",
- expected: 'underline',
- }, {
- input: "\x02bold\x038yellow\x02nonBold\x03default",
- expected:
- 'bold' +
- 'yellow' +
- 'nonBold' +
- "default",
- }, {
- input: "\x02bold\x02 \x02bold\x02",
- expected:
- 'bold' +
- " " +
- 'bold',
- }];
-
- const actual = testCases.map((testCase) => parse(testCase.input));
- const expected = testCases.map((testCase) => testCase.expected);
-
- expect(actual).to.deep.equal(expected);
+ [{
+ name: "bold",
+ input: "\x02bold",
+ expected: 'bold',
+ }, {
+ name: "foreground color",
+ input: "\x038yellowText",
+ expected: 'yellowText',
+ }, {
+ name: "foreground and background colors (white)",
+ input: "\x030,0white,white",
+ expected: 'white,white',
+ }, {
+ name: "foreground and background colors",
+ input: "\x034,8yellowBGredText",
+ expected: 'yellowBGredText',
+ }, {
+ name: "hex foreground color",
+ input: "\x04663399rebeccapurple",
+ expected: 'rebeccapurple',
+ }, {
+ name: "hex foreground and background colors",
+ input: "\x04415364,ff9e18The Lounge",
+ expected: 'The Lounge',
+ }, {
+ name: "italic",
+ input: "\x1ditalic",
+ expected: 'italic',
+ }, {
+ name: "underline",
+ input: "\x1funderline",
+ expected: 'underline',
+ }, {
+ name: "resets",
+ input: "\x02bold\x038yellow\x02nonBold\x03default",
+ expected:
+ 'bold' +
+ 'yellow' +
+ 'nonBold' +
+ "default",
+ }, {
+ name: "duplicates",
+ input: "\x02bold\x02 \x02bold\x02",
+ expected:
+ 'bold' +
+ " " +
+ 'bold',
+ }].forEach((item) => { // TODO: In Node v6+, use `{name, input, expected}`
+ it(`should handle style characters: ${item.name}`, function() {
+ expect(parse(item.input)).to.equal(item.expected);
+ });
});
it("should find nicks", () => {
@@ -312,6 +325,36 @@ describe("parse Handlebars helper", () => {
expect(actual).to.deep.equal(expected);
});
+ // Emoji
+ [{
+ name: "in text",
+ input: "Hello💬",
+ expected: 'Hello💬',
+ }, {
+ name: "with modifiers",
+ input: "🤷♀️",
+ expected: '🤷♀️',
+ }, {
+ // FIXME: These multiple `span`s should be optimized into a single one. See https://github.com/thelounge/lounge/issues/1783
+ name: "wrapped in style",
+ input: "Super \x034💚 green!",
+ expected: 'Super 💚 green!',
+ }, {
+ name: "wrapped in URLs",
+ input: "https://i.❤️.thelounge.chat",
+ // FIXME: Emoji in text should be `❤️`. See https://github.com/thelounge/lounge/issues/1784
+ expected: 'https://i.❤️.thelounge.chat',
+ }, {
+ name: "wrapped in channels",
+ input: "#i❤️thelounge",
+ // FIXME: Emoji in text should be `❤️`. See https://github.com/thelounge/lounge/issues/1784
+ expected: '#i❤️thelounge',
+ }].forEach((item) => { // TODO: In Node v6+, use `{name, input, expected}`
+ it(`should find emoji: ${item.name}`, function() {
+ expect(parse(item.input)).to.equal(item.expected);
+ });
+ });
+
it("should optimize generated html", () => {
const testCases = [{
input: 'test \x0312#\x0312\x0312"te\x0312st\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312\x0312a',
diff --git a/test/client/js/libs/handlebars/roundBadgeNumberTest.js b/test/client/js/libs/handlebars/roundBadgeNumberTest.js
new file mode 100644
index 00000000..d514c77a
--- /dev/null
+++ b/test/client/js/libs/handlebars/roundBadgeNumberTest.js
@@ -0,0 +1,24 @@
+"use strict";
+
+const expect = require("chai").expect;
+const roundBadgeNumber = require("../../../../../client/js/libs/handlebars/roundBadgeNumber");
+
+describe("roundBadgeNumber Handlebars helper", function() {
+ it("should return any number under 1000 as a string", function() {
+ expect(roundBadgeNumber(123)).to.equal("123");
+ });
+
+ it("should return numbers above 999 in thousands", function() {
+ expect(roundBadgeNumber(1000)).to.be.equal("1.0k");
+ });
+
+ it("should round and not floor", function() {
+ expect(roundBadgeNumber(9999)).to.be.equal("10.0k");
+ });
+
+ it("should always include a single digit when rounding up", function() {
+ expect(roundBadgeNumber(1234)).to.be.equal("1.2k");
+ expect(roundBadgeNumber(12345)).to.be.equal("12.3k");
+ expect(roundBadgeNumber(123456)).to.be.equal("123.4k");
+ });
+});
diff --git a/test/client/js/libs/handlebars/slugifyTest.js b/test/client/js/libs/handlebars/slugifyTest.js
new file mode 100644
index 00000000..9d945801
--- /dev/null
+++ b/test/client/js/libs/handlebars/slugifyTest.js
@@ -0,0 +1,10 @@
+"use strict";
+
+const expect = require("chai").expect;
+const slugify = require("../../../../../client/js/libs/handlebars/slugify");
+
+describe("slugify Handlebars helper", function() {
+ it("should only produce lowercase strings", function() {
+ expect(slugify("#TheLounge")).to.equal("\\#thelounge");
+ });
+});
diff --git a/test/client/js/libs/handlebars/tojson.js b/test/client/js/libs/handlebars/tojson.js
new file mode 100644
index 00000000..4f25cd86
--- /dev/null
+++ b/test/client/js/libs/handlebars/tojson.js
@@ -0,0 +1,13 @@
+"use strict";
+
+const expect = require("chai").expect;
+const tojson = require("../../../../../client/js/libs/handlebars/tojson");
+
+describe("tojson Handlebars helper", function() {
+ it("should return JSON strings", function() {
+ expect(tojson([])).to.equal("[]");
+ expect(tojson({})).to.equal("{}");
+ expect(tojson("")).to.equal('""');
+ expect(tojson({foo: "bar"})).to.be.equal('{"foo":"bar"}');
+ });
+});