7

I get this error when trying to execute simple Jest test with a form React component :

  ● <LoginForm /> › clicking the validate button › should display page title                              
                                                                                                          
    could not find react-redux context value; please ensure the component is wrapped in a <Provider>      
                                                                                                          
      14 |      const [inputPassword, setInputPassword] = useState("");                                   
      15 |                                                                                                
    > 16 |      const dispatch = useDispatch(); 

Here is the component itself :

import React, { useState, useEffect } from "react";
import { useDispatch } from "react-redux";
import { useHistory } from "react-router-dom";
import jwt_decode from "jwt-decode";
import Cookies from "js-cookie";

import post from "../../../services/request/Post";
import { setCurrentUser } from "../../../redux/action";
import "./index.scss";

const LoginForm = () => {
    const [userData, setUserData] = useState(null);
    const [inputEmail, setInputEmail] = useState("");
    const [inputPassword, setInputPassword] = useState("");

    const dispatch = useDispatch();
    const history = useHistory();

    const handleEmailChange = (e) => {
        setInputEmail(e.target.value);
    };

    const handlePasswordChange = (e) => {
        setInputPassword(e.target.value);
    };

    const handleSubmit = (e) => {
        e.preventDefault();
        setUserData({
            ...userData,
            email: inputEmail,
            password: inputPassword
        });
    };

    const handleLogin = async (data) => {
        if (data) {
            let body = {
                user: { email: data.email, password: data.password }
            };
            const response = await post("/tokens", body);
            if (response != null) {
                Cookies.set("token", response.data.token, {
                    sameSite: "strict",
                    Secure: true
                });
                const payload = {
                    type: "user",
                    id: jwt_decode(response.data.token).user_id,
                    email: userData.email,
                    username: response.data.username
                };
                dispatch(setCurrentUser(payload));
                history.push("/");
            }
        }
    };

    useEffect(() => {
        handleLogin(userData);
    }, [userData]);

    return (
        <div className="LoginForm">
            <form action="" onSubmit={handleSubmit}>
                <label htmlFor="email">Adresse email</label>
                <input
                    type="email"
                    id="email"
                    name="email"
                    value={inputEmail}
                    onChange={handleEmailChange}
                />

                <label htmlFor="password">Mot de passe</label>
                <input
                    type="password"
                    id="password"
                    name="password"
                    value={inputPassword}
                    onChange={handlePasswordChange}
                />

                <button type="submit" id="submitButton">
                    Valider
                </button>
            </form>
        </div>
    );
};

export default LoginForm;

Here is the main.jsx component (the entry point):

ReactDOM.render(
    <React.StrictMode>
        <Provider store={store}>
            <PersistGate loading={null} persistor={persistor}>
                <App />
            </PersistGate>
        </Provider>
    </React.StrictMode>,
    document.getElementById("root")
);

As one can see, I already wrapped the <App /> component in a <Provider>

Finally, here is the quite simple test I wrote:

import React from 'react';
import { render, screen } from "@testing-library/react";
// import userEvent from "@testing-library/user-event";

import LoginForm from '../components/forms/LoginForm';

describe('<LoginForm />', () => {
  describe('clicking the validate button', () => {
    beforeEach(
      render(<LoginForm />)
    );

    it("should display page title", () => {
      expect(screen.getByText("Page de connexion")).toBeInTheDocument();
      expect(screen.getByText("Adresse email")).toBeInTheDocument();
      expect(screen.getByText("Mot de passe")).toBeInTheDocument();
    })
  });
});

It is the first time I write test with React so I am kinda lost. Should I use a sort of mock store for testing environments ? If so, is it possible to do it globally, for every tested components ?

Lou
  • 148
  • 1
  • 12
  • Does this answer your question? [Testing custom hook: Invariant Violation: could not find react-redux context value; please ensure the component is wrapped in a ](https://stackoverflow.com/questions/59476912/testing-custom-hook-invariant-violation-could-not-find-react-redux-context-val) – Michael Freidgeim Feb 28 '23 at 06:36

3 Answers3

6

Yes, you should be wrapping the <LoginForm /> with a <Provider store={store}>.

You can set up a reusable function that will automatically do that for you:

https://redux.js.org/usage/writing-tests#components

markerikson
  • 63,178
  • 10
  • 141
  • 157
0
In my case, to be able to mock store and provider, I implemented a custom render function named renderWithProviders according to the redux docs to my application that was built using Typescript, Webpack, React-Redux, and Jest.

Referance

serdarsen
  • 193
  • 2
  • 8
0

You have to mock useDispatch and useSelector in your test file.

jest.mock('react-redux', () => ({
   useDispatch: jest.fn(),
   useSelector: jest.fn(),
 }));
Sikander Bakht
  • 239
  • 2
  • 8