Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

react-intl with react-testing-library gives Invalid hook call error

in our project we use react-intl for internationalisation. We are using jest as the testing framework and we decided to move our unit test utility library from enzyme to react-testing-library. But now, since there is no shallow rendering, I have to provide <IntlProvider ... /> in the test myself, no problem. But even if I do that, when testing terminal says Invalid hook call. Hooks can only be called inside of the body of a function component but when I run the project locally, no errors just runs normally as expected. P.S in the tests, Apollo provider works normally.

FirstNameFor.test.tsx

import { IntlProvider } from 'react-intl';
import { createMockClient } from 'mock-apollo-client';
import { ApolloProvider as ApolloProviderHooks } from '@apollo/react-hooks';
import { ApolloProvider } from 'react-apollo';

const wrapper = (mockProps, mockClient) => {
  return (
    <ApolloProvider client={mockClient}>
      <ApolloProviderHooks client={mockClient}>
        <IntlProvider locale="en">
          <FirstNameForm
            handleNext={mockProps.handleNext}
            onboardingState={mockProps.onboardingState}
            setHelpContent={mockProps.setHelpContent}
            updateOnboardingState={mockProps.updateOnboardingState}
          />
        </IntlProvider>
      </ApolloProviderHooks>
    </ApolloProvider>
  );
};

describe('FirstNameForm Container', () => {
  afterEach(() => {
    jest.clearAllMocks();
    cleanup();
  });

  it('should match snapshot', () => {
    // Arrange
    const mockProps = {
      handleNext: jest.fn(),
      onboardingState: {},
      setHelpContent: jest.fn(),
      updateOnboardingState: jest.fn(),
    };
    const mockClient = createMockClient();

    // Act
    const component = render(wrapper(mockProps, mockClient));

    // Assert
    expect(component).toMatchSnapshot();
  });
});

FirstNameForm.tsx

export const FirstNameForm: React.FC<StepContentProps> = props => {
  const [showMessageMutation] = useShowMessageMutation();
  const intl = useIntl();

  const formik = useFormik<FirstNameFormValues>({
   ...,
  });

  return <FirstNameFormComponent formik={formik} intl={intl} />;
};

Terminal Screenshot enter image description here

package.json

{
  "private": true,
  "proxy": "http://localhost:5000",
  "version": "0.1.57",
  "scripts": {
    "dev": "yarn graphql:generate && SKIP_PREFLIGHT_CHECK=true react-app-rewired start",
    "build": "SKIP_PREFLIGHT_CHECK=true react-app-rewired build",
    "testonly": "SKIP_PREFLIGHT_CHECK=true react-app-rewired test --env=jsdom",
    "coverage": "SKIP_PREFLIGHT_CHECK=true react-app-rewired test --env=jsdom --coverage",
  },
  "jest": {
    "coveragePathIgnorePatterns": [
      "/node_modules/",
      "src/types/",
      "src/config/analytics/mp.d.ts",
      "src/config/analytics/ua.d.ts"
    ],
    "snapshotSerializers": [
      "enzyme-to-json/serializer"
    ]
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "resolutions": {
    "@types/react": "16.8.17"
  },
  "dependencies": {
    "@apollo/react-hooks": "3.1.3",
    "animated-scroll-to": "1.2.2",
    "apollo-cache": "1.3.2",
    "apollo-cache-inmemory": "1.6.3",
    "apollo-client": "2.6.3",
    "apollo-link": "1.2.12",
    "apollo-link-context": "1.0.18",
    "apollo-link-error": "1.1.11",
    "apollo-link-http": "1.5.15",
    "apollo-link-ws": "1.0.18",
    "apollo-utilities": "1.3.2",
    "big.js": "5.2.2",
    "copy-to-clipboard": "3.2.0",
    "core-js": "3.0.1",
    "date-fns": "1.30.1",
    "downloadjs": "1.4.7",
    "formik": "2.1.1",
    "graphql": "14.3.0",
    "graphql-subscriptions": "1.1.0",
    "graphql-tag": "2.10.1",
    "graphql-tools": "4.0.4",
    "history": "4.9.0",
    "intl": "1.2.5",
    "js-cookie": "2.2.0",
    "lodash": "4.17.11",
    "owasp-password-strength-test": "1.3.0",
    "qrcode.react": "0.9.3",
    "query-string": "6.5.0",
    "react": "16.8.6",
    "react-apollo": "3.1.3",
    "react-dom": "16.8.6",
    "react-google-recaptcha": "1.1.0",
    "react-intl": "3.1.8",
    "react-router-dom": "5.1.0",
    "recompose": "0.30.0",
    "regenerator-runtime": "0.13.2",
    "subscriptions-transport-ws": "0.9.16",
    "validator": "10.11.0",
    "victory": "34.0.0",
    "yup": "0.27.0"
  },
  "devDependencies": {
    "@apollo/react-testing": "3.1.3",
    "@babel/cli": "7.4.4",
    "@babel/core": "7.4.4",
    "@babel/preset-env": "7.4.4",
    "@graphql-codegen/add": "1.8.1",
    "@graphql-codegen/cli": "1.8.1",
    "@graphql-codegen/fragment-matcher": "1.8.1",
    "@graphql-codegen/typescript": "1.8.1",
    "@graphql-codegen/typescript-operations": "1.8.1",
    "@graphql-codegen/typescript-react-apollo": "1.8.1",
    "@testing-library/react": "10.0.4",
    "@testing-library/jest-dom": "5.8.0",
    "@types/testing-library__react": "10.0.1",
    "@types/big.js": "4.0.5",
    "@types/downloadjs": "1.4.1",
    "@types/enzyme": "3.10.5",
    "@types/graphql": "14.2.0",
    "@types/js-cookie": "2.2.2",
    "@types/node": "12.0.0",
    "@types/owasp-password-strength-test": "1.3.0",
    "@types/prop-types": "15.7.1",
    "@types/qrcode.react": "0.8.2",
    "@types/query-string": "6.3.0",
    "@types/react": "16.8.17",
    "@types/react-dom": "16.8.4",
    "@types/react-google-recaptcha": "1.0.0",
    "@types/react-router-dom": "5.1.0",
    "@types/react-test-renderer": "16.9.0",
    "@types/recompose": "0.30.6",
    "@types/validator": "10.11.0",
    "@types/victory": "33.1.0",
    "@types/ws": "6.0.1",
    "@types/yup": "0.26.13",
    "babel-loader": "8.0.6",
    "enzyme": "3.11.0",
    "enzyme-adapter-react-16": "1.15.2",
    "enzyme-to-json": "3.4.4",
    "jest-canvas-mock": "2.2.0",
    "jest-localstorage-mock": "2.4.0",
    "merge-graphql-schemas": "1.5.8",
    "npm-run-all": "4.1.5",
    "patch-package": "6.1.2",
    "postinstall-postinstall": "2.0.0",
    "react-app-rewired": "2.1.3",
    "react-scripts": "3.3.0",
    "react-test-renderer": "16.8.6",
    "source-map-explorer": "1.8.0",
    "ts-jest": "25.3.1",
    "ts-node": "8.1.0",
    "typescript": "3.5.3"
  }
}
like image 756
onuriltan Avatar asked Jan 27 '20 10:01

onuriltan


People also ask

How do you fix error invalid hook call Hooks can only be called inside of the body of a function component?

If the error persists, try to delete your node_modules and package-lock. json (not package. json ) files, re-run npm install and restart your IDE. The error is often caused by having multiple versions of react in the same project.

How do you call a hook inside a function in a React?

The rules of React Hooks clearly state: Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function. React Hooks need to be called in the same order each time the component renders.

Which is incorrect about React Hooks?

There are three common reasons you might be seeing it: You might have mismatching versions of React and React DOM. You might be breaking the Rules of Hooks. You might have more than one copy of React in the same app.

How do you test React Hooks?

If you need to test a custom Hook, you can do so by creating a component in your test, and using your Hook from it. Then you can test the component you wrote. To reduce the boilerplate, we recommend using React Testing Library which is designed to encourage writing tests that use your components as the end users do.


1 Answers

The error comes from React itself, and most likely has nothing to do with react-intl.

There's a good chance you have multiple instances of React in conflict, for some reason only occurring in the test environment. I suspect it might have to do with react-app-rewired, not sure though.

The steps from the official help doc should help reveal whether duplicate Reacts is the source of the problem.

If that is the reason, here's some of the top solutions from the community:

  • Modify your webpack config to resolve the react alias (discussion)
  resolve: {
    alias: {
        react: path.resolve('./node_modules/react'),
      }
  },
  • Modify your webpack config to set react as an external (PR example)
  externals: {
    react: 'react'
  }
  • Or one of these other miscellaneous approaches
like image 177
mrc114 Avatar answered Sep 18 '22 04:09

mrc114