Skip to content

Commit 2194ffd

Browse files
[tests] Fix and refactor e2e test "Same keys" in "translations_spec.js" (#3809)
While working on the translations (in #3792 and #3794) I realised that the e2e "Same keys" tests were not working entirely. There was also a TODO entry for this in the test, as well as a try-catch-block workaround. I therefore fixed and refactored it. I also sorted the translations in `translations/translations.js`, so that the test outputs are alphabetically.
1 parent faf15ad commit 2194ffd

File tree

3 files changed

+86
-83
lines changed

3 files changed

+86
-83
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ planned for 2025-07-01
4545
- [calendar] fix fullday event rrule until with timezone offset (#3781)
4646
- [feat] Add rule `no-undef` in config file validation to fix #3785 (#3786)
4747
- [fonts] Fix `roboto.css` to avoid error message `Unknown descriptor 'var(' in @font-face rule.` in firefox console (#3787)
48+
- [tests] Fix and refactor e2e test `Same keys` in `translations_spec.js` (#3809)
4849

4950
### Updated
5051

tests/e2e/translations_spec.js

Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -154,77 +154,79 @@ describe("Translations", () => {
154154

155155
describe("Same keys", () => {
156156
let base;
157-
let missing = [];
158157

159-
beforeAll(() => {
160-
return new Promise((done) => {
161-
const dom = new JSDOM(
162-
`<script>var translations = ${JSON.stringify(translations)}; var Log = {log: () => {}};</script>\
163-
<script src="file://${path.join(__dirname, "..", "..", "js", "translator.js")}">`,
164-
{ runScripts: "dangerously", resources: "usable" }
165-
);
158+
// Some expressions are not easy to translate automatically. For the sake of a working test, we filter them out.
159+
const COMMON_EXCEPTIONS = ["WEEK_SHORT"];
160+
161+
// Some languages don't have certain words, so we need to filter those language specific exceptions.
162+
const LANGUAGE_EXCEPTIONS = {
163+
ca: ["DAYBEFOREYESTERDAY"],
164+
cv: ["DAYBEFOREYESTERDAY"],
165+
cy: ["DAYBEFOREYESTERDAY"],
166+
en: ["DAYAFTERTOMORROW", "DAYBEFOREYESTERDAY"],
167+
fy: ["DAYBEFOREYESTERDAY"],
168+
gl: ["DAYBEFOREYESTERDAY"],
169+
hu: ["DAYBEFOREYESTERDAY"],
170+
id: ["DAYBEFOREYESTERDAY"],
171+
it: ["DAYBEFOREYESTERDAY"],
172+
"pt-br": ["DAYAFTERTOMORROW"],
173+
tr: ["DAYBEFOREYESTERDAY"]
174+
};
175+
176+
// Function to initialize JSDOM and load translations
177+
const initializeTranslationDOM = (language) => {
178+
const dom = new JSDOM("", { runScripts: "dangerously", resources: "usable" });
179+
dom.window.Log = { log: jest.fn() };
180+
dom.window.translations = translations;
181+
const translatorJs = fs.readFileSync(path.join(__dirname, "..", "..", "js", "translator.js"), "utf-8");
182+
dom.window.eval(translatorJs);
183+
184+
return new Promise((resolve) => {
166185
dom.window.onload = async () => {
167186
const { Translator } = dom.window;
168-
169-
await Translator.load(mmm, translations.de, false);
170-
base = Object.keys(Translator.translations[mmm.name]).sort();
171-
done();
187+
await Translator.load(mmm, translations[language], false);
188+
resolve(Translator.translations[mmm.name]);
172189
};
173190
});
174-
});
191+
};
175192

176-
afterAll(() => {
177-
console.log(missing);
193+
beforeAll(async () => {
194+
// Using German as the base rather than English, since
195+
// some words do not have a direct translation in English.
196+
const germanTranslations = await initializeTranslationDOM("de");
197+
base = Object.keys(germanTranslations).sort();
178198
});
179199

180-
// Using German as the base rather than English, since
181-
// at least one translated word doesn't exist in English.
182-
for (let language in translations) {
183-
if (language === "de") {
184-
continue;
185-
}
200+
for (const language in translations) {
201+
if (language === "de") continue;
186202

187203
describe(`Translation keys of ${language}`, () => {
188204
let keys;
189205

190-
beforeAll(() => {
191-
return new Promise((done) => {
192-
const dom = new JSDOM(
193-
`<script>var translations = ${JSON.stringify(translations)}; var Log = {log: () => {}};</script>\
194-
<script src="file://${path.join(__dirname, "..", "..", "js", "translator.js")}">`,
195-
{ runScripts: "dangerously", resources: "usable" }
196-
);
197-
dom.window.onload = async () => {
198-
const { Translator } = dom.window;
199-
200-
await Translator.load(mmm, translations[language], false);
201-
keys = Object.keys(Translator.translations[mmm.name]).sort();
202-
done();
203-
};
204-
});
206+
beforeAll(async () => {
207+
const languageTranslations = await initializeTranslationDOM(language);
208+
keys = Object.keys(languageTranslations).sort();
205209
});
206210

207-
it(`${language} keys should be in base`, () => {
211+
it(`${language} should not contain keys that are not in base language`, () => {
208212
keys.forEach((key) => {
209-
expect(base.indexOf(key)).toBeGreaterThanOrEqual(0);
213+
expect(base).toContain(key, `Translation key '${key}' in language '${language}' is not present in base language`);
210214
});
211215
});
212216

213-
it(`${language} should contain all base keys`, () => {
214-
// TODO: when all translations are fixed, use
215-
// expect(keys).toEqual(base);
216-
// instead of the try-catch-block
217-
218-
try {
219-
expect(keys).toEqual(base);
220-
} catch (e) {
221-
if (e.message.match(/expect.*toEqual/)) {
222-
const diff = base.filter((key) => !keys.includes(key));
223-
missing.push(`Missing Translations for language ${language}: ${diff}`);
224-
} else {
225-
throw e;
226-
}
217+
it(`${language} should contain all base keys (excluding defined exceptions)`, () => {
218+
let filteredBase = base.filter((key) => !COMMON_EXCEPTIONS.includes(key));
219+
let filteredKeys = keys.filter((key) => !COMMON_EXCEPTIONS.includes(key));
220+
221+
if (LANGUAGE_EXCEPTIONS[language]) {
222+
const exceptions = LANGUAGE_EXCEPTIONS[language];
223+
filteredBase = filteredBase.filter((key) => !exceptions.includes(key));
224+
filteredKeys = filteredKeys.filter((key) => !exceptions.includes(key));
227225
}
226+
227+
filteredBase.forEach((baseKey) => {
228+
expect(filteredKeys).toContain(baseKey, `Translation key '${baseKey}' is missing in language '${language}'`);
229+
});
228230
});
229231
});
230232
}

translations/translations.js

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,49 @@
11
let translations = {
22
en: "translations/en.json", // English
3-
nl: "translations/nl.json", // Dutch
3+
af: "translations/af.json", // Afrikaans
4+
bg: "translations/bg.json", // Bulgarian
5+
ca: "translations/ca.json", // Catalan
6+
cs: "translations/cs.json", // Czech
7+
cv: "translations/cv.json", // Chuvash
8+
cy: "translations/cy.json", // Welsh (Cymraeg)
9+
da: "translations/da.json", // Danish
410
de: "translations/de.json", // German
11+
el: "translations/el.json", // Greek
512
eo: "translations/eo.json", // Esperanto
13+
es: "translations/es.json", // Spanish
14+
et: "translations/et.json", // Estonian
615
fi: "translations/fi.json", // Suomi
716
fr: "translations/fr.json", // French
817
fy: "translations/fy.json", // Frysk
9-
es: "translations/es.json", // Spanish
10-
ca: "translations/ca.json", // Catalan
11-
cv: "translations/cv.json", // Chuvash
12-
nb: "translations/nb.json", // Norsk bokmål
13-
nn: "translations/nn.json", // Norsk nynorsk
14-
pt: "translations/pt.json", // Português
15-
"pt-br": "translations/pt-br.json", // Português Brasileiro
16-
sv: "translations/sv.json", // Svenska
18+
gl: "translations/gl.json", // Galego
19+
gu: "translations/gu.json", // Gujarati
20+
he: "translations/he.json", // Hebrew
21+
hi: "translations/hi.json", // Hindi
22+
hr: "translations/hr.json", // Croatian
23+
hu: "translations/hu.json", // Hungarian
1724
id: "translations/id.json", // Indonesian
25+
is: "translations/is.json", // Icelandic
1826
it: "translations/it.json", // Italian
19-
"zh-cn": "translations/zh-cn.json", // Simplified Chinese
20-
"zh-tw": "translations/zh-tw.json", // Traditional Chinese
2127
ja: "translations/ja.json", // Japanese
22-
pl: "translations/pl.json", // Polish
23-
el: "translations/el.json", // Greek
24-
da: "translations/da.json", // Danish
25-
tr: "translations/tr.json", // Turkish
26-
ru: "translations/ru.json", // Russian
27-
af: "translations/af.json", // Afrikaans
28-
hu: "translations/hu.json", // Hungarian
29-
is: "translations/is.json", // Icelandic
30-
et: "translations/et.json", // Estonian
3128
ko: "translations/ko.json", // Korean
29+
lt: "translations/lt.json", // Lithuanian
30+
"ms-my": "translations/ms-my.json", // Malay
31+
nb: "translations/nb.json", // Norsk bokmål
32+
nl: "translations/nl.json", // Dutch
33+
nn: "translations/nn.json", // Norsk nynorsk
34+
pl: "translations/pl.json", // Polish
35+
pt: "translations/pt.json", // Português
36+
"pt-br": "translations/pt-br.json", // Português Brasileiro
3237
ro: "translations/ro.json", // Romanian
33-
cy: "translations/cy.json", // Welsh (Cymraeg)
34-
bg: "translations/bg.json", // Bulgarian
35-
cs: "translations/cs.json", // Czech
36-
hr: "translations/hr.json", // Croatian
38+
ru: "translations/ru.json", // Russian
3739
sk: "translations/sk.json", // Slovak
40+
sv: "translations/sv.json", // Svenska
41+
th: "translations/th.json", // Thai
3842
tlh: "translations/tlh.json", // Klingon
39-
"ms-my": "translations/ms-my.json", // Malay
40-
he: "translations/he.json", // Hebrew
43+
tr: "translations/tr.json", // Turkish
4144
uk: "translations/uk.json", // Ukrainian
42-
hi: "translations/hi.json", // Hindi
43-
gu: "translations/gu.json", // Gujarati
44-
gl: "translations/gl.json", // Galego
45-
lt: "translations/lt.json", // Lithuanian
46-
th: "translations/th.json" // Thai
45+
"zh-cn": "translations/zh-cn.json", // Simplified Chinese
46+
"zh-tw": "translations/zh-tw.json" // Traditional Chinese
4747
};
4848

4949
if (typeof module !== "undefined") {

0 commit comments

Comments
 (0)