乐闻世界logo
搜索文章和话题

How to write tests for i18next?

2月18日 22:07

Basic Testing

Testing Translation Functionality

javascript
import i18next from 'i18next'; describe('i18next translations', () => { beforeEach(() => { i18next.init({ lng: 'en', resources: { en: { translation: { welcome: 'Welcome', greeting: 'Hello {{name}}' } } } }); }); test('should translate simple key', () => { expect(i18next.t('welcome')).toBe('Welcome'); }); test('should translate with interpolation', () => { expect(i18next.t('greeting', { name: 'John' })).toBe('Hello John'); }); });

React Component Testing

Testing Components Using useTranslation

javascript
import { render, screen } from '@testing-library/react'; import { useTranslation } from 'react-i18next'; import { I18nextProvider } from 'react-i18next'; import i18next from 'i18next'; function Welcome() { const { t } = useTranslation(); return <h1>{t('welcome')}</h1>; } describe('Welcome component', () => { const renderWithI18n = (component) => { return render( <I18nextProvider i18n={i18next}> {component} </I18nextProvider> ); }; beforeEach(() => { i18next.init({ lng: 'en', resources: { en: { translation: { welcome: 'Welcome' } } } }); }); test('should display welcome message', () => { renderWithI18n(<Welcome />); expect(screen.getByText('Welcome')).toBeInTheDocument(); }); });

Testing Language Switching

javascript
import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { useTranslation } from 'react-i18next'; import { I18nextProvider } from 'react-i18next'; import i18next from 'i18next'; function LanguageSwitcher() { const { t, i18n } = useTranslation(); return ( <div> <p>{t('currentLang')}</p> <button onClick={() => i18n.changeLanguage('zh')}>中文</button> <button onClick={() => i18n.changeLanguage('en')}>English</button> </div> ); } describe('LanguageSwitcher', () => { beforeEach(() => { i18next.init({ lng: 'en', resources: { en: { translation: { currentLang: 'English' } }, zh: { translation: { currentLang: '中文' } } } }); }); test('should switch language', async () => { render( <I18nextProvider i18n={i18next}> <LanguageSwitcher /> </I18nextProvider> ); expect(screen.getByText('English')).toBeInTheDocument(); fireEvent.click(screen.getByText('中文')); await waitFor(() => { expect(screen.getByText('中文')).toBeInTheDocument(); }); }); });

Testing Trans Component

javascript
import { render, screen } from '@testing-library/react'; import { Trans } from 'react-i18next'; import { I18nextProvider } from 'react-i18next'; import i18next from 'i18next'; function MyComponent() { return ( <Trans i18nKey="user.greeting"> Welcome <strong>{{name}}</strong> </Trans> ); } describe('Trans component', () => { beforeEach(() => { i18next.init({ lng: 'en', resources: { en: { translation: { 'user.greeting': 'Welcome <1>{{name}}</1>' } } } }); }); test('should render translated content with interpolation', () => { render( <I18nextProvider i18n={i18next}> <MyComponent /> </I18nextProvider> ); expect(screen.getByText(/Welcome/i)).toBeInTheDocument(); }); });

Mocking i18next

Create Test Utility Functions

javascript
// test-utils/i18n.js import { initReactI18next } from 'react-i18next'; import i18next from 'i18next'; export const createI18nInstance = (resources = {}) => { const instance = i18next.createInstance(); instance.use(initReactI18next).init({ lng: 'en', resources: { en: { translation: resources } } }); return instance; }; export const renderWithI18n = (component, resources = {}) => { const i18n = createI18nInstance(resources); return render( <I18nextProvider i18n={i18n}> {component} </I18nextProvider> ); };

Using Test Utilities

javascript
import { renderWithI18n } from './test-utils/i18n'; test('should render with mocked translations', () => { renderWithI18n(<MyComponent />, { welcome: 'Welcome', goodbye: 'Goodbye' }); expect(screen.getByText('Welcome')).toBeInTheDocument(); });

Testing Lazy Loading

javascript
import { render, screen, waitFor } from '@testing-library/react'; import { useTranslation } from 'react-i18next'; import { I18nextProvider } from 'react-i18next'; import i18next from 'i18next'; function LazyComponent() { const { t, ready } = useTranslation('lazy', { useSuspense: false }); if (!ready) { return <div>Loading...</div>; } return <p>{t('content')}</p>; } describe('Lazy loading', () => { beforeEach(() => { i18next.init({ lng: 'en', resources: { en: { translation: {} } } }); }); test('should show loading state initially', () => { render( <I18nextProvider i18n={i18next}> <LazyComponent /> </I18nextProvider> ); expect(screen.getByText('Loading...')).toBeInTheDocument(); }); test('should load namespace and show content', async () => { render( <I18nextProvider i18n={i18next}> <LazyComponent /> </I18nextProvider> ); i18next.addResourceBundle('en', 'lazy', { content: 'Loaded content' }); await waitFor(() => { expect(screen.getByText('Loaded content')).toBeInTheDocument(); }); }); });

Testing Missing Translations

javascript
describe('Missing translations', () => { beforeEach(() => { i18next.init({ lng: 'en', fallbackLng: 'en', saveMissing: true, missingKeyHandler: (lng, ns, key) => { console.warn(`Missing translation: ${lng}.${ns}.${key}`); }, resources: { en: { translation: { existing: 'Existing translation' } } } }); }); test('should return key when translation is missing', () => { const result = i18next.t('nonexistent'); expect(result).toBe('nonexistent'); }); test('should use fallback translation', () => { i18next.addResourceBundle('en', 'translation', { fallback: 'Fallback' }); const result = i18next.t('fallback'); expect(result).toBe('Fallback'); }); });

Integration Testing

javascript
describe('i18next integration tests', () => { test('should handle language change across components', async () => { const { rerender } = render( <I18nextProvider i18n={i18next}> <App /> </I18nextProvider> ); expect(screen.getByText('English')).toBeInTheDocument(); await i18next.changeLanguage('zh'); rerender( <I18nextProvider i18n={i18next}> <App /> </I18nextProvider> ); expect(screen.getByText('中文')).toBeInTheDocument(); }); });

Best Practices

  1. Isolated Tests: Each test should run independently without depending on other tests
  2. Mock Resources: Use mocked translation resources to avoid depending on actual files
  3. Test Utilities: Create reusable test utility functions
  4. Async Testing: Properly handle async operations like language switching and lazy loading
  5. Edge Cases: Test edge cases like missing translations and error conditions
  6. Snapshot Testing: Use snapshot testing for translated components to ensure consistency
  7. Performance Testing: Test performance when dealing with large amounts of translations
标签:i18next