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

问题描述

我试图对翻译进行存根/间谍,而不仅仅是模拟它,即使在这种最基本的情况下,我似乎也无法触发它。

  / ** 
* ComponentName.jsx
* /

import {useTranslation}来自 react-i18next ;

导出默认函数ComponentName(){
const {t} = useTranslation();

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

/ **
* ComponentName.test.jsx
* /

从酶中导入{浅};
从 ./ComponentName导入ComponentName;
import {useTranslation} from react-i18next;
jest.mock( react-i18next,()=>({
useTranslation:()=>({t:jest.fn(key => key)})
}));

it(调用翻译函数,()=> {
const wrapper = shallow(< ComponentName />);

期望(useTranslation()。t).toHaveBeenCalled();
});

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

是否有一种方法可以存根,以便最终使用 toHaveBeenCalledWith 对其进行标记?还是我被降级为对该组件执行 contains( index:path)




编辑:所以,当我更新@felixmosh的答案

  / ** 
* ComponentName.test .jsx
* /


从酶导入{mount};从 react-i18next导入
{I18nextProvider};

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;

导出默认函数ComponentName(){
const {t} = useTranslation();

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

这是同样的问题。如果 t 字符串 而不是 jest.fn(),当我在 ComponentName.jsx 中的console.log t 时,我正确地得到了字符串 ,当我用 jest.fn(key => key)console.log t ,我正确地获得了一个函数。


但是当我调用它时,却没有。


解决方案

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


  1. useTransaltion 是需要上下文的钩子,请确保使用 i18nextProvider 包装组件。

  2. 事实上,您将拥有嵌套的组件开关带有 mount

  3. 无需嘲笑任何东西, i18next 具有对测试的内置支持。
    为了启用它,请使用作为 lng 配置测试 i18next 时。


  // i18nForTests.js 

从'i18next'导入i18n;
从 react-i18next导入{initReactI18next;

i18n.use(initReactI18next).init({
lng:'cimode',
// ----- ^
//具有公共命名空间在整个应用程序中使用
ns:['translations'],
defaultNS:'translations',

插值:{
escapeValue:false,//不需要
},

资源:{zh:{翻译:{}}},
});

出口默认值i18n;


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

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

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

编辑:带有模拟的I18next的版本

  // i18nextMock.js 
导出常量i18nextMock = {
t:jest.fn(),
//对其他i18next字段
执行相同的操作};

// SomeComponent.test.js
从酶导入{mount};从 react-i18next导入
{I18nextProvider};
从 ../i18nextMock导入i18nextMock;

describe('< SomeComponent />',()=> {
it('dispatches SORT_TABLE',()=> {
constaseWrapper =安装(
< I18nextProvider i18n = {i18nextMock}>
< SomeComponent />
< / I18nextProvider>
);
aseWerapper.find('。 sort')。simulate('click');

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

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

07-10 12:16