Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Thanks to: @dathbe.
- [refactor] Add new file `js/module_functions.js` to move code used in several modules to one place (#3837)
- [tests] refactor: simplify jest config file (#3844)
- [tests] refactor: extract constants for weather electron tests (#3845)
- [tests] refactor: add `setupDOMEnvironment` helper function to eliminate repetitive JSDOM setup code (#3860)
- [tests] replace `console` with `Log` in calendar `debug.js` to avoid exception in eslint config (#3846)
- [tests] speed up e2e tests, cleanup and stabilize weather e2e tests (#3847, #3848)

Expand Down
41 changes: 24 additions & 17 deletions tests/e2e/translations_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ const express = require("express");
const sinon = require("sinon");
const translations = require("../../translations/translations");

/**
* Helper function to setup DOM environment.
* @returns {object} The JSDOM window object
*/
function setupDOMEnvironment () {
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });

dom.window.Log = { log: jest.fn(), error: jest.fn() };
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "translator.js"), "utf-8");
dom.window.translations = translations;
dom.window.eval(translatorJs);

return dom.window;
}

describe("translations", () => {
let server;

Expand Down Expand Up @@ -38,10 +53,10 @@ describe("translations", () => {

beforeEach(() => {
// Create a new JSDOM instance for each test
dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
const window = setupDOMEnvironment();
dom = { window };

// Mock the necessary global objects
dom.window.Log = { log: jest.fn(), error: jest.fn() };
// Additional setup for loadTranslations tests
dom.window.Translator = {};
dom.window.config = { language: "de" };

Expand Down Expand Up @@ -132,21 +147,16 @@ describe("translations", () => {
}
};

const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "translator.js"), "utf-8");

describe("parsing language files through the Translator class", () => {
for (const language in translations) {
it(`should parse ${language}`, async () => {
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
dom.window.Log = { log: jest.fn() };
dom.window.translations = translations;
dom.window.eval(translatorJs);
const window = setupDOMEnvironment();

await new Promise((resolve) => {
dom.window.onload = resolve;
window.onload = resolve;
});

const { Translator } = dom.window;
const { Translator } = window;
await Translator.load(mmm, translations[language], false);

expect(typeof Translator.translations[mmm.name]).toBe("object");
Expand Down Expand Up @@ -178,14 +188,11 @@ describe("translations", () => {

// Function to initialize JSDOM and load translations
const initializeTranslationDOM = (language) => {
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
dom.window.Log = { log: jest.fn() };
dom.window.translations = translations;
dom.window.eval(translatorJs);
const window = setupDOMEnvironment();

return new Promise((resolve) => {
dom.window.onload = async () => {
const { Translator } = dom.window;
window.onload = async () => {
const { Translator } = window;
await Translator.load(mmm, translations[language], false);
resolve(Translator.translations[mmm.name]);
};
Expand Down
130 changes: 45 additions & 85 deletions tests/unit/classes/translator_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ const helmet = require("helmet");
const { JSDOM } = require("jsdom");
const express = require("express");

/**
* Helper function to setup DOM environment.
* @param {string} scriptContent - The script content to evaluate
* @returns {Promise<object>} The JSDOM window object
*/
async function setupDOMEnvironment (scriptContent) {
const dom = new JSDOM("", { runScripts: "outside-only" });

dom.window.eval(scriptContent);
dom.window.Log = { log: jest.fn(), error: jest.fn() };

await new Promise((resolve) => dom.window.onload = resolve);
return dom.window;
}

describe("Translator", () => {
let server;
const sockets = new Set();
Expand Down Expand Up @@ -81,12 +96,8 @@ 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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
setTranslations(Translator);

let translation = Translator.translate({ name: "MMM-Module" }, "Hello");
Expand All @@ -97,12 +108,8 @@ 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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
setTranslations(Translator);
let translation = Translator.translate({ name: "MMM-Module" }, "FOO");
expect(translation).toBe("Foo");
Expand All @@ -111,48 +118,32 @@ 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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
setTranslations(Translator);
const translation = Translator.translate({ name: "MMM-Module" }, "MISSING");
expect(translation).toBe("MISSING");
Expand All @@ -168,12 +159,8 @@ describe("Translator", () => {
};

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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
const file = "translation_test.json";

await Translator.load(mmm, file, false);
Expand All @@ -182,30 +169,20 @@ 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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
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 window = await setupDOMEnvironment(translatorJsScriptContent);
const { Translator } = window;
const file = "translation_test.json";


dom.window.Log = { log: jest.fn() };
Translator.translationsFallback[mmm.name] = {
Hello: "Hallo"
};
Expand All @@ -220,13 +197,9 @@ 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 = await setupDOMEnvironment(translatorJsScriptContent);
window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
const { Translator } = window;
await Translator.loadCoreTranslations("en");

const en = translationTestData;
Expand All @@ -238,13 +211,9 @@ describe("Translator", () => {
});

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 = await setupDOMEnvironment(translatorJsScriptContent);
window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
const { Translator } = window;
await Translator.loadCoreTranslations("MISSINGLANG");

const en = translationTestData;
Expand All @@ -258,13 +227,9 @@ 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 = await setupDOMEnvironment(translatorJsScriptContent);
window.translations = { en: "http://localhost:3000/translations/translation_test.json" };
const { Translator } = window;
await Translator.loadCoreTranslationsFallback();

const en = translationTestData;
Expand All @@ -275,14 +240,9 @@ describe("Translator", () => {
});

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 = await setupDOMEnvironment(translatorJsScriptContent);
window.translations = {};
const { Translator } = window;
await Translator.loadCoreTranslations();

await new Promise((resolve) => setTimeout(resolve, 500));
Expand Down