Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: How to mock Auth0 for testing with Jest

I'm using React(react-create-app and TypeScript). Login is made with Auth0.

I want to write tests with Jest, and I found this ressource which is basically the only thing around that speaks about Mocking the Auth0 object.

So my code looks like this:

import React from "react";
import ReactDOM from "react-dom";
import TopBar from "./index";
import {
  useAuth0
} from "react-auth0-spa";

const user = {
  email: "[email protected]",
  email_verified: true,
  sub: "google-oauth2|12345678901234"
};

// intercept the useAuth0 function and mock it
jest.mock("react-auth0-spa");

describe("First test", () => {
  beforeEach(() => {
    // Mock the Auth0 hook and make it return a logged in state
    useAuth0.mockReturnValue({
      isAuthenticated: true,
      user,
      logout: jest.fn(),
      loginWithRedirect: jest.fn()
    });
  });

  it("renders without crashing", () => {
    const div = document.createElement("div");
    ReactDOM.render( < TopBar / > , div);
  });
});

But I end stuck with this error:

Property 'mockReturnValue' does not exist on type '() => IAuth0Context | undefined'.ts(2339)

I'm a bit lost here, any help would be greatly appreciated!

like image 735
tmos Avatar asked Jan 31 '20 19:01

tmos


People also ask

How do you use Jest mock in React?

Default Export To mock a React component, the most straightforward approach is to use the jest. mock function. You mock the file that exports the component and replace it with a custom implementation. Since a component is basically a function, the mock should also return a function.

How do you create mock data in testing Jest?

Note: In order to mock properly, Jest needs jest. mock('moduleName') to be in the same scope as the require/import statement. Here's a contrived example where we have a module that provides a summary of all the files in a given directory. In this case, we use the core (built in) fs module.


2 Answers

Spent an hour or so figuring this out myself. Problem stems from incorrect types being applied to useAuth0 after modifying mock return value. My solution was to use mocked from 'ts-jest/utils'. You can add Roles, Scope etc to user object also. (see adminUser object)

import { render, screen } from "@testing-library/react";
import { useAuth0 } from "@auth0/auth0-react";
import { mocked } from "ts-jest/utils";

const user = {
    email: "[email protected]",
    email_verified: true,
    sub: "google-oauth2|12345678901234",
};

const adminUser = {
    email: "[email protected]",
    email_verified: true,
    sub: "google-oauth2|12345678901234",
    "https://<<API_URL>>/roles": ["admin", "superuser"],
};


jest.mock("@auth0/auth0-react");

const mockedUseAuth0 = mocked(useAuth0, true);

describe("TopNav Component Tests - Logged in", () => {
    beforeEach(() => {
        mockedUseAuth0.mockReturnValue({
            isAuthenticated: true,
            user,
            logout: jest.fn(),
            loginWithRedirect: jest.fn(),
            getAccessTokenWithPopup: jest.fn(),
            getAccessTokenSilently: jest.fn(),
            getIdTokenClaims: jest.fn(),
            loginWithPopup: jest.fn(),
            isLoading: false,
        });
    });
    test("Logout Button displays when logged in", () => {
        render(
                <TopNav />
        );
        const loginButton = screen.getByText(/Logout/i);
        expect(loginButton).toBeInTheDocument();
    });
    test("Make sure Admin Panel Button doesnt show without Role", () => {
        render(
                <TopNav />
        );
        const adminPanelButton = screen.queryByText(/Admin Panel/i);
        expect(adminPanelButton).toBeNull();
    });
});

describe("TopNav Component Tests - Admin User", () => {
    beforeEach(() => {
        mockedUseAuth0.mockReturnValue({
            isAuthenticated: true,
            user: adminUser,
            logout: jest.fn(),
            loginWithRedirect: jest.fn(),
            getAccessTokenWithPopup: jest.fn(),
            getAccessTokenSilently: jest.fn(),
            getIdTokenClaims: jest.fn(),
            loginWithPopup: jest.fn(),
            isLoading: false,
        });
    });
    test("Admin Panel Button displays", () => {
        render(
            <TopNav />
        );
        const adminPanelButton = screen.getByText(/Admin Panel/i);
        expect(adminPanelButton).toBeInTheDocument();
    });
});
like image 185
Sam Duff Avatar answered Sep 20 '22 11:09

Sam Duff


It's a TypeScript error. You will need to type the mocked useAuth0 as the original type does not have a method called mockReturnValue. Something like this should work:

const mockedUseAuth0 = <jest.Mock<typeof useAuth0>>useAuth0;

mockedUseAuth0.mockReturnValue({
  isAuthenticated: true,
  user,
  logout: jest.fn(),
  loginWithRedirect: jest.fn()
});
like image 20
balzafin Avatar answered Sep 20 '22 11:09

balzafin