如何在使用 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=>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 翻译文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Firebase 在 Web 上托管 Flutter?它的效果如何?
如何在自动布局中使用约束标识符以及如何使用标识符更改约束? [迅速]
如何使用 Java 在 selenium webdriver 中打开新选项卡,或者如何使用 selenium webdriver 使用动作类在 selenium 中按 ctrl + T [重复]