Mocking useTranslation for i18n in JEST not working
Asked Answered
T

4

6

My react component uses translations from i18next and I'm trying to create tests for it using JEST. However, nothing is getting translated and I have tried mocking the useTranslation function below:

const useMock : any = [(k: any) => k, {}];
useMock.t = (k: any) => k;
useMock.i18n = {};

jest.mock('react-i18next', () => ({
  // this mock makes sure any components using the translate HoC receive the t function as a prop
  /* tslint:disable-next-line:variable-name */
  useTranslation: () => useMock,
}));

What am I doing wrong?

Tendance answered 23/5, 2019 at 0:27 Comment(0)
S
4

Create a file __mocks__/react-i18next.js (the folder __mocks__ being next to node_modules, in the same parent folder), containing:

module.exports = {
  useTranslation: () => ({
    t: key => key,
  }),
}

In your test script, import useTranslation normally, but define the mock to be used.

import {useTranslation} from 'react-i18next'
/* Other imports and code */

jest.mock('react-i18next')
/* Your test code using useTranslation */
Sidman answered 16/6, 2020 at 14:34 Comment(2)
In my case, creating __mocks__/react-i18next.js with your code snippet was enough to get rid of this warning. I didn't have to explicitly call jest.mock('react-i18next') or import useTranslation in my tests.Malta
If I only need to translate a single key and would prefer not to declare a mock file with strings, is that doable? I'm not testing a translation as such. I'm getting a key as a lookup to our strings in an external service obtaining a string that is enhanced in a few places by the actual data. Then, I'd like to test that content to have both the boilerplate text (in English, no other languages required) and the inserted parameters. So I want to set the state of my store and then - boom - see that it's reflected in the component's text.Luvenialuwana
E
3

Create a mock file: __mocks__/react-i18next.useTranslation.js with this content:

module.exports = () => {
  return () => ({
    t: key => key
  })
}
Earp answered 17/7, 2019 at 17:16 Comment(0)
U
1

Try like this:

jest.mock('react-i18next', () => ({
  useTranslation: () => ({ t: () => ['key'] }),
  Trans: () => jest.fn(),
  t: () => jest.fn(),
}));
Unsphere answered 19/5, 2023 at 10:4 Comment(1)
Your answer could be improved with the help of supporting informationTether
B
0

i share my config i hope that it can help you

my folder are this : enter image description here

my mocks is this :

react-i18next.js
const React = require('react');
const reactI18next = require('react-i18next');
let root = __dirname;
var fs = require('fs');

//console.log(root.replace("src\\__mocks__","public\\assets\\i18n\\{{ns}}.json"))
const hasChildren = (node) => node && (node.children || (node.props && node.props.children));

const getChildren = (node) =>
    node && node.children ? node.children : node.props && node.props.children;

const renderNodes = (reactNodes) => {
    if (typeof reactNodes === 'string') {
        return reactNodes;
    }

    return Object.keys(reactNodes).map((key, i) => {
        const child = reactNodes[key];
        const isElement = React.isValidElement(child);

        if (typeof child === 'string') {
            return child;
        }
        if (hasChildren(child)) {
            const inner = renderNodes(getChildren(child));
            return React.cloneElement(child, { ...child.props, key: i }, inner);
        }
        if (typeof child === 'object' && !isElement) {
            return Object.keys(child).reduce((str, childKey) => `${str}${child[childKey]}`, '');
        }

        return child;
    });
};

let language = "en"
const useMock = [(k) => k, {}];
let traduccions = root.replace("src\\__mocks__", `public\\assets\\i18n\\commons\\${language}.json`)

let changeLanguage = (lng = "en") => {
    useMock.language = lng;
}

useMock.i18n = { 
    ns: ['commons'],
    defaultNS: 'commons',
    changeLanguage,
    language,
};
useMock.t = (k) => { 
    const result =()=> fs.readFileSync(traduccions,"utf8", function (err, data) {
        if (err) {
           return console.error(err);
        }
       return data.toString()
     });  
    let termsToSearch = k.replace(`${useMock.i18n.defaultNS}:`,'').split(".")
    let res =JSON.parse(result());
    termsToSearch.forEach(element => {
         res=res[element];
    });
    return res;
};



/**
 * commons:language.language
 */



module.exports = {
    // this mock makes sure any components using the translate HoC receive the t function as a prop
    withTranslation: () => (Component) => (props) => <Component t={(k) => k} {...props} />,
    Trans: ({ children }) =>
        Array.isArray(children) ? renderNodes(children) : renderNodes([children]),
    Translation: ({ children }) => children((k) => k, { i18n: {} }),
    useTranslation: () => useMock,

    // mock if needed
    I18nextProvider: reactI18next.I18nextProvider,
    initReactI18next: reactI18next.initReactI18next,
    setDefaults: reactI18next.setDefaults,
    getDefaults: reactI18next.getDefaults,
    setI18n: reactI18next.setI18n,
    getI18n: reactI18next.getI18n,
};

The major parte is of the documentation of i18n i only add the way to show the right traduction

https://react.i18next.com/misc/testing https://github.com/i18next/react-i18next/blob/master/example/test-jest/src/__mocks__/react-i18next.js

Bawd answered 13/11, 2021 at 2:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.