Skip to content

Commit 4c0a468

Browse files
[tests] refactor translation tests (#3866)
- Remove `sinon` dependency in favor of Jest native mocking - Unify test helper functions across translation test suites - Rename `setupDOMEnvironment` to `createTranslationTestEnvironment` for consistency - Simplify DOM setup by removing unnecessary Promise/async patterns - Avoid potential port conflicts by using port 3001 for translator unit tests - Improve test reliability and maintainability
1 parent eb71942 commit 4c0a468

File tree

5 files changed

+69
-171
lines changed

5 files changed

+69
-171
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ Thanks to: @dathbe.
2727
- [tests] refactor: add `setupDOMEnvironment` helper function to eliminate repetitive JSDOM setup code (#3860)
2828
- [tests] replace `console` with `Log` in calendar `debug.js` to avoid exception in eslint config (#3846)
2929
- [tests] speed up e2e tests, cleanup and stabilize weather e2e tests, update snapshot url (#3847, #3848, #3861)
30+
- [tests] refactor translation tests (#3866)
31+
- Remove `sinon` dependency in favor of Jest native mocking
32+
- Unify test helper functions across translation test suites
33+
- Rename `setupDOMEnvironment` to `createTranslationTestEnvironment` for consistency
34+
- Simplify DOM setup by removing unnecessary Promise/async patterns
35+
- Avoid potential port conflicts by using port 3001 for translator unit tests
36+
- Improve test reliability and maintainability
3037

3138
### Updated
3239

package-lock.json

Lines changed: 0 additions & 59 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@
111111
"markdownlint-cli2": "^0.18.1",
112112
"playwright": "^1.55.0",
113113
"prettier": "^3.6.2",
114-
"sinon": "^21.0.0",
115114
"stylelint": "^16.23.1",
116115
"stylelint-config-standard": "^39.0.0",
117116
"stylelint-prettier": "^5.0.3"

tests/e2e/translations_spec.js

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,24 @@ const path = require("node:path");
33
const helmet = require("helmet");
44
const { JSDOM } = require("jsdom");
55
const express = require("express");
6-
const sinon = require("sinon");
76
const translations = require("../../translations/translations");
87

98
/**
10-
* Helper function to setup DOM environment.
11-
* @returns {object} The JSDOM window object
9+
* Helper function to create a fresh Translator instance with DOM environment.
10+
* @returns {object} Object containing window and Translator
1211
*/
13-
function setupDOMEnvironment () {
14-
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
12+
function createTranslationTestEnvironment () {
13+
// Setup DOM environment with Translator
14+
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "translator.js"), "utf-8");
15+
const dom = new JSDOM("", { url: "http://localhost:3000", runScripts: "outside-only" });
1516

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

21-
return dom.window;
21+
const window = dom.window;
22+
23+
return { window, Translator: window.Translator };
2224
}
2325

2426
describe("translations", () => {
@@ -52,91 +54,76 @@ describe("translations", () => {
5254
let dom;
5355

5456
beforeEach(() => {
55-
// Create a new JSDOM instance for each test
56-
const window = setupDOMEnvironment();
57-
dom = { window };
58-
59-
// Additional setup for loadTranslations tests
60-
dom.window.Translator = {};
61-
dom.window.config = { language: "de" };
57+
// Create a new translation test environment for each test
58+
const env = createTranslationTestEnvironment();
59+
const window = env.window;
6260

63-
// Load class.js and module.js content directly
61+
// Load class.js and module.js content directly for loadTranslations tests
6462
const classJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "class.js"), "utf-8");
6563
const moduleJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "module.js"), "utf-8");
6664

6765
// Execute the scripts in the JSDOM context
68-
dom.window.eval(classJs);
69-
dom.window.eval(moduleJs);
66+
window.eval(classJs);
67+
window.eval(moduleJs);
68+
69+
// Additional setup for loadTranslations tests
70+
window.config = { language: "de" };
71+
72+
dom = { window };
7073
});
7174

7275
it("should load translation file", async () => {
73-
await new Promise((resolve) => {
74-
dom.window.onload = resolve;
75-
});
76-
7776
const { Translator, Module, config } = dom.window;
7877
config.language = "en";
79-
Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
78+
Translator.load = jest.fn().mockImplementation((_m, _f, _fb) => null);
8079

8180
Module.register("name", { getTranslations: () => translations });
8281
const MMM = Module.create("name");
8382

8483
await MMM.loadTranslations();
8584

86-
expect(Translator.load.args).toHaveLength(1);
87-
expect(Translator.load.calledWith(MMM, "translations/en.json", false)).toBe(true);
85+
expect(Translator.load.mock.calls).toHaveLength(1);
86+
expect(Translator.load).toHaveBeenCalledWith(MMM, "translations/en.json", false);
8887
});
8988

9089
it("should load translation + fallback file", async () => {
91-
await new Promise((resolve) => {
92-
dom.window.onload = resolve;
93-
});
94-
9590
const { Translator, Module } = dom.window;
96-
Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
91+
Translator.load = jest.fn().mockImplementation((_m, _f, _fb) => null);
9792

9893
Module.register("name", { getTranslations: () => translations });
9994
const MMM = Module.create("name");
10095

10196
await MMM.loadTranslations();
10297

103-
expect(Translator.load.args).toHaveLength(2);
104-
expect(Translator.load.calledWith(MMM, "translations/de.json", false)).toBe(true);
105-
expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true);
98+
expect(Translator.load.mock.calls).toHaveLength(2);
99+
expect(Translator.load).toHaveBeenCalledWith(MMM, "translations/de.json", false);
100+
expect(Translator.load).toHaveBeenCalledWith(MMM, "translations/en.json", true);
106101
});
107102

108103
it("should load translation fallback file", async () => {
109-
await new Promise((resolve) => {
110-
dom.window.onload = resolve;
111-
});
112-
113104
const { Translator, Module, config } = dom.window;
114105
config.language = "--";
115-
Translator.load = sinon.stub().callsFake((_m, _f, _fb) => null);
106+
Translator.load = jest.fn().mockImplementation((_m, _f, _fb) => null);
116107

117108
Module.register("name", { getTranslations: () => translations });
118109
const MMM = Module.create("name");
119110

120111
await MMM.loadTranslations();
121112

122-
expect(Translator.load.args).toHaveLength(1);
123-
expect(Translator.load.calledWith(MMM, "translations/en.json", true)).toBe(true);
113+
expect(Translator.load.mock.calls).toHaveLength(1);
114+
expect(Translator.load).toHaveBeenCalledWith(MMM, "translations/en.json", true);
124115
});
125116

126117
it("should load no file", async () => {
127-
await new Promise((resolve) => {
128-
dom.window.onload = resolve;
129-
});
130-
131118
const { Translator, Module } = dom.window;
132-
Translator.load = sinon.stub();
119+
Translator.load = jest.fn();
133120

134121
Module.register("name", {});
135122
const MMM = Module.create("name");
136123

137124
await MMM.loadTranslations();
138125

139-
expect(Translator.load.callCount).toBe(0);
126+
expect(Translator.load.mock.calls).toHaveLength(0);
140127
});
141128
});
142129

@@ -150,13 +137,7 @@ describe("translations", () => {
150137
describe("parsing language files through the Translator class", () => {
151138
for (const language in translations) {
152139
it(`should parse ${language}`, async () => {
153-
const window = setupDOMEnvironment();
154-
155-
await new Promise((resolve) => {
156-
window.onload = resolve;
157-
});
158-
159-
const { Translator } = window;
140+
const { Translator } = createTranslationTestEnvironment();
160141
await Translator.load(mmm, translations[language], false);
161142

162143
expect(typeof Translator.translations[mmm.name]).toBe("object");
@@ -187,16 +168,10 @@ describe("translations", () => {
187168
};
188169

189170
// Function to initialize JSDOM and load translations
190-
const initializeTranslationDOM = (language) => {
191-
const window = setupDOMEnvironment();
192-
193-
return new Promise((resolve) => {
194-
window.onload = async () => {
195-
const { Translator } = window;
196-
await Translator.load(mmm, translations[language], false);
197-
resolve(Translator.translations[mmm.name]);
198-
};
199-
});
171+
const initializeTranslationDOM = async (language) => {
172+
const { Translator } = createTranslationTestEnvironment();
173+
await Translator.load(mmm, translations[language], false);
174+
return Translator.translations[mmm.name];
200175
};
201176

202177
beforeAll(async () => {

0 commit comments

Comments
 (0)