From f368dcdc69b5690a775234a20e88c3a0e2d74aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Astori?= Date: Wed, 29 Nov 2017 00:31:03 -0500 Subject: [PATCH 1/2] Add a bunch of client tests --- client/js/libs/handlebars/roundBadgeNumber.js | 2 +- client/js/libs/handlebars/tojson.js | 4 +- test/client/js/constantsTest.js | 61 +++++++++ .../js/libs/handlebars/localedateTest.js | 19 +++ test/client/js/libs/handlebars/modesTest.js | 23 ++++ test/client/js/libs/handlebars/parse.js | 119 ++++++++++++------ .../libs/handlebars/roundBadgeNumberTest.js | 24 ++++ test/client/js/libs/handlebars/slugifyTest.js | 10 ++ test/client/js/libs/handlebars/tojson.js | 13 ++ 9 files changed, 234 insertions(+), 41 deletions(-) create mode 100644 test/client/js/constantsTest.js create mode 100644 test/client/js/libs/handlebars/localedateTest.js create mode 100644 test/client/js/libs/handlebars/modesTest.js create mode 100644 test/client/js/libs/handlebars/roundBadgeNumberTest.js create mode 100644 test/client/js/libs/handlebars/slugifyTest.js create mode 100644 test/client/js/libs/handlebars/tojson.js 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"}'); + }); +}); From 6bb0251d57b8de34969109f1b3ee3336a2238a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Astori?= Date: Wed, 29 Nov 2017 00:31:15 -0500 Subject: [PATCH 2/2] Ignore coverage folder from coverage report --- .nycrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.nycrc b/.nycrc index 03b56c0a..3a147dcb 100644 --- a/.nycrc +++ b/.nycrc @@ -1,6 +1,7 @@ { "all": true, "exclude": [ + "coverage", "public/", "test/", "webpack.config.js"