From 2809ed17501ecd4729b9cf31aa926a03f00ae7e3 Mon Sep 17 00:00:00 2001
From: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Date: Sat, 21 Jun 2025 00:37:15 +0200
Subject: [PATCH] [tests] Review and refactor translation tests (#3792)
I have refactored the translations tests, they should now be clearer and
easier to understand. There should be no functional impact.
I have discarded the original approach of also replacing
`XMLHttpRequest` with `fetch` in the file `js/translator.js`. I had
managed to get it to work functionally, but I couldn't get the tests to
work.
---
CHANGELOG.md | 3 +-
tests/e2e/translations_spec.js | 186 +++++++-------
tests/unit/classes/translator_spec.js | 350 ++++++++++++--------------
3 files changed, 262 insertions(+), 277 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d16efdda..66ec171f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -38,7 +38,8 @@ planned for 2025-07-01
- Removed as many of the date conversions as possible
- Use `moment-timezone` when calculating recurring events, this will fix problems from the past with offsets and DST not being handled properly
- Added some tests to test the behavior of the refactored methods to make sure the correct event dates are returned
-- [linter] Enable ESLint rule `no-console` and replace `console` with `Log` in some files
+- [linter] Enable ESLint rule `no-console` and replace `console` with `Log` in some files (#3810)
+- [tests] Review and refactor translation tests (#3792)
### Fixed
diff --git a/tests/e2e/translations_spec.js b/tests/e2e/translations_spec.js
index 4f7f01a3..2c43e6a1 100644
--- a/tests/e2e/translations_spec.js
+++ b/tests/e2e/translations_spec.js
@@ -6,7 +6,7 @@ const express = require("express");
const sinon = require("sinon");
const translations = require("../../translations/translations");
-describe("Translations", () => {
+describe("translations", () => {
let server;
beforeAll(() => {
@@ -26,8 +26,9 @@ describe("Translations", () => {
});
it("should have a translation file in the specified path", () => {
- for (let language in translations) {
+ for (const language in translations) {
const file = fs.statSync(translations[language]);
+
expect(file.isFile()).toBe(true);
}
});
@@ -36,90 +37,91 @@ describe("Translations", () => {
let dom;
beforeEach(() => {
- dom = new JSDOM(
- `\
- \
- `,
- { runScripts: "dangerously", resources: "usable" }
- );
+ // Create a new JSDOM instance for each test
+ dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
+
+ // Mock the necessary global objects
+ dom.window.Log = { log: jest.fn(), error: jest.fn() };
+ dom.window.Translator = {};
+ dom.window.config = { language: "de" };
+
+ // Load class.js and module.js content directly
+ const classJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "class.js"), "utf-8");
+ const moduleJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "module.js"), "utf-8");
+
+ // Execute the scripts in the JSDOM context
+ dom.window.eval(classJs);
+ dom.window.eval(moduleJs);
});
- it("should load translation file", () => {
- return new Promise((done) => {
- dom.window.onload = async () => {
- const { Translator, Module, config } = dom.window;
- config.language = "en";
- Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
-
- Module.register("name", { getTranslations: () => translations });
- const MMM = Module.create("name");
-
- await MMM.loadTranslations();
-
- expect(Translator.load.args).toHaveLength(1);
- expect(Translator.load.calledWith(MMM, "translations/en.json", false)).toBe(true);
-
- done();
- };
+ it("should load translation file", async () => {
+ await new Promise((resolve) => {
+ dom.window.onload = resolve;
});
+
+ const { Translator, Module, config } = dom.window;
+ config.language = "en";
+ Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
+
+ Module.register("name", { getTranslations: () => translations });
+ const MMM = Module.create("name");
+
+ await MMM.loadTranslations();
+
+ expect(Translator.load.args).toHaveLength(1);
+ expect(Translator.load.calledWith(MMM, "translations/en.json", false)).toBe(true);
});
- it("should load translation + fallback file", () => {
- return new Promise((done) => {
- dom.window.onload = async () => {
- const { Translator, Module } = dom.window;
- Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
-
- Module.register("name", { getTranslations: () => translations });
- const MMM = Module.create("name");
-
- await MMM.loadTranslations();
-
- expect(Translator.load.args).toHaveLength(2);
- expect(Translator.load.calledWith(MMM, "translations/de.json", false)).toBe(true);
- expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true);
-
- done();
- };
+ it("should load translation + fallback file", async () => {
+ await new Promise((resolve) => {
+ dom.window.onload = resolve;
});
+
+ const { Translator, Module } = dom.window;
+ Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
+
+ Module.register("name", { getTranslations: () => translations });
+ const MMM = Module.create("name");
+
+ await MMM.loadTranslations();
+
+ expect(Translator.load.args).toHaveLength(2);
+ expect(Translator.load.calledWith(MMM, "translations/de.json", false)).toBe(true);
+ expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true);
});
- it("should load translation fallback file", () => {
- return new Promise((done) => {
- dom.window.onload = async () => {
- const { Translator, Module, config } = dom.window;
- config.language = "--";
- Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
-
- Module.register("name", { getTranslations: () => translations });
- const MMM = Module.create("name");
-
- await MMM.loadTranslations();
-
- expect(Translator.load.args).toHaveLength(1);
- expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true);
-
- done();
- };
+ it("should load translation fallback file", async () => {
+ await new Promise((resolve) => {
+ dom.window.onload = resolve;
});
+
+ const { Translator, Module, config } = dom.window;
+ config.language = "--";
+ Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
+
+ Module.register("name", { getTranslations: () => translations });
+ const MMM = Module.create("name");
+
+ await MMM.loadTranslations();
+
+ expect(Translator.load.args).toHaveLength(1);
+ expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true);
});
- it("should load no file", () => {
- return new Promise((done) => {
- dom.window.onload = async () => {
- const { Translator, Module } = dom.window;
- Translator.load = sinon.stub();
-
- Module.register("name", {});
- const MMM = Module.create("name");
-
- await MMM.loadTranslations();
-
- expect(Translator.load.callCount).toBe(0);
-
- done();
- };
+ it("should load no file", async () => {
+ await new Promise((resolve) => {
+ dom.window.onload = resolve;
});
+
+ const { Translator, Module } = dom.window;
+ Translator.load = sinon.stub();
+
+ Module.register("name", {});
+ const MMM = Module.create("name");
+
+ await MMM.loadTranslations();
+
+ expect(Translator.load.callCount).toBe(0);
});
});
@@ -130,29 +132,30 @@ describe("Translations", () => {
}
};
- describe("Parsing language files through the Translator class", () => {
- for (let language in translations) {
- it(`should parse ${language}`, () => {
- return new Promise((done) => {
- const dom = new JSDOM(
- `\
- \
- \
- \
- \
-