Release 2.33.0 (#3903)

This commit is contained in:
Kristjan ESPERANTO
2025-09-30 18:02:22 +02:00
committed by GitHub
parent 62b0f7f26e
commit b0c5924019
77 changed files with 2811 additions and 2654 deletions

View File

@@ -4,11 +4,23 @@ const helmet = require("helmet");
const { JSDOM } = require("jsdom");
const express = require("express");
/**
* Helper function to create a fresh Translator instance with DOM environment.
* @returns {object} Object containing window and Translator
*/
function createTranslationTestEnvironment () {
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "..", "js", "translator.js"), "utf-8");
const dom = new JSDOM("", { url: "http://localhost:3001", runScripts: "outside-only" });
dom.window.Log = { log: jest.fn(), error: jest.fn() };
dom.window.eval(translatorJs);
return { window: dom.window, Translator: dom.window.Translator };
}
describe("Translator", () => {
let server;
const sockets = new Set();
const translatorJsPath = path.join(__dirname, "..", "..", "..", "js", "translator.js");
const translatorJsScriptContent = fs.readFileSync(translatorJsPath, "utf8");
const translationTestData = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "..", "..", "tests", "mocks", "translation_test.json"), "utf8"));
beforeAll(() => {
@@ -20,7 +32,7 @@ describe("Translator", () => {
});
app.use("/translations", express.static(path.join(__dirname, "..", "..", "..", "tests", "mocks")));
server = app.listen(3000);
server = app.listen(3001);
server.on("connection", (socket) => {
sockets.add(socket);
@@ -81,12 +93,7 @@ describe("Translator", () => {
};
it("should return custom module translation", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
setTranslations(Translator);
let translation = Translator.translate({ name: "MMM-Module" }, "Hello");
@@ -97,12 +104,7 @@ describe("Translator", () => {
});
it("should return core translation", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
setTranslations(Translator);
let translation = Translator.translate({ name: "MMM-Module" }, "FOO");
expect(translation).toBe("Foo");
@@ -111,48 +113,28 @@ describe("Translator", () => {
});
it("should return custom module translation fallback", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
setTranslations(Translator);
const translation = Translator.translate({ name: "MMM-Module" }, "A key");
expect(translation).toBe("A translation");
});
it("should return core translation fallback", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
setTranslations(Translator);
const translation = Translator.translate({ name: "MMM-Module" }, "Fallback");
expect(translation).toBe("core fallback");
});
it("should return translation with placeholder for missing variables", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
setTranslations(Translator);
const translation = Translator.translate({ name: "MMM-Module" }, "Hello {username}");
expect(translation).toBe("Hallo {username}");
});
it("should return key if no translation was found", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
setTranslations(Translator);
const translation = Translator.translate({ name: "MMM-Module" }, "MISSING");
expect(translation).toBe("MISSING");
@@ -163,17 +145,12 @@ describe("Translator", () => {
const mmm = {
name: "TranslationTest",
file (file) {
return `http://localhost:3000/translations/${file}`;
return `http://localhost:3001/translations/${file}`;
}
};
it("should load translations", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
dom.window.Log = { log: jest.fn() };
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
const file = "translation_test.json";
await Translator.load(mmm, file, false);
@@ -182,30 +159,18 @@ describe("Translator", () => {
});
it("should load translation fallbacks", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
const file = "translation_test.json";
dom.window.Log = { log: jest.fn() };
await Translator.load(mmm, file, true);
const json = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "..", "..", "tests", "mocks", file), "utf8"));
expect(Translator.translationsFallback[mmm.name]).toEqual(json);
});
it("should not load translations, if module fallback exists", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { Translator } = createTranslationTestEnvironment();
const file = "translation_test.json";
dom.window.Log = { log: jest.fn() };
Translator.translationsFallback[mmm.name] = {
Hello: "Hallo"
};
@@ -220,37 +185,23 @@ describe("Translator", () => {
describe("loadCoreTranslations", () => {
it("should load core translations and fallback", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
dom.window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
dom.window.Log = { log: jest.fn() };
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { window, Translator } = createTranslationTestEnvironment();
window.translations = { en: "http://localhost:3001/translations/translation_test.json" };
await Translator.loadCoreTranslations("en");
const en = translationTestData;
await new Promise((resolve) => setTimeout(resolve, 500));
expect(Translator.coreTranslations).toEqual(en);
expect(Translator.coreTranslationsFallback).toEqual(en);
});
it("should load core fallback if language cannot be found", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
dom.window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
dom.window.Log = { log: jest.fn() };
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { window, Translator } = createTranslationTestEnvironment();
window.translations = { en: "http://localhost:3001/translations/translation_test.json" };
await Translator.loadCoreTranslations("MISSINGLANG");
const en = translationTestData;
await new Promise((resolve) => setTimeout(resolve, 500));
expect(Translator.coreTranslations).toEqual({});
expect(Translator.coreTranslationsFallback).toEqual(en);
});
@@ -258,35 +209,20 @@ describe("Translator", () => {
describe("loadCoreTranslationsFallback", () => {
it("should load core translations fallback", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
dom.window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
dom.window.Log = { log: jest.fn() };
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { window, Translator } = createTranslationTestEnvironment();
window.translations = { en: "http://localhost:3001/translations/translation_test.json" };
await Translator.loadCoreTranslationsFallback();
const en = translationTestData;
await new Promise((resolve) => setTimeout(resolve, 500));
expect(Translator.coreTranslationsFallback).toEqual(en);
});
it("should load core fallback if language cannot be found", async () => {
const dom = new JSDOM("", { runScripts: "outside-only" });
dom.window.eval(translatorJsScriptContent);
dom.window.translations = {};
dom.window.Log = { log: jest.fn() };
await new Promise((resolve) => dom.window.onload = resolve);
const { Translator } = dom.window;
const { window, Translator } = createTranslationTestEnvironment();
window.translations = {};
await Translator.loadCoreTranslations();
await new Promise((resolve) => setTimeout(resolve, 500));
expect(Translator.coreTranslationsFallback).toEqual({});
});
});

View File

@@ -1,4 +1,4 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`Updatenotification custom module returns status information without hash 1`] = `
{

View File

@@ -1,4 +1,5 @@
const { cors } = require("../../../js/server_functions");
const { expect } = require("playwright/test");
const { cors, getUserAgent } = require("#server_functions");
describe("server_functions tests", () => {
describe("The cors method", () => {
@@ -142,5 +143,21 @@ describe("server_functions tests", () => {
expect(corsResponse.set.mock.calls[2][0]).toBe("header2");
expect(corsResponse.set.mock.calls[2][1]).toBe("value2");
});
it("Gets User-Agent from configuration", async () => {
config = {};
let userAgent;
userAgent = getUserAgent();
expect(userAgent).toContain("Mozilla/5.0 (Node.js ");
config.userAgent = "Mozilla/5.0 (Foo)";
userAgent = getUserAgent();
expect(userAgent).toBe("Mozilla/5.0 (Foo)");
config.userAgent = () => "Mozilla/5.0 (Bar)";
userAgent = getUserAgent();
expect(userAgent).toBe("Mozilla/5.0 (Bar)");
});
});
});

View File

@@ -4,7 +4,7 @@ const path = require("node:path");
const root_path = path.join(__dirname, "../../..");
describe("Default modules set in modules/default/defaultmodules.js", () => {
const expectedDefaultModules = require("../../../modules/default/defaultmodules");
const expectedDefaultModules = require(`${root_path}/modules/default/defaultmodules`);
for (const defaultModule of expectedDefaultModules) {
it(`contains a folder for modules/default/${defaultModule}"`, () => {

View File

@@ -2,7 +2,7 @@ const fs = require("node:fs");
const path = require("node:path");
const root_path = path.join(__dirname, "../../..");
const version = require(`${__dirname}/../../../package.json`).version;
const version = require(`${root_path}/package.json`).version;
describe("'global.root_path' set in js/app.js", () => {
const expectedSubPaths = ["modules", "serveronly", "js", "js/app.js", "js/main.js", "js/electron.js", "config"];

View File

@@ -10,7 +10,7 @@ describe("Calendar fetcher utils test", () => {
excludedEvents: [],
includePastEvents: false,
maximumEntries: 10,
maximumNumberOfDays: 365
maximumNumberOfDays: 367
};
describe("filterEvents", () => {

View File

@@ -2,10 +2,18 @@ const weather = require("../../../../../modules/default/weather/weatherutils");
const WeatherUtils = require("../../../../../modules/default/weather/weatherutils");
describe("Weather utils tests", () => {
describe("windspeed conversion to imperial", () => {
describe("temperature conversion to imperial", () => {
it("should convert temp correctly from Celsius to Celsius", () => {
expect(Math.round(WeatherUtils.convertTemp(10, "metric"))).toBe(10);
});
it("should convert temp correctly from Celsius to Fahrenheit", () => {
expect(Math.round(WeatherUtils.convertTemp(10, "imperial"))).toBe(50);
});
it("should convert temp correctly from Fahrenheit to Celsius", () => {
expect(Math.round(WeatherUtils.convertTempToMetric(10))).toBe(-12);
});
});
describe("windspeed conversion to beaufort", () => {
@@ -44,11 +52,11 @@ describe("Weather utils tests", () => {
describe("feelsLike calculation", () => {
it("should return a calculated feelsLike info (negative value)", () => {
expect(WeatherUtils.calculateFeelsLike(0, 20, 40)).toBe(-9.444444444444445);
expect(WeatherUtils.calculateFeelsLike(0, 20, 40)).toBe(-9.397005931555448);
});
it("should return a calculated feelsLike info (positive value)", () => {
expect(WeatherUtils.calculateFeelsLike(30, 0, 60)).toBe(32.8320322777777);
expect(WeatherUtils.calculateFeelsLike(30, 0, 60)).toBe(32.832032277777756);
});
});