Ahmed Adnan
Ahmed Adnan

Reputation: 11

Mocking the functions inside a reactjs component using vitest

I have a component in my reactjs project. The code is given below -

import jwt_decode from "jwt-decode";
import { createContext, useEffect, useState } from "react";

export const AuthContext = createContext();

export const AuthProvider = (props) => {
  const [isLoggedIn, setIsLoggedIn] = useState(
    localStorage.getItem("isLoggedIn") === "true"
  );

  const [browserCookie, setBrowserCookie] = useState(document.cookie);

  useEffect(() => {
      try {
        jwt_decode(document.cookie);
      } catch (error) {
        setIsLoggedIn(false);
        return;
      }
  }, [browserCookie]);

  useEffect(() => {
    localStorage.setItem("isLoggedIn", isLoggedIn);
  }, [isLoggedIn]);

  return (
    <AuthContext.Provider value={{ isLoggedIn, setIsLoggedIn, browserCookie, setBrowserCookie }}>
      {props.children}
    </AuthContext.Provider>
  );
};

I am trying to write unit tests for this code using vitest and react-testing-library. I have written the following code for testing -

import React from "react";
import { vi } from 'vitest';
import jwt_decode from "jwt-decode";
import { render, screen } from "@testing-library/react";
import { AuthProvider } from "../contexts/authContext";

describe("AuthProvider", () => {
  test("renders children without errors", () => {
    render(
      <AuthProvider>
        <div>Test Child</div>
      </AuthProvider>
    );

    const childElement = screen.getByText("Test Child");
    expect(childElement).toBeInTheDocument();
  });


  test('sets isLoggedIn to false if cookie decoding fails', () => {
    
    vi.spyOn(jwt_decode).mockImplementation(() => {
        throw new Error("Decoding error");
    });
    
    const useEffectSpy = vi.spyOn(AuthProvider, "useEffect");
    useEffectSpy.mockImplementation(() => {
      throw new Error("Decoding error");
    });

    render(
      <AuthProvider>
        <div>Test Child</div>
      </AuthProvider>
    );
  
    expect(screen.queryByText('Test Child')).not.toBeInTheDocument();
  });

});

But I am getting an error for the second test because I think I am not mocking the jwt_decode() function properly. The error is given below -

Error: undefined does not exist
 ❯ src/__tests__/authContext.test.jsx:22:8
     20|   test('sets isLoggedIn to false if cookie decoding fails', () => {
     21|     
     22|     vi.spyOn(jwt_decode).mockImplementation(() => {
       |                             ^
     23|         throw new Error("Decoding error");
     24|     });

Can anyone please help me with the correct test code that mocks the function properly?

Upvotes: 1

Views: 4126

Answers (1)

rozza2058
rozza2058

Reputation: 678

vitest.spyOn takes two arguments: the object on which you want to insert a spy, and the name of the method you're spying on. In this situation, you're not calling a method on an object, as jwt_decode is a default export.

My recommendation would be to mock the module, like so:

import jwt_decode from "jwt_decode";

vi.mock("jwt_decode");

test('...', () => {
  // If using TS:
  vi.mocked(jwt_decode).mockImplementation(...);

  // If using pure JS:
  jwt_decode.mockImplementation(...);
});

Upvotes: 0

Related Questions