Next-i18next: How to test a component that is using HOC withNameSpaces

Created on 21 Feb 2019  路  8Comments  路  Source: isaachinman/next-i18next

Hi, I am currently using Jest and Enzyme and trying to update my test suites after adding translation on most my components.
Do you have ideas how to archieve this or any documentation?

Without changing anything, the error clearly point out to react-i18next: "NamespacesConsumerComponent.render (node_modules/react-i18next/dist/commonjs/NamespacesConsumer.js:220:33)"

I actually tried something like this https://react.i18next.com/misc/testing based on react-i18next documentation but unfortunately the i18nForTests.js just can't be imported at all...

Most helpful comment

By following the doc (v9 in my case, see the link). I used this mock react-next example
https://github.com/i18next/react-i18next/blob/7325cc39e1b9791bbc0e87c1748a303028cc91c8/example/test-jest/__mocks__/react-i18next.js

and moduleNameMapper in my jest.config.js to map module to this mock, here's my jest config:

module.exports = {
  setupFiles: ['<rootDir>/jest.setup.js'],
  testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/', '__*.js'],
  snapshotSerializers: ["enzyme-to-json/serializer"],
  setupTestFrameworkScriptFile: "./node_modules/jest-enzyme/lib/index.js",
  // verbose: true,
  collectCoverage : true,
  coverageDirectory: '.coverage',
  collectCoverageFrom: ['client/components/*.js', 'client/containers/*.js'],
  "coverageThreshold": {
    "global": {
      "branches": 80,
      "functions": 80,
      "lines": 80,
      "statements": 80
    }
  },
  // static imported assets
  "moduleNameMapper": {
    "react-i18next": "<rootDir>/client/utils/tests/mock-react-i18next.js",
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/client/utils/tests/fileMock.js",
    "\\.(css|less)$": "<rootDir>/client/utils/tests/mock-style.js"
  }
}

All 8 comments

Please post a more descriptive account of the issue you are facing, and the solution you would like to achieve.

Well my app.js is wrapped by hoc appWithTranslation.

Take a simple component wrapped by hoc withNamespaces, let's call it MyTranslatedComponent.js

// @flow
import React from 'react';
import { withNamespaces } from '../utils/i18n'

type Props = {
  t: Function,
}

class MyTranslatedComponent extends React.PureComponent<Props> {
  render() {
    const { t } = this.props

    return (
      <div>
        {t('hello')}
      </div>
    )
  }
}

export default withNamespaces('common')(MyTranslatedComponent)

in components/MyTranslatedComponent.test.js Try to mount or render such component with Enzyme naively and you'll get TypeError: Cannot read property 'wait' of null. Note that the shallow works somehow...

describe('MyTranslatedComponent without any props', () => {
  it('Should shallow correctly"', () => {
    const component = shallow(<MyTranslatedComponent />)
    console.log(component.debug())
    expect(component).toMatchSnapshot();
  })

  it('Should render correctly"', () => {
    const component = render(<MyTranslatedComponent />)
    console.log(component)
    expect(component).toMatchSnapshot();
  })

  it('Should mount correctly"', () => {
    const component = mount(<MyTranslatedComponent />)
    console.log(component)
    expect(component).toMatchSnapshot();
  })

})
TypeError: Cannot read property 'wait' of null
at NamespacesConsumerComponent.render (node_modules/react-i18next/dist/commonjs/NamespacesConsumer.js:220:33)
      at finishClassComponent (node_modules/react-dom/cjs/react-dom.development.js:14535:31)
      at updateClassComponent (node_modules/react-dom/cjs/react-dom.development.js:14490:24)
      at beginWork (node_modules/react-dom/cjs/react-dom.development.js:15438:16)
      at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:19106:12)
      at workLoop (node_modules/react-dom/cjs/react-dom.development.js:19146:24)
      at renderRoot (node_modules/react-dom/cjs/react-dom.development.js:19229:7)
      at performWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:20136:7)
      at performWork (node_modules/react-dom/cjs/react-dom.development.js:20048:7)
      at performSyncWork (node_modules/react-dom/cjs/react-dom.development.js:20022:3)
      at requestWork (node_modules/react-dom/cjs/react-dom.development.js:19891:5)
      at scheduleWork (node_modules/react-dom/cjs/react-dom.development.js:19705:5)
      at scheduleRootUpdate (node_modules/react-dom/cjs/react-dom.development.js:20366:3)
      at updateContainerAtExpirationTime (node_modules/react-dom/cjs/react-dom.development.js:20394:10)
      at updateContainer (node_modules/react-dom/cjs/react-dom.development.js:20451:10)
      at ReactRoot.Object.<anonymous>.ReactRoot.render (node_modules/react-dom/cjs/react-dom.development.js:20747:3)      at node_modules/react-dom/cjs/react-dom.development.js:20884:14
      at unbatchedUpdates (node_modules/react-dom/cjs/react-dom.development.js:20253:10)
      at legacyRenderSubtreeIntoContainer (node_modules/react-dom/cjs/react-dom.development.js:20880:5)
      at Object.render (node_modules/react-dom/cjs/react-dom.development.js:20949:12)
      at Object.render (node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:367:114)
      at new ReactWrapper (node_modules/enzyme/build/ReactWrapper.js:134:16)
      at mount (node_modules/enzyme/build/mount.js:21:10)
      at Object.<anonymous> (__tests__/components/MyTranslatedComponent.test.js:44:23)

I'll come back later with some solutions I tried based react-i18n doc

@Renaud009 That error is coming from react-i18next - specifically NamespacesConsumer. Could be a context issue? Just like with other HOCs (thinking of Redux, etc), you will need to either mock withNamespaces, or properly mount the component with a provider wrapper instead of shallow mounting.

This is not specific to next-i18next, but just the way it works when testing these type of React trees.

There are some examples in the react-i18next repo, but I'm pretty hesitant to maintain anything like that here.

Let me know if you have any other questions.

@isaachinman Yes I tried the __mocks__/react-i18next.js couple days ago, but just figured out since you guys are still using v9, we need to use and older version of the file https://github.com/i18next/react-i18next/blob/7325cc39e1b9791bbc0e87c1748a303028cc91c8/example/test-jest/__mocks__/react-i18next.js

Then it's easy to test the component wrapped by hoc withNamespaces:

const component = mount(<MyTranslatedComponent t={(k) => 'translate hardcoded'} />); 

Thanks for the quick replies

You can keep track of our upgrade to v10 via #164. Glad you found a solution!

@Renaud009 How do you resolve the problem ?? i still have the same problem than you.
TypeError: Cannot read property 'wait' of null

Also i tried your solution without success

const component = mount(<MyTranslatedComponent t={(k) => 'translate hardcoded'} />);

By following the doc (v9 in my case, see the link). I used this mock react-next example
https://github.com/i18next/react-i18next/blob/7325cc39e1b9791bbc0e87c1748a303028cc91c8/example/test-jest/__mocks__/react-i18next.js

and moduleNameMapper in my jest.config.js to map module to this mock, here's my jest config:

module.exports = {
  setupFiles: ['<rootDir>/jest.setup.js'],
  testPathIgnorePatterns: ['<rootDir>/.next/', '<rootDir>/node_modules/', '__*.js'],
  snapshotSerializers: ["enzyme-to-json/serializer"],
  setupTestFrameworkScriptFile: "./node_modules/jest-enzyme/lib/index.js",
  // verbose: true,
  collectCoverage : true,
  coverageDirectory: '.coverage',
  collectCoverageFrom: ['client/components/*.js', 'client/containers/*.js'],
  "coverageThreshold": {
    "global": {
      "branches": 80,
      "functions": 80,
      "lines": 80,
      "statements": 80
    }
  },
  // static imported assets
  "moduleNameMapper": {
    "react-i18next": "<rootDir>/client/utils/tests/mock-react-i18next.js",
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/client/utils/tests/fileMock.js",
    "\\.(css|less)$": "<rootDir>/client/utils/tests/mock-style.js"
  }
}

@Renaud009 If you put that in a __mocks__ dir like the example, jest will pick it up automatically.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ddereszewski picture ddereszewski  路  3Comments

denny7 picture denny7  路  6Comments

chayakornwc picture chayakornwc  路  6Comments

romaincointepas picture romaincointepas  路  6Comments

dimensi picture dimensi  路  4Comments