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

Posted

技术标签:

【中文标题】如何在使用 react-testing-library 和 jest 完成的单元测试中启用 react-i18n 翻译文件?【英文标题】:How can I enable react-i18n translation file to be used in the unit tests done with react-testing-library and jest? 【发布时间】:2019-11-30 13:13:46 【问题描述】:

我正在使用 jest 和 react-testing-library 为使用 React 完成的前端应用程序进行单元测试。在我使用 react-i18next -library 添加国际化之前,我的单元测试运行良好。现在,当我运行测试时,它似乎没有找到/使用翻译文件,并且所有应该阅读内容的地方都是空的。我正在使用带有钩子的最新反应版本,而不是 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);
    );

错误消息:无法找到具有以下文本的元素:翻译文件标题。这可能是因为文本被多个元素分解。在这种情况下,你可以为你的文本匹配器提供一个函数,让你的匹配器更加灵活。

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

【问题讨论】:

我认为你不应该嘲笑 i18n 库。如果您使用debug,您会在页面中看到什么?文字是空的吗? i18n 库是否使用提供程序来工作? react.i18next.com/misc/… 我没有在我的应用程序中使用 redux、provider 或 store,所以这对我没有帮助。这些测试也与酶有关,我正在使用反应测试库。如果我使用 debug() 工具,它看起来是空的(在这个地方,应该有翻译的文本),正如我之前提到的:/ 所以应该以某种方式模拟翻译或将其带入测试。 【参考方案1】:

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

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;

【讨论】:

我不知道该对你说什么,但非常感谢你,因为我整天都坐在这个问题前面 我遵循了这个并且它有效。例如,我有另一种语言要测试,例如日语。我应该创建另一个 i18n 配置,以便它呈现日语字符串,然后检查测试文件中的字符串吗?【参考方案2】:

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

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

如果有人需要这个。

另外在组件内部,我只使用了t=key=&gt;key,它启用了这样的查询:expect(c.getByText('json.field.in.translation')).toBeDefined();

【讨论】:

你不能用这种方法测试像count books 这样的值 你有没有偶然在某个地方发布的例子?【参考方案3】:

我是这样做的:

    在单独的文件中为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;
    

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

    在测试中,我使用 render 函数并寻找 real 翻译值:

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

【讨论】:

以上是关于如何在使用 react-testing-library 和 jest 完成的单元测试中启用 react-i18n 翻译文件?的主要内容,如果未能解决你的问题,请参考以下文章

如何在发布管道中使用输出变量

如何在Hive&Impala中使用UDF

如何使用 Firebase 在 Web 上托管 Flutter?它的效果如何?

如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]

如何在android中使用WCF服务?

如何使用 Java 在 selenium webdriver 中打开新选项卡,或者如何使用 selenium webdriver 使用动作类在 selenium 中按 ctrl + T [重复]