如何在使用 react-testing-library 和 jest 完成的单元测试中启用 react-i18n 翻译文件?

问题描述 投票:0回答:4

我正在用 jest 和 react-testing-library 为我的前端应用程序进行单元测试,这是用 React 完成的。在我使用 react-i18next -library 添加国际化之前,我的单元测试运行良好。现在,当我运行测试时,它似乎没有找到/使用翻译文件,所有应该阅读的地方都留空了。我正在使用带有钩子的最新 React 版本,而不是 React.Component 我正在使用这种“const-components”:

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

国际化在实际页面中完美运行,但单元测试由于未使用翻译文件而失败,所以我认为问题在于正确模拟翻译文件。我只是为使用 this.variableName 类型的解决方案的旧反应找到一些建议解决方案,但这对我帮助不大。

我试图用 jest.fn() 模拟它,但我不确定哪个函数是我应该模拟的,以及如何从测试中正确使用 useTranslation() 函数。

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

错误消息:无法找到包含文本的元素:翻译文件标题。这可能是因为文本被多个元素打断了。在这种情况下,您可以为您的文本匹配器提供一个函数,使您的匹配器更加灵活。

简而言之:应该包含某些文本的地方现在完全是空的。

reactjs jestjs internationalization react-testing-library i18next
4个回答
24
投票

你不应该模拟翻译,而是将带有翻译库的组件渲染为高阶组件,例如;

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(); 
});

不是用 i18n.getDataByLanguage('en') 调用你的翻译文本,你可以给你的项目的默认翻译,如果它是法语调用 i18n.getDataByLanguage('fr').

也像这样更改您的组件,而不是从 props 中获取 useTranslation 钩子,而是使用钩子将其放入组件中

ComponentName.jsx

import { useTranslation } from 'react-i18next'

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

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

export default ComponentName;

10
投票

最终我得到了这样的模拟(在 App.js 中):

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

万一有人需要这个。

另外在我刚刚使用的组件内部

t={key=>key}
,它启用了这样的查询:
expect(c.getByText('json.field.in.translation')).toBeDefined();


3
投票

我是这样做的:

  1. 在单独的文件中为

    i18n
    创建配置:

     const DEFAULT_LANGUAGE = "en";
     const DEFAULT_NAMESPACE = "translations";
     const enTranslationJson={ //bring that json from your real translation file!
      "nav": {
         "home": "Home",
         "example": "Example"
       },
      "page-title": "{{pageName}} Page",
     };
    
     i18n.use(initReactI18next).init({
      lng: DEFAULT_LANGUAGE,
      fallbackLng: DEFAULT_LANGUAGE,
      ns: [DEFAULT_NAMESPACE],
      defaultNS: DEFAULT_NAMESPACE,
      debug: false,
      interpolation: {
       escapeValue: false,
      },
      resources: { [DEFAULT_LANGUAGE]: { [DEFAULT_NAMESPACE]: 
       enTranslationJson } },
      });
    
      export default i18n;
    
  2. 使用

    I18nextProvider
    覆盖渲染方法:

    import { render as rtlRender } from "@testing-library/react";
    import { I18nextProvider } from "react-i18next";
    
    const render = (ui: React.ReactElement) => {
       return rtlRender(<I18nextProvider i18n={i18n}>{ui}</I18nextProvider>);
    }
    
  3. 在测试中我使用了

    render
    函数并寻找real翻译值:

    test("home component render correctly", async () => {
      render(<Home />);
      const item = screen.getByText("Template Page");
      expect(item).toBeInTheDocument();
    });
    

0
投票

我使用

[email protected]
,这种方式适用于我的项目。

和你一样,我使用

useTranslation
t
来翻译我组件中的文本。

import React from "react";
import { useTranslation } from "react-i18next";

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

  return <div>{t("SIDEMENU.PROJECT")}</div>;
};

export default ComponentName;

我不模拟翻译,而是导入

i18n
文件并使用
I18nextProvider
包装组件。它将呈现实际的翻译。

import { render, screen } from "@testing-library/react";
import React from "react";
import { I18nextProvider } from "react-i18next";

import ComponentName from "../ComponentName";

import i18n from "@/locales/i18n";

describe("ComponentName", () => {
  it("should render translated title", () => {
    render(
      <I18nextProvider i18n={i18n}>
        <ComponentName title="SIDEMENU.PROJECT" />
      </I18nextProvider>,
    );
    const headingElement = screen.getByText(/PROJECT/i);
    const enText = screen.getByText(
      i18n.getDataByLanguage("en").translations["SIDEMENU"]["PROJECT"],
    );
    expect(headingElement).toBeInTheDocument();
    expect(enText).toBeDefined();
  });
});

希望这能有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.