jest.mock('react-i18next', () => ({
// this mock makes sure any components using the translate HoC receive the t function as a prop
withTranslation: () => Component => {
Component.defaultProps = { ...Component.defaultProps, t: (i18nKey) => i18nKey };
// or with TypeScript:
//Component.defaultProps = { ...Component.defaultProps, t: (i18nKey: string) => i18nKey };
return Component;
},
}));
Or, when using the useTranslation hook instead of withTranslation, mock it like:
jest.mock('react-i18next', () => ({
// this mock makes sure any components using the translate hook can use it without a warning being shown
useTranslation: () => {
return {
t: (i18nKey) => i18nKey,
// or with TypeScript:
//t: (i18nKey: string) => i18nKey,
i18n: {
changeLanguage: () => new Promise(() => {}),
},
};
},
initReactI18next: {
type: '3rdParty',
init: () => {},
}
}));
or, you can also spy the t function:
// implementation
import React from 'react';
import { useTranslation } from 'react-i18next';
export default function CustomComponent() {
const { t } = useTranslation();
return <div>{t('some.key', { some: 'variable' })}</div>;
}
// test
import React from 'react';
import { mount } from 'enzyme';
import UseTranslationWithInterpolation from './UseTranslationWithInterpolation';
import { useTranslation } from 'react-i18next';
jest.mock('react-i18next', () => ({
useTranslation: jest.fn(),
}));
it('test render', () => {
const useTranslationSpy = useTranslation;
const tSpy = jest.fn((str) => str);
useTranslationSpy.mockReturnValue({
t: tSpy,
i18n: {
changeLanguage: () => new Promise(() => {}),
},
});
const mounted = mount(<UseTranslationWithInterpolation />);
// console.log(mounted.debug());
expect(mounted.contains(<div>some.key</div>)).toBe(true);
// If you want you can also check how the t function has been called,
// but basically this is testing your mock and not the actual code.
expect(tSpy).toHaveBeenCalledTimes(1);
expect(tSpy).toHaveBeenLastCalledWith('some.key', { some: 'variable' });
});
Testing without stubbing
Alternatively, you could also test I18next without stubbing anything, by providing the correct configuration and fully wrapping your container in the provider.
Example configuration for testing
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n
.use(initReactI18next)
.init({
lng: 'en',
fallbackLng: 'en',
// have a common namespace used around the full app
ns: ['translationsNS'],
defaultNS: 'translationsNS',
debug: true,
interpolation: {
escapeValue: false, // not needed for react!!
},
resources: { en: { translationsNS: {} } },
});
export default i18n;
Example test using this configuration
import React from 'react';
import { Provider } from 'react-redux';
import { mount } from 'enzyme';
import { I18nextProvider } from 'react-i18next';
import configureStore from 'redux-mock-store';
import ContactTable from './ContactTable';
import actionTypes from '../constants';
import i18n from '../i18nForTests';
const mockStore = configureStore([]);
const store = mockStore({ contacts: [ ] });
it('dispatches SORT_TABLE', () => {
const enzymeWrapper = mount(
<Provider store={store}>
<I18nextProvider i18n={i18n}>
<ContactTable />
</I18nextProvider>
</Provider>
);
enzymeWrapper.find('.sort').simulate('click');
const actions = store.getActions();
expect(actions).toEqual([{ type: actionTypes.SORT_TABLE }]);
});
As translations aren't provided, this.props.i18n.language will be undefined. In case your application relies on that value you can mock resources by adding these lines to the object passed to init: