Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I enable react-i18n translation file to be used in the unit tests done with react-testing-library and jest?

I am making unit tests with jest and react-testing-library for my frontend application which is done with React. My unit tests worked nicely before I added the internationalization with react-i18next -library. Now when I run the tests, it seems that it doesn't find/use the translation files and all places where there should read something, are left empty. I'm using the newest react version with hooks and instead of React.Component I am using this kind of "const-components":

    const ComponentName = ({t}) => {
        return(
          <p>{t('example')}</p>
        )}
      export default ComponentName;

The internationalization works perfectly in the actual page but just that the unit tests fail due to not using the translation-file so I think the problem is with correctly mocking the translation files. I am only finding some suggestion solutions for the older react using this.variableName -type of solutions, which however doesn't help me much.

I have tried to mock it with jest.fn(), but I am not sure which function is the one, which I should mock and how to utilize the useTranslation() -function correctly from the tests.

    import React from 'react';
    import { useTranslation, Trans } from 'react-i18next';
    import { render } from '@testing-library/react';
    import ComponentName from './ComponentName';

    import '../locales/i18n';

    test('renders all documents in the list', () => {
      const mockUseTranslation = jest.fn();

      const { t, i18n } = mockUseTranslation();

      // const t = jest.fn();
      const c = render(<ComponentName t={t} />);
      expect(c.getByText('Translation File Title')).toBeDefined();
      expect(
        c.getAllByText(
          'Lorem ipsum'
        ).length
      ).toBe(3);
    });

Error message: Unable to find an element with the text: Translation File Title. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

So in short: the place, which should contain certain text is now totally empty.

like image 631
Sonja Laurila Avatar asked Jul 22 '19 14:07

Sonja Laurila


People also ask

What is i18n in React?

Internationalization or i18n is the design and development of a product, application, or document content that enables easy localization for target audiences that vary in culture, region, or language. Thus, React i18n is concerned with localizing React applications for different locales.

How to translate react app with react-i18next?

How to translate your React app with react-i18next 1 Setup your first React app. We're setting up a small React application to learn how localization works. ... 2 Add internationalization. ... 3 Translation IDs vs Translation strings. ... 4 Translate your application. ... 5 Changing languages. ... 6 Maintain translation files. ...

How to use react-i18next module in React-Native?

The react-i18next module is a widely used module available for multilingual setup on react js and also for react-native. So let us get started on how to use that module in our project. Create a react project. 2. Now install react-i18next and i18next packages in your project.

What is react i18n?

Internationalization or i18n is the design and development of a product, application, or document content that enables easy localization for target audiences that vary in culture, region, or language. Thus, React i18n is concerned with localizing React applications for different locales.

What is the best internationalization library for react i18n?

You can refer to react-intl documentation here. In this tutorial, we will be using the react-intl library to apply internationalization as it is the best and most popular library for React i18n to date. The react-intl-universal internationalization package, which is built by Alibaba Group, is based on the react-intl library.


2 Answers

You should not mock the translation, instead render the component with translation library as Higher Order Component, for example;

import React from 'react';
import i18n from '../../../i18n' // your i18n config file
import { render } from '@testing-library/react';
import ComponentName from './ComponentName';
import { I18nextProvider } from 'react-i18next'

test('renders all documents in the list', () => {
    const c = render(
      <I18nextProvider i18n={i18n}> // actually give translation to your component
         <ComponentName />
      </I18nextProvider>
    );
    // example if you have a key called example
    expect(c.getByText(i18n.getDataByLanguage('en').translation.example)).toBeDefined(); 
});

Instead of calling your translation texts with i18n.getDataByLanguage('en') , you can give the default translation of your project, if it is French call it by i18n.getDataByLanguage('fr').

Also change your component like this, instead of taking useTranslation hook from props, take it inside the component with hooks

ComponentName.jsx

import { useTranslation } from 'react-i18next'

const ComponentName = () => {
  const { t } = useTranslation()

  return(
    <p>{t('example')}</p>
  )}

export default ComponentName;
like image 182
onuriltan Avatar answered Oct 18 '22 18:10

onuriltan


Eventually I got the mock working like this (in App.js):

jest.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: key => key,
    i18n: { changeLanguage: jest.fn() }
  })
}));

In case somebody needs this.

Additionally inside components I was just using t={key=>key}, which enabled queries like this: expect(c.getByText('json.field.in.translation')).toBeDefined();

like image 9
Sonja Laurila Avatar answered Oct 18 '22 20:10

Sonja Laurila