Skip to content

Commit 56fef58

Browse files
πŸ§ͺ [testing] add unit tests for i18n module
🎯 What: Added a missing test file `src/__tests__/i18n.test.ts` for `src/i18n.ts` to ensure proper functioning of translation features. πŸ“Š Coverage: Tested `setLocale`, `getLocale`, `t` (including fallback and string interpolation logic), `addTranslations`, and the singleton export. ✨ Result: Improved test coverage and ensured reliability of translation utility and interpolation functions. Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com>
1 parent 72dc9e9 commit 56fef58

1 file changed

Lines changed: 90 additions & 0 deletions

File tree

β€Žsrc/__tests__/i18n.test.tsβ€Ž

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { describe, expect, test } from 'bun:test';
2+
3+
describe('I18n', () => {
4+
// Use a helper function to import the real implementation
5+
// since `../i18n` is globally mocked in `setup.ts`
6+
const getRealI18n = async () => {
7+
// Generate a random cache-buster so we get a fresh instance if needed,
8+
// although singleton is usually fine, the `setup.ts` mock needs to be bypassed.
9+
const module = await import('../i18n?real');
10+
return { I18n: module.I18n, i18nSingleton: module.default };
11+
};
12+
13+
test('setLocale and getLocale', async () => {
14+
const { I18n } = await getRealI18n();
15+
const i18n = new I18n();
16+
17+
expect(i18n.getLocale()).toBe('en'); // Default is 'en'
18+
19+
i18n.setLocale('zh');
20+
expect(i18n.getLocale()).toBe('zh');
21+
22+
i18n.setLocale('en');
23+
expect(i18n.getLocale()).toBe('en');
24+
});
25+
26+
test('basic translations and fallback', async () => {
27+
const { I18n } = await getRealI18n();
28+
const i18n = new I18n();
29+
30+
// English translation
31+
i18n.setLocale('en');
32+
expect(i18n.t('checking_update')).toBe('Checking for updates...');
33+
34+
// Chinese translation
35+
i18n.setLocale('zh');
36+
expect(i18n.t('checking_update')).toBe('ζ­£εœ¨ζ£€ζŸ₯ζ›΄ζ–°...');
37+
38+
// Fallback logic
39+
// Add translation only to 'zh', check if 'en' falls back to 'zh'
40+
i18n.addTranslations('zh', { 'only_in_zh': 'δΈ­ζ–‡δΈ“ε±ž' });
41+
i18n.setLocale('en');
42+
expect(i18n.t('only_in_zh' as any)).toBe('δΈ­ζ–‡δΈ“ε±ž');
43+
44+
// Add translation only to 'en', check if 'zh' falls back to 'en'
45+
i18n.addTranslations('en', { 'only_in_en': 'English Only' });
46+
i18n.setLocale('zh');
47+
expect(i18n.t('only_in_en' as any)).toBe('English Only');
48+
49+
// Key missing in both locales
50+
expect(i18n.t('missing_key' as any)).toBe('missing_key');
51+
});
52+
53+
test('string interpolation', async () => {
54+
const { I18n } = await getRealI18n();
55+
const i18n = new I18n();
56+
57+
i18n.setLocale('en');
58+
59+
// Normal interpolation
60+
expect(i18n.t('download_progress', { progress: 50 })).toBe('Download progress: 50%');
61+
62+
// Multiple interpolations
63+
expect(i18n.t('retry_count', { count: 1, max: 3 })).toBe('Retry attempt: 1/3');
64+
65+
// Interpolation with missing values (should leave placeholder as is)
66+
expect(i18n.t('download_progress')).toBe('Download progress: {{progress}}%');
67+
68+
// Invalid interpolation syntax (spaces) are ignored
69+
i18n.addTranslations('en', { 'invalid_syntax': 'Test {{ key }} here' });
70+
expect(i18n.t('invalid_syntax' as any, { key: 'value' })).toBe('Test {{ key }} here');
71+
});
72+
73+
test('addTranslations', async () => {
74+
const { I18n } = await getRealI18n();
75+
const i18n = new I18n();
76+
77+
i18n.addTranslations('en', { 'new_key': 'New Value' });
78+
i18n.setLocale('en');
79+
80+
expect(i18n.t('new_key' as any)).toBe('New Value');
81+
});
82+
83+
test('singleton export', async () => {
84+
const { i18nSingleton } = await getRealI18n();
85+
86+
// Verify it works
87+
expect(i18nSingleton.getLocale()).toBeDefined();
88+
expect(i18nSingleton.t('checking_update')).toBeDefined();
89+
});
90+
});

0 commit comments

Comments
Β (0)