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' });
});
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: