最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React: How to mock Auth0 for testing with Jest - Stack Overflow

programmeradmin0浏览0评论

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);
  });
});

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!

Share Improve this question edited Feb 1, 2020 at 12:34 skyboyer 23.7k7 gold badges61 silver badges71 bronze badges asked Jan 31, 2020 at 19:36 tmostmos 3331 gold badge3 silver badges13 bronze badges
Add a comment  | 

3 Answers 3

Reset to default 13

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)

Update 2022-11-21 The mocked function from the ts-jest package has been removed as of version 28.0+ (see mocked v27 documentation)

This function is now deprecated and will be removed in 28.0.0. The function has been integrated into jest-mock package as a part of Jest 27.4.0, see https://github.com/facebook/jest/pull/12089. Please use the one from jest-mock instead.

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

// if you're using jest 27.4.0+ and ts-jest 28.0.0+
import { mocked } from "jest-mock";

// if you're using ts-jest < 28.0.0
// 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();
   });
});

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()
});

After reading this post, hitting similar errors, and investigating the jest documentation more closely...

I was able mock the useAuth0() hook while using the normal Auth0 imports and the standard jest mock functionality.

If there are improvements to this solution or problems with it, please let me know as I'm new with using jest.

What I did is outlined below. In this example, I use FooBar as a react component, and FooBar.test.js as the corresponding jest test script.

STEP 1: In your FooBar.test.js, create a variable that can be use to indicate logged-in/logged-out

// flag to switch between logged-in and logged-out, default to logged-out
let mockLoginStatus = false;

STEP 2: In your FooBar.test.js, create a user, the values for loggedin and loggeout, and a function that mocks useAuth0

// mock user info
const auth0User = {
  nickname: 'marydoe',
  name: '[email protected]',
  email: '[email protected]',
};

// value returned for useAuth0 when logged-in
const mockUseAuth0LoggedIn = {
  isAuthenticated: true,
  isLoading: false,
  user: auth0User,
  logout: jest.fn(),
  loginWithRedirect: jest.fn()
};

// value returned for useAuth0 when logged-out
const mockUseAuth0LoggedOut = {
  isAuthenticated: false,
  isLoading: false,
  user: null,
  logout: jest.fn(),
  loginWithRedirect: jest.fn()
};

// mock useAuth0 function that return logged-in or logged-out values
const mockUseAuth0 = (status) => {
  if (status) {
    return mockUseAuth0LoggedIn;
  }
  return mockUseAuth0LoggedOut;
};

STEP 3: In your FooBar.test.js, set up your mock of the @auth0 library. Mock only the functions you need to mock while leaving other functionality the same as the original module.

jest.mock('@auth0/auth0-react', () => {
  // load original module
  const originalModule = jest.requireActual('@auth0/auth0-react');

  // mock only the functions we want to mock
  return {
    __esModule: true,
    ...originalModule,
    useAuth0: jest.fn(() => mockUseAuth0(mockLoginStatus))
  };
});

STEP 4: In your FooBar.test.js set up your tests beforeAll and afterAll to login (or not login) as you wish.

describe('FooBar component, authenticated', () => {
  
  // login, authenticate
  beforeAll(() => {
    mockLoginStatus = true;
  });
  // logout
  afterAll(() => {
    mockLoginStatus = false;
  });

  test('FooBar contains foo bar', () => {
    YOUR TEST CODE GOES HERE
  });

After this is done, in your react component FooBar.js where you have useAuth0 it will mock properly and call your mockAuth0 function and return the values you defined above.

If you are reading this and needing help, I hope this helps, and that it works for you too. :)

Wishing you the best,

-Gabriel

发布评论

评论列表(0)

  1. 暂无评论