在 Jest 中存根 I18next useTranslation 钩子不会触发 toHaveBeenCalled [英] Stubbing I18next useTranslation hook in Jest doesn't trigger toHaveBeenCalled

查看:28
本文介绍了在 Jest 中存根 I18next useTranslation 钩子不会触发 toHaveBeenCalled的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试存根/监视翻译,而不仅仅是嘲笑它,即使在这种最基本的情况下,我似乎也无法触发它.

/*** 组件名称.jsx*/import { useTranslation } from react-i18next";导出默认函数 ComponentName() {const { t } = useTranslation();return 

t(`index:path`)

}/*** 组件名称.test.jsx*/从酶"导入{浅};从./ComponentName"导入组件名称;import { useTranslation } from react-i18next";jest.mock(react-i18next", () => ({useTranslation: () =>({ t: jest.fn(key => key) })}));it(调用翻译函数", () => {const 包装器 = 浅(<组件名称/>);期望(useTranslation().t).toHaveBeenCalled();});

当我在 ComponentName.jsx 文件 中放入一个 console.log(t) 时,它正确地显示它是一个模拟函数.如果我将 t() 放在 ComponentName.test.jsx 文件中,它就会通过.

有没有办法存根,以便我最终可以用 toHaveBeenCalledWith 标记它?还是我被降级为对组件执行 contains("index:path") ?


所以,当我更新@felixmosh 的回答时

/*** 组件名称.test.jsx*/从'酶'导入{安装};从'react-i18next'导入{ I18nextProvider };describe('', () => {it('调度 SORT_TABLE', () => {const i18nextMock = {t: jest.fn(key => key),};const 酶包装器 = 安装(<I18nextProvider i18n={i18nextMock}><某些组件/></I18nextProvider>);期望(i18nextmock.t).toHaveBeenCalled()});});/*** 组件名称.jsx*/import { useTranslation } from react-i18next";导出默认函数 ComponentName() {const { t } = useTranslation();return 

t(`index:path`)

}

同样的问题.如果 ta string" 而不是 jest.fn(),当我 console.log tComponentName.jsx 中,当我将 console.log t 作为 jest.fn(key=> 键),我正确地得到了一个函数.

但是当我调用它时,我不明白.

是否有可能发送到 I18nextProvider 的实例不是同一个实例?

解决方案

2 你应该在代码中改进的地方:

  1. useTransaltion 是一个需要 context 的钩子,确保你用 i18nextProvider 包裹你的组件.
  2. 事实上,您将嵌套组件切换 shallowmount.
  3. 不需要模拟任何东西,i18next 内置了对测试的支持.为了启用它,请使用 cimode 作为 lng测试配置i18next时.

//i18nForTests.js从i18next"导入 i18n;从'react-i18next'导入{initReactI18next};i18n.use(initReactI18next).init({lng: 'cimode',//----- ^//有一个围绕完整应用程序使用的公共命名空间ns: ['翻译'],默认NS:'翻译',插值:{escapeValue: false,//不需要反应!!},资源:{ en:{ 翻译:{} } },});导出默认 i18n;

//SomeComponent.test.js从'酶'导入{安装};从'react-i18next'导入{ I18nextProvider };从 '../i18nForTests' 导入 i18n;describe('', () => {it('调度 SORT_TABLE', () => {const 酶包装器 = 安装(<I18nextProvider i18n={i18n}><某些组件/></I18nextProvider>);酶Wrapper.find('.sort').simulate('click');期望(enzymeWrapper.find('#some-text').text()).toEqual('MY_TRANS_KEY');});});

带有模拟 I18next 的版本

//i18nextMock.js导出 const i18nextMock = {t: jest.fn(),//对其他 i18next 字段执行相同操作};//SomeComponent.test.js从'酶'导入{安装};从'react-i18next'导入{ I18nextProvider };从'../i18nextMock'导入i18nextMock;describe('', () => {it('调度 SORT_TABLE', () => {const 酶包装器 = 安装(<I18nextProvider i18n={i18nextMock}><某些组件/></I18nextProvider>);酶Wrapper.find('.sort').simulate('click');期望(enzymeWrapper.find('#some-text').text()).toEqual('MY_TRANS_KEY');});});

I'm trying to stub/spy the translation, not just mock it, and I can't seem to get it to trigger even in this most base case.

/**
 * ComponentName.jsx
 */

import { useTranslation } from "react-i18next";

export default function ComponentName() {
  const { t } = useTranslation();

  return <div>t(`index:path`)</div>
}

/**
 * ComponentName.test.jsx
 */

import { shallow } from "enzyme";
import ComponentName from "./ComponentName";
import { useTranslation } from "react-i18next";
jest.mock("react-i18next", () => ({
  useTranslation: () => ({ t: jest.fn(key => key) })
}));

it("calls the translation function", () => {
  const wrapper = shallow(<ComponentName />);

  expect(useTranslation().t).toHaveBeenCalled();
});

When I drop a console.log(t) in the ComponentName.jsx file, it correctly displays that it's a mocked function. If I put t() in the ComponentName.test.jsx file, it passes.

Is there a way to stub this so that I can eventually tag it with toHaveBeenCalledWith? Or am I relegated to doing contains("index:path") on the component?


Edit: So, when I updated on @felixmosh's answer

/**
 * ComponentName.test.jsx
 */


import { mount } from 'enzyme';
import { I18nextProvider } from 'react-i18next';

describe('<SomeComponent />', () => {
  it('dispatches SORT_TABLE', () => {
    const i18nextMock = {
      t: jest.fn(key => key),
    };
    const enzymeWrapper = mount(
      <I18nextProvider i18n={i18nextMock}>
        <SomeComponent />
      </I18nextProvider>
    );

    expect(i18nextmock.t).toHaveBeenCalled()
  });
});

/**
 * ComponentName.jsx
 */

import { useTranslation } from "react-i18next";

export default function ComponentName() {
  const { t } = useTranslation();

  return <div>t(`index:path`)</div>
}

It's the same issue. If t was "a string" instead of jest.fn(), when i console.log t in ComponentName.jsx, I correctly get "a string", when I console.log t as jest.fn(key => key), I correctly get a function.

But when I call it, I don't get it.

Is it possible that it's not the same instance that's being sent to I18nextProvider?

解决方案

2 Things that you should improve in your code:

  1. useTransaltion is a hook which requires context, make sure you wrap you component with i18nextProvider.
  2. As of the fact you will have nested components switch shallow with mount.
  3. There is no need for mocking anything, i18next has a built-it support of tests. In order to enable it use cimode as the lng when configuring your i18next for tests.

// i18nForTests.js

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

i18n.use(initReactI18next).init({
  lng: 'cimode',
  // ----- ^
  // have a common namespace used around the full app
  ns: ['translations'],
  defaultNS: 'translations',

  interpolation: {
    escapeValue: false, // not needed for react!!
  },

  resources: { en: { translations: {} } },
});

export default i18n;

// SomeComponent.test.js
import { mount } from 'enzyme';
import { I18nextProvider } from 'react-i18next';
import i18n from '../i18nForTests';

describe('<SomeComponent />', () => {
  it('dispatches SORT_TABLE', () => {
    const enzymeWrapper = mount(
        <I18nextProvider i18n={i18n}>
          <SomeComponent />
        </I18nextProvider>
    );
    enzymeWrapper.find('.sort').simulate('click');

    expect(enzymeWrapper.find('#some-text').text()).toEqual('MY_TRANS_KEY');
  });
});

Edit: Version with mocked I18next

// i18nextMock.js
export const i18nextMock = {
  t: jest.fn(),
  // Do the same for other i18next fields
};

// SomeComponent.test.js
import { mount } from 'enzyme';
import { I18nextProvider } from 'react-i18next';
import i18nextMock from '../i18nextMock';

describe('<SomeComponent />', () => {
  it('dispatches SORT_TABLE', () => {
    const enzymeWrapper = mount(
        <I18nextProvider i18n={i18nextMock}>
          <SomeComponent />
        </I18nextProvider>
    );
    enzymeWrapper.find('.sort').simulate('click');

    expect(enzymeWrapper.find('#some-text').text()).toEqual('MY_TRANS_KEY');
  });
});

这篇关于在 Jest 中存根 I18next useTranslation 钩子不会触发 toHaveBeenCalled的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆