17

包.json

"moduleNameMapper": {
  "i18next": "<rootDir>/__mocks__/i18nextMock.js"
}

i18n.js

import i18n from 'i18next'
import XHR from 'i18next-xhr-backend'
// import Cache from 'i18next-localstorage-cache'
import LanguageDetector from 'i18next-browser-languagedetector'

i18n
  .use(XHR)
  // .use(Cache)
  .use(LanguageDetector)
  .init({
    fallbackLng: 'en',
    // wait: true, // globally set to wait for loaded translations in translate hoc
    lowerCaseLng: true,
    load: 'languageOnly',
    // have a common namespace used around the full app
    ns: ['common'],
    defaultNS: 'common',
    debug: true,

    // cache: {
    //   enabled: true
    // },

    interpolation: {
      escapeValue: false, // not needed for react!!
      formatSeparator: ',',
      format: function (value, format, lng) {
        if (format === 'uppercase') return value.toUpperCase()
        return value
      }
    }
  })

export default i18n

i18nextMock.js

/* global jest */
const i18next = jest.genMockFromModule('react-i18next')
i18next.t = (i) => i
i18next.translate = (c) => (k) => k

module.exports = i18next

由于某种原因,开玩笑的单元测试没有得到组件。

这是一个单元测试:

import React from 'react'
import { Provider } from 'react-redux'
import { MemoryRouter } from 'react-router-dom'
import { mount } from 'enzyme'

import { storeFake } from 'Base/core/storeFake'
import Container from '../container'

describe('MyContainer (Container) ', () => {
  let Component;

  beforeEach(() => {
    const store = storeFake({})

    const wrapper = mount(
      <MemoryRouter>
        <Provider store={store}>
          <Container />
        </Provider>
      </MemoryRouter>
    )

    Component = wrapper.find(Container)
  });

  it('should render', () => {
    // Component is undefined here
    expect(Component.length).toBeTruthy()
  })
})
4

4 回答 4

9

您不需要模拟该t功能,只translate需要一个。对于第二个,您对参数的使用令人困惑,而且您需要返回一个组件。

我能够让它在我的项目中发挥作用。这是我的模拟文件和我的 Jest 配置

笑话配置

"moduleNameMapper": {
    "react-i18next": "<rootDir>/__mocks__/reacti18nextMock.js"
}

要模拟的源代码react-i18next

/* global jest */
import React from 'react'

const react_i18next = jest.genMockFromModule('react-i18next')

const translate = () => Component => props => <Component t={() => ''} {...props} />

react_i18next.translate = translate

module.exports = react_i18next
于 2018-03-05T19:25:13.313 回答
6

我在开玩笑的测试中使用了 Atemu 的 anwser,但最终在模拟中得到了以下一行:

module.exports = {t: key => key};

还修改了 jest 配置,因为我从“i18next”导入了“t”:

"moduleNameMapper": {
    "i18next": "<rootDir>/__mocks__/reacti18nextMock.js"
}
于 2018-04-20T18:11:09.437 回答
4

在我的例子中,使用带有 TypeScript 的 useTranslation 钩子,如下所示:

const reactI18Next: any = jest.createMockFromModule('react-i18next');

reactI18Next.useTranslation = () => {
  return {
    t: (str: string) => str,
    i18n: {
      changeLanguage: () => new Promise(() => {}),
    },
  };
};

module.exports = reactI18Next;

export default {};

jest.config.ts: _

const config: Config.InitialOptions = {
  verbose: true,
  moduleNameMapper: {
    'react-i18next': '<rootDir>/__mocks__/react-i18next.ts',
  },
};
于 2020-11-30T02:06:55.847 回答
0

“按原样”返回密钥并不是最好的。我们使用英文文本作为键,最好“评估”我们传入的值(即t('{{timePeriod}} left')评估为:'5 days left')。在这种情况下,我创建了一个辅助函数来执行此操作。以下是所需的笑话和额外文件:

Jest 配置(即 jest.config.js):

  moduleNameMapper: {
    'react-i18next': '<rootDir>/src/tests/i18nextReactMocks.tsx',
    'i18next': '<rootDir>/src/tests/i18nextMocks.ts',
    // ...
  },

i18nextMocks.ts:

function replaceBetween(startIndex: number, endIndex: number, original: string, insertion: string) {
  const result = original.substring(0, startIndex) + insertion + original.substring(endIndex);
  return result;
}

export function mockT(i18nKey: string, args?: any) {
  let key = i18nKey;

  while (key.includes('{{')) {
    const startIndex = key.indexOf('{{');
    const endIndex = key.indexOf('}}');

    const currentArg = key.substring(startIndex + 2, endIndex);
    const value = args[currentArg];

    key = replaceBetween(startIndex, endIndex + 2, key, value);
  }

  return key;
}

const i18next: any = jest.createMockFromModule('i18next');
i18next.t = mockT;
i18next.language = 'en';
i18next.changeLanguage = (locale: string) => new Promise(() => {});

export default i18next;

i18nextReactMocks.tsx:

import React from 'react';
import * as i18nextMocks from './i18nextMocks';

export const useTranslation = () => {
  return {
    t: i18nextMocks.mockT,
    i18n: {
      changeLanguage: () => new Promise(() => {}),
    },
  };
};

export const Trans = ({ children }) => <React.Fragment>{children}</React.Fragment>;

我会免费提供模拟单元测试:)

import * as i18nextMocks from './i18nextMocks';

describe('i18nextMocks', () => {
  describe('mockT', () => {
    it('should return correctly with no arguments', async () => {
      const testText = `The company's new IT initiative, code named Phoenix Project, is critical to the
        future of Parts Unlimited, but the project is massively over budget and very late. The CEO wants
        Bill to report directly to him and fix the mess in ninety days or else Bill's entire department
        will be outsourced.`;

      const translatedText = i18nextMocks.mockT(testText);

      expect(translatedText).toBe(testText);
    });

    test.each`
      testText                            | args                                          | expectedText
      ${'{{fileName}} is invalid.'}       | ${{ fileName: 'example_5.csv' }}              | ${'example_5.csv is invalid.'}
      ${'{{fileName}} {is}.'}             | ${{ fileName: '   ' }}                        | ${'    {is}.'}
      ${'{{number}} of {{total}}'}        | ${{ number: 0, total: 999 }}                  | ${'0 of 999'}
      ${'There was an error:\n{{error}}'} | ${{ error: 'Failed' }}                        | ${'There was an error:\nFailed'}
      ${'Click:{{li}}{{li2}}{{li_3}}'}    | ${{ li: '', li2: 'https://', li_3: '!@#$%' }} | ${'Click:https://!@#$%'}
      ${'{{happy}}y✔{{sad}}{{laugh}}'}  | ${{ happy: '', sad: '', laugh: '' }}    | ${'y✔'}
    `('should return correctly while handling arguments in different scenarios', ({ testText, args, expectedText }) => {
      const translatedText = i18nextMocks.mockT(testText, args);

      expect(translatedText).toBe(expectedText);
    });
  });

  describe('language', () => {
    it('should return language', async () => {
      const language = i18nextMocks.default.language;

      expect(language).toBe('en');
    });
  });
});
于 2021-10-21T07:24:03.753 回答