'react-i18next:: You will need to pass in an i18next instance by using initReactI18next warning thrown in Jest unit test
I am using react-i18next
in my app to great effect but when I run the unit tests against my component:
const OptionList = ({
definition,
name,
status = EMutationStatus.IDLE,
onChange = () => null,
value = [],
}: IOptionListProps): React.ReactElement => {
const { t } = useTranslation();
const { options } = definition;
return (
<Select
name={name}
data-testid="optionList"
id={name}
placeholder={t('COMMON.PLEASE_SELECT')}
onChange={e => onChange(e.currentTarget.value)}
defaultValue={value[0]}
disabled={status === EMutationStatus.LOADING}
>
{options.map((option: string): React.ReactElement => {
return (
<option key={option} value={option}>
{option}
</option>
);
})}
</Select>
);
};
It throws the following warning when running the unit test suite:
react-i18next:: You will need to pass in an i18next instance by using initReactI18next
I am a bit lost as I have set up react-i18next
for unit testing in a custom render function for react-testing-library
.
My i18n
instance for tests:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
i18n.use(initReactI18next).init({
lng: 'cimode', // setting lng to 'cimode' will cause the t function to always return the key.
// ----- ^
// have a common namespace used around the full app
ns: ['translations'],
defaultNS: 'translations',
interpolation: {
escapeValue: false, // not needed for react!!
},
resources: { en: { translations: {} }, zh: { translations: {} }, th: { translations: {} } },
});
export default i18n;
And my custom render function is as follows:
export function render(
ui: RenderUI,
{ wrapper, ...options }: RenderOptions = {}
): RenderResult {
if (!wrapper) {
// eslint-disable-next-line no-param-reassign
wrapper = ({ children }) => (
<BrowserRouter>
<ChakraProvider resetCSS theme={theme}>
<QueryClientProvider client={testQueryClient}>
<I18nextProvider i18n={i18n}>{children}</I18nextProvider>
</QueryClientProvider>
</ChakraProvider>
</BrowserRouter>
);
}
return defaultRender(ui, { wrapper, ...options });
}
It is only a warning so not a big deal but am confused as to why this is throwing here as I believe I have set up the Provider as outlined in the docs here:
https://react.i18next.com/misc/testing
An anyone help me get rid of this warning?
UPDATE
I tried adding the suggested jest mock of the useTranslation
hook from the same testing link:
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: (str: string): string => str,
};
},
}));
But still I get the same warning.
Solution 1:[1]
Did you try to call i18n.init()
inside beforeEach hook? And i18n should be the instance of your instantiated i18n instance.
The only difference that in my case I have named export of the i18n instance.
import { i18n } from "../../services/Internationalization";
describe('testSuite', () => {
beforeEach(() => {
i18n.init();
});
});
And in i18n.ts I have to do:
i18n.use(initReactI18Next).init(...some configs);
export { i18n };
Solution 2:[2]
One modification for RyanP13s proposal,
I return an array as expected return value from useTranslation()
, works now fine for me:
jest.mock('react-i18next', () => ({
useTranslation: () => {
return [/* t */ (str: string): string => str, /* i18n */ { language: 'cimode' }]
},
}))
Solution 3:[3]
This worked for me. You can find more info in the official documentation.
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: (str) => str,
i18n: {
changeLanguage: () => new Promise(() => {}),
},
};
},
}));
Solution 4:[4]
While it's not the official solution, I found that creating an instance of i18n specifically for testing worked nicely. It renders the actual strings and you don't have to mock useTranslation
, which is the usual recommendation.
Create a file called i18nForTests
.
// i18nForTests.js
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import { fooTranslation } from '/translations/foo'
import { barTranslation } from '/translations/bar'
i18n
.use(initReactI18next)
.init({
lng: 'foo',
fallbackLng: 'foo',
ns: ['foobar'],
defaultNS: 'foobar',
debug: true,
resources: {
'foo': fooTranslation,
'bar': barTranslation
}
})
export default i18n
Then import and initialize this heinous hackery in jest.setup.js
.
Note: if you don't have jest.setup.js
, use this in whichever setup file you do have (see jest.config.js > setupFiles
). If you don't have any setup files, create one.
// jest.setup.js
import i18n from 'i18nForTests'
i18n.init()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Andrew Trends |
Solution 2 | matthias |
Solution 3 | MWO |
Solution 4 | John |