Skip to content

Commit 7454ba7

Browse files
Copilothotlong
andcommitted
Add provider.test.tsx for @object-ui/i18n React integration
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent dc56bd9 commit 7454ba7

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { describe, it, expect, vi } from 'vitest';
2+
import { renderHook, waitFor, act } from '@testing-library/react';
3+
import React from 'react';
4+
import { I18nProvider, useObjectTranslation, useI18nContext } from '../provider';
5+
import { createI18n } from '../i18n';
6+
7+
describe('I18nProvider', () => {
8+
it('creates i18n instance from config', () => {
9+
const wrapper = ({ children }: { children: React.ReactNode }) =>
10+
React.createElement(I18nProvider, { config: { defaultLanguage: 'en', detectBrowserLanguage: false } }, children);
11+
12+
const { result } = renderHook(() => useObjectTranslation(), { wrapper });
13+
14+
expect(result.current.i18n).toBeDefined();
15+
expect(result.current.language).toBe('en');
16+
});
17+
18+
it('accepts pre-created instance', () => {
19+
const instance = createI18n({ defaultLanguage: 'fr', detectBrowserLanguage: false });
20+
21+
const wrapper = ({ children }: { children: React.ReactNode }) =>
22+
React.createElement(I18nProvider, { instance }, children);
23+
24+
const { result } = renderHook(() => useObjectTranslation(), { wrapper });
25+
26+
expect(result.current.i18n).toBeDefined();
27+
expect(result.current.language).toBe('fr');
28+
});
29+
});
30+
31+
describe('useObjectTranslation', () => {
32+
const wrapper = ({ children }: { children: React.ReactNode }) =>
33+
React.createElement(I18nProvider, { config: { defaultLanguage: 'en', detectBrowserLanguage: false } }, children);
34+
35+
it('returns t, language, changeLanguage, direction, i18n', () => {
36+
const { result } = renderHook(() => useObjectTranslation(), { wrapper });
37+
38+
expect(result.current.t).toBeTypeOf('function');
39+
expect(result.current.language).toBeTypeOf('string');
40+
expect(result.current.changeLanguage).toBeTypeOf('function');
41+
expect(result.current.direction).toBeTypeOf('string');
42+
expect(result.current.i18n).toBeDefined();
43+
});
44+
45+
it('translates keys correctly', () => {
46+
const { result } = renderHook(() => useObjectTranslation(), { wrapper });
47+
48+
expect(result.current.t('common.save')).toBe('Save');
49+
expect(result.current.t('common.cancel')).toBe('Cancel');
50+
expect(result.current.t('common.delete')).toBe('Delete');
51+
});
52+
53+
it('returns en as default language', () => {
54+
const { result } = renderHook(() => useObjectTranslation(), { wrapper });
55+
56+
expect(result.current.language).toBe('en');
57+
});
58+
59+
it('works with Chinese language', () => {
60+
const zhWrapper = ({ children }: { children: React.ReactNode }) =>
61+
React.createElement(I18nProvider, { config: { defaultLanguage: 'zh', detectBrowserLanguage: false } }, children);
62+
63+
const { result } = renderHook(() => useObjectTranslation(), { wrapper: zhWrapper });
64+
65+
expect(result.current.language).toBe('zh');
66+
expect(result.current.t('common.save')).toBe('保存');
67+
expect(result.current.t('common.cancel')).toBe('取消');
68+
});
69+
70+
it('changeLanguage updates language', async () => {
71+
const { result } = renderHook(() => useObjectTranslation(), { wrapper });
72+
73+
expect(result.current.language).toBe('en');
74+
75+
await act(async () => {
76+
await result.current.changeLanguage('zh');
77+
});
78+
79+
await waitFor(() => {
80+
expect(result.current.language).toBe('zh');
81+
});
82+
});
83+
84+
it('returns RTL direction for Arabic', () => {
85+
const arWrapper = ({ children }: { children: React.ReactNode }) =>
86+
React.createElement(I18nProvider, { config: { defaultLanguage: 'ar', detectBrowserLanguage: false } }, children);
87+
88+
const { result } = renderHook(() => useObjectTranslation(), { wrapper: arWrapper });
89+
90+
expect(result.current.direction).toBe('rtl');
91+
});
92+
});
93+
94+
describe('useI18nContext', () => {
95+
it('throws when used outside provider', () => {
96+
// Suppress console.error from React for the expected error
97+
const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
98+
99+
expect(() => {
100+
renderHook(() => useI18nContext());
101+
}).toThrow('useI18nContext must be used within an I18nProvider');
102+
103+
spy.mockRestore();
104+
});
105+
106+
it('returns context inside provider', () => {
107+
const wrapper = ({ children }: { children: React.ReactNode }) =>
108+
React.createElement(I18nProvider, { config: { defaultLanguage: 'en', detectBrowserLanguage: false } }, children);
109+
110+
const { result } = renderHook(() => useI18nContext(), { wrapper });
111+
112+
expect(result.current.language).toBe('en');
113+
expect(result.current.changeLanguage).toBeTypeOf('function');
114+
expect(result.current.direction).toBe('ltr');
115+
expect(result.current.i18n).toBeDefined();
116+
});
117+
});

0 commit comments

Comments
 (0)