diff --git a/.travis.yml b/.travis.yml index 1e3b6a9f..ec119b78 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: + - "8" - "7" - "6" - "5.1" @@ -12,6 +13,8 @@ script: - grunt - npm run test:unit - npm run test:e2e +after_script: + - npm list cache: directories: - node_modules diff --git a/CHANGELOG.md b/CHANGELOG.md index 90bae37b..aefee995 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,15 +9,19 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Added - Add `clientonly` script to start only the electron client for a remote server. - Add symbol and color properties of event when `CALENDAR_EVENTS` notification is broadcasted from `default/calendar` module. -- Add `.vscode/` folder to `.gitignore` to keep custom Visual Studio Code config out of git +- Add `.vscode/` folder to `.gitignore` to keep custom Visual Studio Code config out of git. +- Add unit test the capitalizeFirstLetter function of newfeed module. +- Add new unit tests for function `shorten` in calendar module. ### Updated -- Changed 'default.js' - listen on all attached interfaces by default +- Changed 'default.js' - listen on all attached interfaces by default. +- Add execution of `npm list` after the test are ran in Travis CI. ### Fixed - -- Fixed issue with incorrect allignment of analog clock when displayed in the center column of the MM -- Fixed ipWhitelist behaviour to make empty whitelist ([]) allow any and all hosts access to the MM +- Fixed issue with incorrect allignment of analog clock when displayed in the center column of the MM. +- Fixed ipWhitelist behaviour to make empty whitelist ([]) allow any and all hosts access to the MM. +- Fixed issue with calendar module where 'excludedEvents' count towards 'maximumEntries'. +- Fixed issue with calendar module where global configuration of maximumEntries was not overridden by calendar specific config (see module doc). ## [2.1.2] - 2017-07-01 @@ -47,7 +51,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Updated - Added missing keys to Polish translation. - Added missing key to German translation. -- Added better translation with flexible word order to Finnish translation +- Added better translation with flexible word order to Finnish translation. ### Fixed - Fix instruction in README for using automatically installer script. @@ -55,8 +59,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Fix double message about port when server is starting - Corrected Swedish translations for TODAY/TOMORROW/DAYAFTERTOMORROW. - Removed unused import from js/electron.js -- Made calendar.js respect config.timeFormat irrespecive of locale setting -- Fixed alignment of analog clock when a large calendar is displayed in the same side bar +- Made calendar.js respect config.timeFormat irrespecive of locale setting. +- Fixed alignment of analog clock when a large calendar is displayed in the same side bar. ## [2.1.1] - 2017-04-01 @@ -64,18 +68,18 @@ This project adheres to [Semantic Versioning](http://semver.org/). ### Changed - Add `anytime` group for Compliments module. -- Compliments module can use remoteFile without default daytime arrays defined +- Compliments module can use remoteFile without default daytime arrays defined. - Installer: Use init config.js from config.js.sample. - Switched out `rrule` package for `rrule-alt` and fixes in `ical.js` in order to fix calendar issues. ([#565](https://github.com/MichMich/MagicMirror/issues/565)) - Make mouse events pass through the region fullscreen_above to modules below. - Scaled the splash screen down to make it a bit more subtle. - Replace HTML tables with markdown tables in README files. - Added `DAYAFTERTOMORROW`, `UPDATE_NOTIFICATION` and `UPDATE_NOTIFICATION_MODULE` to Finnish translations. -- Run `npm test` on Travis automatically +- Run `npm test` on Travis automatically. - Show the splash screen image even when is reboot or halted. - Added some missing translaton strings in the sv.json file. - Run task jsonlint to check translation files. -- Restructured Test Suite +- Restructured Test Suite. ### Added - Added Docker support (Pull Request [#673](https://github.com/MichMich/MagicMirror/pull/673)). diff --git a/index.html b/index.html index 85951a85..f3e8d12f 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ - Magic Mirror + MagicMirror² diff --git a/modules/default/calendar/calendar.js b/modules/default/calendar/calendar.js index a5716d77..0b73fa49 100644 --- a/modules/default/calendar/calendar.js +++ b/modules/default/calendar/calendar.js @@ -153,20 +153,6 @@ Module.register("calendar", { for (var e in events) { var event = events[e]; - - var excluded = false; - for (var f in this.config.excludedEvents) { - var filter = this.config.excludedEvents[f]; - if (event.title.toLowerCase().includes(filter.toLowerCase())) { - excluded = true; - break; - } - } - - if (excluded) { - continue; - } - var eventWrapper = document.createElement("tr"); if (this.config.colored) { @@ -366,7 +352,7 @@ Module.register("calendar", { return a.startDate - b.startDate; }); - return events.slice(0, this.config.maximumEntries); + return events; }, /* createEventList(url) @@ -377,6 +363,7 @@ Module.register("calendar", { addCalendar: function (url, auth, calendarConfig) { this.sendSocketNotification("ADD_CALENDAR", { url: url, + excludedEvents: calendarConfig.excludedEvents || this.config.excludedEvents, maximumEntries: calendarConfig.maximumEntries || this.config.maximumEntries, maximumNumberOfDays: calendarConfig.maximumNumberOfDays || this.config.maximumNumberOfDays, fetchInterval: this.config.fetchInterval, @@ -437,25 +424,27 @@ Module.register("calendar", { return defaultValue; }, - /* shorten(string, maxLength) - * Shortens a string if it's longer than maxLength. - * Adds an ellipsis to the end. - * - * argument string string - The string to shorten. - * argument maxLength number - The max length of the string. - * argument wrapEvents - Wrap the text after the line has reached maxLength - * - * return string - The shortened string. + /** + * Shortens a string if it's longer than maxLength and add a ellipsis to the end + * + * @param {string} string Text string to shorten + * @param {number} maxLength The max length of the string + * @param {boolean} wrapEvents Wrap the text after the line has reached maxLength + * @returns {string} The shortened string */ shorten: function (string, maxLength, wrapEvents) { - if (wrapEvents) { + if (typeof string !== "string") { + return ""; + } + + if (wrapEvents === true) { var temp = ""; var currentLine = ""; var words = string.split(" "); for (var i = 0; i < words.length; i++) { var word = words[i]; - if (currentLine.length + word.length < 25 - 1) { // max - 1 to account for a space + if (currentLine.length + word.length < (typeof maxLength === "number" ? maxLength : 25) - 1) { // max - 1 to account for a space currentLine += (word + " "); } else { if (currentLine.length > 0) { @@ -467,12 +456,12 @@ Module.register("calendar", { } } - return temp + currentLine; + return (temp + currentLine).trim(); } else { - if (string.length > maxLength) { - return string.slice(0, maxLength) + "…"; + if (maxLength && typeof maxLength === "number" && string.length > maxLength) { + return string.trim().slice(0, maxLength) + "…"; } else { - return string; + return string.trim(); } } }, diff --git a/modules/default/calendar/calendarfetcher.js b/modules/default/calendar/calendarfetcher.js index 9655f21e..12495f78 100644 --- a/modules/default/calendar/calendarfetcher.js +++ b/modules/default/calendar/calendarfetcher.js @@ -8,7 +8,7 @@ var ical = require("./vendor/ical.js"); var moment = require("moment"); -var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumberOfDays, auth) { +var CalendarFetcher = function(url, reloadInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth) { var self = this; var reloadTimer = null; @@ -113,6 +113,19 @@ var CalendarFetcher = function(url, reloadInterval, maximumEntries, maximumNumbe title = event.description; } + var excluded = false; + for (var f in excludedEvents) { + var filter = excludedEvents[f]; + if (title.toLowerCase().includes(filter.toLowerCase())) { + excluded = true; + break; + } + } + + if (excluded) { + continue; + } + var location = event.location || false; var geo = event.geo || false; var description = event.description || false; diff --git a/modules/default/calendar/node_helper.js b/modules/default/calendar/node_helper.js index 90c286c8..25e7f1f7 100644 --- a/modules/default/calendar/node_helper.js +++ b/modules/default/calendar/node_helper.js @@ -24,7 +24,7 @@ module.exports = NodeHelper.create({ socketNotificationReceived: function(notification, payload) { if (notification === "ADD_CALENDAR") { //console.log('ADD_CALENDAR: '); - this.createFetcher(payload.url, payload.fetchInterval, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth); + this.createFetcher(payload.url, payload.fetchInterval, payload.excludedEvents, payload.maximumEntries, payload.maximumNumberOfDays, payload.auth); } }, @@ -36,7 +36,7 @@ module.exports = NodeHelper.create({ * attribute reloadInterval number - Reload interval in milliseconds. */ - createFetcher: function(url, fetchInterval, maximumEntries, maximumNumberOfDays, auth) { + createFetcher: function(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth) { var self = this; if (!validUrl.isUri(url)) { @@ -47,7 +47,7 @@ module.exports = NodeHelper.create({ var fetcher; if (typeof self.fetchers[url] === "undefined") { console.log("Create new calendar fetcher for url: " + url + " - Interval: " + fetchInterval); - fetcher = new CalendarFetcher(url, fetchInterval, maximumEntries, maximumNumberOfDays, auth); + fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth); fetcher.onReceive(function(fetcher) { //console.log('Broadcast events.'); diff --git a/tests/e2e/env_spec.js b/tests/e2e/env_spec.js index 50be0825..9454b92e 100644 --- a/tests/e2e/env_spec.js +++ b/tests/e2e/env_spec.js @@ -50,7 +50,7 @@ describe("Electron app environment", function() { .should.eventually.have.property("height") .and.be.above(0) .browserWindow.getTitle() - .should.eventually.equal("Magic Mirror"); + .should.eventually.equal("MagicMirror²"); }); it("get request from http://localhost:8080 should return 200", function(done) { diff --git a/tests/unit/functions/calendar_spec.js b/tests/unit/functions/calendar_spec.js index 2c7f62f8..3d65f497 100644 --- a/tests/unit/functions/calendar_spec.js +++ b/tests/unit/functions/calendar_spec.js @@ -14,8 +14,10 @@ describe("Functions into modules/default/calendar/calendar.js", function() { Module.definitions[name] = moduleDefinition; }; - // load calendar.js - require("../../../modules/default/calendar/calendar.js"); + before(function() { + // load calendar.js + require("../../../modules/default/calendar/calendar.js"); + }); describe("capFirst", function() { words = { @@ -27,10 +29,47 @@ describe("Functions into modules/default/calendar/calendar.js", function() { }; Object.keys(words).forEach(word => { - it(`for ${word} should return ${words[word]}`, function() { + it(`for '${word}' should return '${words[word]}'`, function() { expect(Module.definitions.calendar.capFirst(word)).to.equal(words[word]); }); }); }); + + describe("shorten", function() { + strings = { + " String with whitespace at the beginning that needs trimming" : { length: 16, return: "String with whit…" }, + "long string that needs shortening": { length: 16, return: "long string that…" }, + "short string": { length: 16, return: "short string" }, + "long string with no maxLength defined": { return: "long string with no maxLength defined" }, + }; + + Object.keys(strings).forEach(string => { + it(`for '${string}' should return '${strings[string].return}'`, function() { + expect(Module.definitions.calendar.shorten(string, strings[string].length)).to.equal(strings[string].return); + }); + }); + + it("should return an empty string if shorten is called with a non-string", function () { + expect(Module.definitions.calendar.shorten(100)).to.equal(""); + }); + + it("should not shorten the string if shorten is called with a non-number maxLength", function () { + expect(Module.definitions.calendar.shorten("This is a test string", "This is not a number")).to.equal("This is a test string"); + }); + + it("should wrap the string instead of shorten it if shorten is called with wrapEvents = true (with maxLength defined as 20)", function () { + expect(Module.definitions.calendar.shorten( + "This is a wrapEvent test. Should wrap the string instead of shorten it if called with wrapEvent = true", + 20, + true)).to.equal("This is a
wrapEvent test. Should wrap
the string instead of
shorten it if called with
wrapEvent = true"); + }); + + it("should wrap the string instead of shorten it if shorten is called with wrapEvents = true (without maxLength defined, default 25)", function () { + expect(Module.definitions.calendar.shorten( + "This is a wrapEvent test. Should wrap the string instead of shorten it if called with wrapEvent = true", + undefined, + true)).to.equal("This is a wrapEvent
test. Should wrap the string
instead of shorten it if called
with wrapEvent = true"); + }); + }); }); diff --git a/tests/unit/functions/newsfeed_spec.js b/tests/unit/functions/newsfeed_spec.js new file mode 100644 index 00000000..583d696a --- /dev/null +++ b/tests/unit/functions/newsfeed_spec.js @@ -0,0 +1,37 @@ +var fs = require("fs"); +var path = require("path"); +var chai = require("chai"); +var expect = chai.expect; +var vm = require("vm"); + + +describe("Functions into modules/default/newsfeed/newsfeed.js", function() { + + Module = {} + Module.definitions = {}; + Module.register = function (name, moduleDefinition) { + Module.definitions[name] = moduleDefinition; + }; + + // load newsfeed.js + require("../../../modules/default/newsfeed/newsfeed.js"); + + describe("capitalizeFirstLetter", function() { + words = { + "rodrigo": "Rodrigo", + "123m": "123m", + "magic mirror": "Magic mirror", + ",a": ",a", + "ñandú": "Ñandú", + ".!": ".!" + }; + + Object.keys(words).forEach(word => { + it(`for ${word} should return ${words[word]}`, function() { + expect(Module.definitions.newsfeed.capitalizeFirstLetter(word)).to.equal(words[word]); + }); + }); + }); + +}); +