Svetoslav Dimitrov
Svetoslav Dimitrov

Reputation: 929

Jest & Enzyme test error with React Context API

I am testing a React app with Jest & Enzyme. When I run npm run test I get the error in UserContext.jsx that is imported in MainPage.jsx. How can I fix that?

Error message

Invariant Violation: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app

      11 | };
      12 | 
    > 13 | export const useUserValue = () => useContext(UserContext);
         |                                   ^

UserContext.jsx

import React, {createContext, useContext, useReducer} from "react";

export const UserContext = createContext();

export const UserProvider = ({reducer, initialState, children}) => {
    return(
        <UserContext.Provider value={useReducer(reducer, initialState)}>
            {children}
        </UserContext.Provider>
    )
};

export const useUserValue = () => useContext(UserContext);

MainPage.test.js

import React from 'react';
import 'jest-styled-components';

import { configure, shallow, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import MainPage from "./MainPage";
import {useUserValue} from "../Context/UserContext";

configure({adapter: new Adapter()});

describe('Main Page Component', () => {

    it('exists', () => {
        const wrapper = shallow(<MainPage />, {context: useUserValue()});
        expect(wrapper).toMatchSnapshot();
    });
});

MainPage.jsx

import React, {useEffect, useState} from 'react';
import {useUserValue} from "../Context/UserContext";

export default function MainPage(props) {
    const [{ user }, dispatch] = useUserValue();

    return (
        <React.Fragment>
           {user.name}
        </React.Fragment>
    );
}

Upvotes: 1

Views: 2710

Answers (1)

Estus Flask
Estus Flask

Reputation: 223318

The error says what is the problem:

Hooks can only be called inside of the body of a function component

Here the hook is incorrectly used outside the component:

const wrapper = shallow(<MainPage />, {context: useUserValue()});

It should have been {context: someContext }, but the problem is that Enzyme renderer accepts a context for legacy React context that cannot affect context consumers and functional components in particular.

Currently shallow doesn't support context providers and needs to use mount:

const wrapper = mount(
 <UserContext.Provider value={...}>
   <MainPage />
 </UserContext.Provider>
);

Since useUserValue is located in its own module, it could be tested separately and mocked in components where it's used, this way it can be used with shallow.

This error can also occur if there are multiple copies or mismatching versions of React and ReactDOM, but this is not the case.

Upvotes: 1

Related Questions