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
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"
}
}
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.
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.
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.
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.
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:
react
alias (discussion) resolve: {
alias: {
react: path.resolve('./node_modules/react'),
}
},
react
as an external (PR example) externals: {
react: 'react'
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With