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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

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

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

beforeAll(() => {
Expand All @@ -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);
}
});
Expand All @@ -36,90 +37,91 @@ describe("Translations", () => {
let dom;

beforeEach(() => {
dom = new JSDOM(
`<script>var Translator = {}; var Log = {log: () => {}}; var config = {language: 'de'};</script>\
<script src="file://${path.join(__dirname, "..", "..", "js", "class.js")}"></script>\
<script src="file://${path.join(__dirname, "..", "..", "js", "module.js")}"></script>`,
{ 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);
it("should load translation file", async () => {
await new Promise((resolve) => {
dom.window.onload = resolve;
});

Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");
const { Translator, Module, config } = dom.window;
config.language = "en";
Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);

await MMM.loadTranslations();
Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");

expect(Translator.load.args).toHaveLength(1);
expect(Translator.load.calledWith(MMM, "translations/en.json", false)).toBe(true);
await MMM.loadTranslations();

done();
};
});
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);
it("should load translation + fallback file", async () => {
await new Promise((resolve) => {
dom.window.onload = resolve;
});

Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");
const { Translator, Module } = dom.window;
Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);

await MMM.loadTranslations();
Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");

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);
await MMM.loadTranslations();

done();
};
});
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);
it("should load translation fallback file", async () => {
await new Promise((resolve) => {
dom.window.onload = resolve;
});

Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");
const { Translator, Module, config } = dom.window;
config.language = "--";
Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);

await MMM.loadTranslations();
Module.register("name", { getTranslations: () => translations });
const MMM = Module.create("name");

expect(Translator.load.args).toHaveLength(1);
expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true);
await MMM.loadTranslations();

done();
};
});
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();
it("should load no file", async () => {
await new Promise((resolve) => {
dom.window.onload = resolve;
});

Module.register("name", {});
const MMM = Module.create("name");
const { Translator, Module } = dom.window;
Translator.load = sinon.stub();

await MMM.loadTranslations();
Module.register("name", {});
const MMM = Module.create("name");

expect(Translator.load.callCount).toBe(0);
await MMM.loadTranslations();

done();
};
});
expect(Translator.load.callCount).toBe(0);
});
});

Expand All @@ -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(
`<script>var translations = ${JSON.stringify(translations)}; var Log = {log: () => {}};</script>\
<script src="file://${path.join(__dirname, "..", "..", "js", "translator.js")}">`,
{ runScripts: "dangerously", resources: "usable" }
);
dom.window.onload = async () => {
const { Translator } = dom.window;

await Translator.load(mmm, translations[language], false);
expect(typeof Translator.translations[mmm.name]).toBe("object");
expect(Object.keys(Translator.translations[mmm.name]).length).toBeGreaterThanOrEqual(1);
done();
};
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);

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

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

expect(typeof Translator.translations[mmm.name]).toBe("object");
expect(Object.keys(Translator.translations[mmm.name]).length).toBeGreaterThanOrEqual(1);
});
}
});

describe("Same keys", () => {
describe("same keys", () => {
let base;

// Some expressions are not easy to translate automatically. For the sake of a working test, we filter them out.
Expand All @@ -178,7 +181,6 @@ describe("Translations", () => {
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
dom.window.Log = { log: jest.fn() };
dom.window.translations = translations;
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "translator.js"), "utf-8");
dom.window.eval(translatorJs);

return new Promise((resolve) => {
Expand Down
Loading