Release v2.25.0 (#3214)

## [2.25.0] - 2023-10-01

Thanks to: @bugsounet, @dgoth, @dependabot, @kenzal, @Knapoc,
@KristjanESPERANTO, @martingron, @NolanKingdon, @Paranoid93,
@TeddyStarinvest and @Ybbet.

Special thanks to @khassel, @rejas and @sdetweil for taking over most
(if not all) of the work on this release as project collaborators. This
version would not be there without their effort. Thank you guys! You are
awesome!

> ⚠️ This release needs nodejs version >= `v18`, older releases have
reached end of life and will not work!

### Added

- Added UV Index support to OpenWeatherMap
- Added 'hideDuplicates' flag to the calendar module
- Added `allowOverrideNotification` to weather module to enable sending
current weather objects with the `CURRENT_WEATHER_OVERRIDE` notification
to supplement/replace the current weather displayed
- Added optional AnimateCSS animate for `hide()`, `show()`,
`updateDom()`
- Added AnimateIn and animateOut in module config definition
- Apply AnimateIn rules on the first start
- Added automatic client page reload when server was restarted by
setting `reloadAfterServerRestart: true` in `config.js`, per default
`false` (#3105)
- Added eventClass option for customEvents on the default calendar
- Added AnimateCSS integration in tests suite (#3206)
- Added npm dependabot [Reserved to developer] (#3210)
- Added improved logging for calendar (#3110)

### Removed

- **Breaking Change**: Removed `digest` authentication method from
calendar module (which was already broken since release `2.15.0`)

### Updated

- Update roboto fonts to version v5
- Update issue template
- Update dev/dependencies incl. electron to v26
- Replace pretty-quick by lint-staged
(<https://github.com/azz/pretty-quick/issues/164>)
- Update engine node >=18. v16 reached it's end of life. (#3170)
- Update typescript definition for modules
- Cleaned up nunjuck templates
- Replace `node-fetch` with internal fetch (#2649) and remove
`digest-fetch`
- Update the French translation according to the English file.
- Update dependabot incl. vendor/fonts (monthly check)
- Renew `package-lock.json` for release

### Fixed

- Fix engine check on npm install (#3135)
- Fix undefined formatTime method in clock module (#3143)
- Fix clientonly startup fails after async added (#3151)
- Fix electron width/heigth when using xrandr under bullseye
- Fix time issue with certain recurring events in calendar module
- Fix ipWhiteList test (#3179)
- Fix newsfeed: Convert HTML entities, codes and tag in description
(#3191)
- Respect width/height (no fullscreen) if set in electronOptions
(together with `fullscreen: false`) in `config.js` (#3174)
- Fix: AnimateCSS merge hide() and show() animated css class when we do
multiple call
- Fix `Uncaught SyntaxError: Identifier 'getCorsUrl' has already been
declared (at utils.js:1:1)` when using `clock` and `weather` module
(#3204)
- Fix overriding `config.js` when running tests (#3201)
- Fix issue in weathergov provider with probability of precipitation not
showing up on hourly or daily forecast

---------

Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com>
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: veeck <michael@veeck.de>
Co-authored-by: dWoolridge <dwoolridge@charter.net>
Co-authored-by: Johan <jojjepersson@yahoo.se>
Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com>
Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com>
Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com>
Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com>
Co-authored-by: buxxi <buxxi@omfilm.net>
Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com>
Co-authored-by: Dave Child <dave@addedbytes.com>
Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com>
Co-authored-by: Grena <grena@grenabox.fr>
Co-authored-by: Magnus Marthinsen <magmar@online.no>
Co-authored-by: Patrick <psieg@users.noreply.github.com>
Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com>
Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com>
Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com>
Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com>
Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com>
Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com>
Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com>
Co-authored-by: Ismar Slomic <ismar@slomic.no>
Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no>
Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: bugsounet <bugsounet@bugsounet.fr>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Knapoc <Knapoc@users.noreply.github.com>
Co-authored-by: sam detweiler <sdetweil@gmail.com>
Co-authored-by: veeck <michael.veeck@nebenan.de>
Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com>
Co-authored-by: NolanKingdon <27908974+NolanKingdon@users.noreply.github.com>
Co-authored-by: J. Kenzal Hunter <kenzal.hunter@gmail.com>
Co-authored-by: Teddy <teddy.payet@gmail.com>
Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com>
Co-authored-by: martingron <61826403+martingron@users.noreply.github.com>
Co-authored-by: dgoth <132394363+dgoth@users.noreply.github.com>
This commit is contained in:
Michael Teeuw
2023-10-01 20:13:41 +02:00
committed by GitHub
parent e87f50e64a
commit 343e7de7bd
80 changed files with 4643 additions and 8570 deletions

View File

@@ -0,0 +1,78 @@
/* AnimateCSS integration Test with compliments module
*
* By bugsounet https://github.com/bugsounet
* and helped by khassel
* 09/2023
* MIT Licensed.
*/
const helpers = require("./helpers/global-setup.js");
describe("AnimateCSS integration Test", () => {
// define config file for testing
let testConfigFile = "tests/configs/modules/compliments/compliments_animateCSS.js";
// define config file to fallback to default: wrong animation name (must return no animation)
let testConfigFileFallbackToDefault = "tests/configs/modules/compliments/compliments_animateCSS_fallbackToDefault.js";
// define config file with an inversed name animation : in for out and vice versa (must return no animation)
let testConfigFileInvertedAnimationName = "tests/configs/modules/compliments/compliments_animateCSS_invertedAnimationName.js";
// define config file with no animation defined
let testConfigByDefault = "tests/configs/modules/compliments/compliments_anytime.js";
/**
* move similar tests in function doTest
* @param {string} [animationIn] animation in name of AnimateCSS to test.
* @param {string} [animationOut] animation out name of AnimateCSS to test.
*/
const doTest = async (animationIn, animationOut) => {
await helpers.getDocument();
let elem = await helpers.waitForElement(`.compliments`);
expect(elem).not.toBe(null);
let styles = window.getComputedStyle(elem);
if (animationIn && animationIn !== "") {
expect(styles._values["animation-name"]).toBe(animationIn);
} else {
expect(styles._values["animation-name"]).toBe(undefined);
}
if (animationOut && animationOut !== "") {
elem = await helpers.waitForElement(`.compliments.animate__animated.animate__${animationOut}`);
expect(elem).not.toBe(null);
styles = window.getComputedStyle(elem);
expect(styles._values["animation-name"]).toBe(animationOut);
} else {
expect(styles._values["animation-name"]).toBe(undefined);
}
};
afterEach(async () => {
await helpers.stopApplication();
});
describe("animateIn and animateOut Test", () => {
it("with flipInX and flipOutX animation", async () => {
await helpers.startApplication(testConfigFile);
await doTest("flipInX", "flipOutX");
});
});
describe("use animateOut name for animateIn (vice versa) Test", () => {
it("without animation", async () => {
await helpers.startApplication(testConfigFileInvertedAnimationName);
await doTest();
});
});
describe("false Animation name test", () => {
it("without animation", async () => {
await helpers.startApplication(testConfigFileFallbackToDefault);
await doTest();
});
});
describe("no Animation defined test", () => {
it("without animation", async () => {
await helpers.startApplication(testConfigByDefault);
await doTest();
});
});
});

View File

@@ -10,12 +10,12 @@ describe("App environment", () => {
});
it("get request from http://localhost:8080 should return 200", async () => {
const res = await helpers.fetch("http://localhost:8080");
const res = await fetch("http://localhost:8080");
expect(res.status).toBe(200);
});
it("get request from http://localhost:8080/nothing should return 404", async () => {
const res = await helpers.fetch("http://localhost:8080/nothing");
const res = await fetch("http://localhost:8080/nothing");
expect(res.status).toBe(404);
});

View File

@@ -22,7 +22,7 @@ describe("All font files from roboto.css should be downloadable", () => {
test.each(fontFiles)("should return 200 HTTP code for file '%s'", async (fontFile) => {
const fontUrl = `http://localhost:8080/fonts/${fontFile}`;
const res = await helpers.fetch(fontUrl);
const res = await fetch(fontUrl);
expect(res.status).toBe(200);
});
});

View File

@@ -1,5 +1,4 @@
const jsdom = require("jsdom");
const corefetch = require("fetch");
exports.startApplication = async (configFilename, exec) => {
jest.resetModules();
@@ -31,7 +30,8 @@ exports.getDocument = () => {
const url = `http://${config.address || "localhost"}:${config.port || "8080"}`;
jsdom.JSDOM.fromURL(url, { resources: "usable", runScripts: "dangerously" }).then((dom) => {
dom.window.name = "jsdom";
dom.window.fetch = corefetch;
global.window = dom.window;
dom.window.fetch = fetch;
dom.window.onload = () => {
global.document = dom.window.document;
resolve();
@@ -80,14 +80,6 @@ exports.waitForAllElements = (selector) => {
});
};
exports.fetch = (url) => {
return new Promise((resolve) => {
corefetch(url).then((res) => {
resolve(res);
});
});
};
exports.testMatch = async (element, regex) => {
const elem = await this.waitForElement(element);
expect(elem).not.toBe(null);

View File

@@ -13,7 +13,6 @@ exports.getText = async (element, result) => {
};
exports.startApp = async (configFileName, additionalMockData) => {
injectMockData(configFileName, additionalMockData);
await helpers.startApplication("");
await helpers.startApplication(injectMockData(configFileName, additionalMockData));
await helpers.getDocument();
};

View File

@@ -10,7 +10,7 @@ describe("ipWhitelist directive configuration", () => {
});
it("should return 403", async () => {
const res = await helpers.fetch("http://localhost:8080");
const res = await fetch("http://localhost:8181");
expect(res.status).toBe(403);
});
});
@@ -24,7 +24,7 @@ describe("ipWhitelist directive configuration", () => {
});
it("should return 200", async () => {
const res = await helpers.fetch("http://localhost:8080");
const res = await fetch("http://localhost:8282");
expect(res.status).toBe(200);
});
});

View File

@@ -60,6 +60,10 @@ describe("Calendar module", () => {
await testElementLength(".calendar .event .fa-dice", 1);
});
it("should show a customEvent calendar eventClass in one event", async () => {
await testElementLength(".calendar .event.undo", 1);
});
it("should show two custom icons for repeating events", async () => {
await testElementLength(".calendar .event .fa-undo", 2);
});
@@ -80,6 +84,17 @@ describe("Calendar module", () => {
});
});
describe("Events from multiple calendars", () => {
beforeAll(async () => {
await helpers.startApplication("tests/configs/modules/calendar/show-duplicates-in-calendar.js");
await helpers.getDocument();
});
it("should show multiple events with the same title and start time from different calendars", async () => {
await testElementLength(".calendar .event", 22);
});
});
process.setMaxListeners(0);
for (let i = -12; i < 12; i++) {
describe("Recurring event per timezone", () => {

View File

@@ -71,11 +71,28 @@ describe("Clock module", () => {
});
it("should not show the time when digital clock is shown", async () => {
const elem = await document.querySelector(".clock .digital .time");
const elem = document.querySelector(".clock .digital .time");
expect(elem).toBe(null);
});
});
describe("with showSun/MoonTime enabled", () => {
beforeAll(async () => {
await helpers.startApplication("tests/configs/modules/clock/clock_showSunMoon.js");
await helpers.getDocument();
});
it("should show the sun times", async () => {
const elem = await helpers.waitForElement(".clock .digital .sun");
expect(elem).not.toBe(null);
});
it("should show the moon times", async () => {
const elem = await helpers.waitForElement(".clock .digital .moon");
expect(elem).not.toBe(null);
});
});
describe("with showWeek config enabled", () => {
beforeAll(async () => {
await helpers.startApplication("tests/configs/modules/clock/clock_showWeek.js");

View File

@@ -25,8 +25,8 @@ describe("Newsfeed module", () => {
it("should NOT show the newsfeed description", async () => {
await helpers.waitForElement(".newsfeed");
const element = document.querySelector(".newsfeed .newsfeed-desc");
expect(element).toBe(null);
const elem = document.querySelector(".newsfeed .newsfeed-desc");
expect(elem).toBe(null);
});
});

View File

@@ -1,9 +1,11 @@
const helpers = require("../helpers/global-setup");
const weatherFunc = require("../helpers/weather-functions");
const { cleanupMockData } = require("../../utils/weather_mocker");
describe("Weather module", () => {
afterAll(async () => {
await helpers.stopApplication();
await cleanupMockData();
});
describe("Current weather", () => {
@@ -48,7 +50,7 @@ describe("Weather module", () => {
it("should render windDirection with an arrow", async () => {
const elem = await helpers.waitForElement(".weather .normal.medium sup i.fa-long-arrow-alt-down");
expect(elem).not.toBe(null);
expect(elem.outerHTML).toContain("transform:rotate(250deg);");
expect(elem.outerHTML).toContain("transform:rotate(250deg)");
});
it("should render humidity", async () => {

View File

@@ -1,9 +1,11 @@
const helpers = require("../helpers/global-setup");
const weatherFunc = require("../helpers/weather-functions");
const { cleanupMockData } = require("../../utils/weather_mocker");
describe("Weather module: Weather Forecast", () => {
afterAll(async () => {
await helpers.stopApplication();
await cleanupMockData();
});
describe("Default configuration", () => {

View File

@@ -1,9 +1,11 @@
const helpers = require("../helpers/global-setup");
const weatherFunc = require("../helpers/weather-functions");
const { cleanupMockData } = require("../../utils/weather_mocker");
describe("Weather module: Weather Hourly Forecast", () => {
afterAll(async () => {
await helpers.stopApplication();
await cleanupMockData();
});
describe("Default configuration", () => {

View File

@@ -10,7 +10,7 @@ describe("port directive configuration", () => {
});
it("should return 200", async () => {
const res = await helpers.fetch("http://localhost:8090");
const res = await fetch("http://localhost:8090");
expect(res.status).toBe(200);
});
});
@@ -24,7 +24,7 @@ describe("port directive configuration", () => {
});
it("should return 200", async () => {
const res = await helpers.fetch("http://localhost:8100");
const res = await fetch("http://localhost:8100");
expect(res.status).toBe(200);
});
});

View File

@@ -17,12 +17,12 @@ describe("App environment", () => {
});
it("get request from http://localhost:8080 should return 200", async () => {
const res = await helpers.fetch("http://localhost:8080");
const res = await fetch("http://localhost:8080");
expect(res.status).toBe(200);
});
it("get request from http://localhost:8080/nothing should return 404", async () => {
const res = await helpers.fetch("http://localhost:8080/nothing");
const res = await fetch("http://localhost:8080/nothing");
expect(res.status).toBe(404);
});
});

View File

@@ -1,3 +1,4 @@
const fs = require("fs");
const helpers = require("./helpers/global-setup");
describe("templated config with port variable", () => {
@@ -6,10 +7,15 @@ describe("templated config with port variable", () => {
});
afterAll(async () => {
await helpers.stopApplication();
try {
fs.unlinkSync("tests/configs/port_variable.js");
} catch (err) {
// do nothing
}
});
it("should return 200", async () => {
const res = await helpers.fetch("http://localhost:8090");
const res = await fetch("http://localhost:8090");
expect(res.status).toBe(200);
});
});

View File

@@ -14,7 +14,7 @@ describe("Vendors", () => {
Object.keys(vendors).forEach((vendor) => {
it(`should return 200 HTTP code for vendor "${vendor}"`, async () => {
const urlVendor = `http://localhost:8080/vendor/${vendors[vendor]}`;
const res = await helpers.fetch(urlVendor);
const res = await fetch(urlVendor);
expect(res.status).toBe(200);
});
});
@@ -22,7 +22,7 @@ describe("Vendors", () => {
Object.keys(vendors).forEach((vendor) => {
it(`should return 404 HTTP code for vendor https://localhost/"${vendor}"`, async () => {
const urlVendor = `http://localhost:8080/${vendors[vendor]}`;
const res = await helpers.fetch(urlVendor);
const res = await fetch(urlVendor);
expect(res.status).toBe(404);
});
});