What is the best approach for testing useAuth0().authorize with Jest in an Expo application built with React Native?

I've been searching for solutions related to this issue without any luck.

My goal is to write unit tests using '@testing-library/react-native' to test the functionality of calling useAuth0().authorize when the login button is pressed. I am expecting it to be called once, however, I am getting back 0 calls.

What could be the mistake in my approach?

Below is the structure of the landing page located in ./app/(login)/index.tsx:

import { StyleSheet, TouchableOpacity, SafeAreaView } from 'react-native';
import { useAuth0 } from 'react-native-auth0';

export default function Landing(): React.JSX.Element {
  const { authorize, clearSession, user } = useAuth0();

  const onLogin = async () => {
    try {
      await authorize();
    } catch (e) {
      console.log(e);
    }
  };

  const loggedIn = user !== undefined && user !== null;

  const onLogout = async () => {
    try {
      await clearSession();
    } catch (e) {
      console.log('Log out cancelled');
    }
  };

  return (
    <SafeAreaView style={styles.container}>
      <TouchableOpacity style={styles.logBtn} onPress={loggedIn ? onLogout : onLogin} testID='loginBtn'>
        {user && <Text style={styles.btnTxt}>Log Out</Text>}
        {!user && <Text style={styles.btnTxt}>Log In</Text>}
      </TouchableOpacity>
    </SafeAreaView>
}

Here is where I am with the testing process:

import { render, fireEvent, waitFor } from '@testing-library/react-native';
import { useAuth0 } from 'react-native-auth0';
import Landing from '@/app/(login)/index';


jest.mock('react-native-auth0', () => ({
  useAuth0: jest.fn(() => ({
    authorize: jest.fn(),
  })),
}));

describe('Ensuring that the Login page correctly interacts with Auth0 functionality', () => {
  test('Verifying if the authorize function is being called upon clicking the Login button', async () => {
     const { getByTestId } = render(<Landing />);
     const loginBtn = getByTestId('loginBtn');
      
     fireEvent.press(loginBtn)

     await waitFor(() => {
       expect(useAuth0().authorize).toHaveBeenCalledTimes(1);
     })
  })
})

Upon execution of the test, the following error is encountered:

expect(jest.fn()).toHaveBeenCalledTimes(expected)

    Expected number of calls: 1
    Received number of calls: 0

      43 |       fireEvent.press(loginBtn)
      44 |
    > 45 |       await waitFor(() => {
         |                    ^
      46 |         expect(useAuth0().authorize).toHaveBeenCalledTimes(1);
      47 |       })
      48 |     })

I also attempted the following:

Changing:

fireEvent.press(loginBtn); to fireEvent(loginBtn, 'click');

and changing:

<TouchableOpacity></TouchableOpacity>
to <Button></Button>

Unfortunately, neither of these strategies produced the desired outcome :(

Answer №1

The issue at hand is that in your test, you are referencing a new mock instead of the one that will be referenced in your component.

To resolve this, you should use a mocked function that you pass into the mocked module.

For instance, I encountered a similar scenario when working with React Router's useNavigate hook:

const mockUseNavigate = jest.fn();

jest.mock("react-router", () => ({
  ...jest.requireActual("react-router"),
  useNavigate: () => mockUseNavigate,
}));

You can then utilize this in two ways:

const useNavigateMock = useNavigate();
// perform actions to trigger navigation
expect(useNavigateMock).toHaveBeenCalledWith("/");

Alternatively, you can directly use the mock:

expect(mockUseNavigate).toHaveBeenCalledWith("/");

The drawback of the first approach is that you have to import and call the hook in every test, while the downside of the second method is using a mock defined outside the test/describe block. Regardless of the method chosen, ensure you include a beforeEach to reset the mocks or set resetMocks: true in your Jest config.

In your specific case, you could update your useAuth0() mock to return an object matching the shape of the hook's return value. For example:

const mockAuthorize = jest.fn();
jest.mock('react-native-auth0', () => ({
  useAuth0: () => ({
    authorize: mockAuthorize,
  }),
}));

(I removed the wrapping jest.fn() as it may not be necessary unless you're checking the usage of the hook itself)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unlocking the Potential of Vue Class Components: Exploring Advanced Customization Options

Currently, I am working on a project using Vue 2 with Typescript. However, I am facing an issue where I cannot add options to the component. <script lang="ts"> import { Component, Vue } from "vue-property-decorator"; import HelloW ...

React Native encounters difficulty in assigning the Production value to the NODE_ENV variable

I am currently working on implementing the process.env.NODE_ENV feature to switch between different environments for my react native application, but I am encountering a couple of issues. 1. When trying to assign a parameter to NODE_ENV, I am not seeing a ...

Discover the outcome of clicking on an object (mock tests)

I am just starting out with React and I'm unsure about when to use mocking. For instance, within the 'ListItem' component, there is a 'click me' button that reveals a dropdown for 'cameras'. Should I focus on testing what ...

Develop a wrapper for a function with multiple variations in TypeScript

Encountering an issue with the code below while attempting to create a proxy for a function with multiple overloads: // The target function function original (a: number): boolean; function original (a: string): boolean; function original (a: boolean): bool ...

What is the reason behind Jest v24 mocking classes that have a need for private methods

Currently, I am facing a challenge in creating mock implementations of my Typescript classes using Jest v24+. Specifically, I am trying to create a mock class that will be injected into a constructor and mock the functions to return specific responses. My ...

Encountered an issue with Laravel 5.8 and React Native when trying to listen to a private channel with Pusher. The error states "No callbacks on conversations34 for pusher

Encountering an issue when the app developer attempts to listen to events via a pusher private channel. Below is the Laravel code snippet showcasing the problem. routes/api.php Route::middleware('auth:api')->post('/broadcast/auth', ...

Simulated static functions are invoked within the main function under evaluation

Looking to mock certain functions within a function I'm currently testing. In my code, there is a class with various static private functions that are called by the main function. Specifically, I want to verify the output of MyClass.functionD (which ...

Positioning the search bar to the left with react-bootstrap-table

Is there a way to move the search bar of react-bootstrap-table to the left instead of keeping it on the right? You can see an example here, at the bottom of the page: I know that you can create a custom search panel and input, but that seems like a compl ...

An error occurred when attempting to access data within a variable that is undefined, resulting in a TypeError at the errorHandler function

Every time I attempt to send a post, patch, or put request, I keep getting this error. However, there are no issues with get requests. TypeError: Cannot read properties of undefined (reading 'data') at errorHandler (/home/joe/Documents/mypro ...

Retrieve an Array Containing a Mix of Objects and Functions in Typescript

Let's address the issue at hand: I spent several months working with a custom React Hook using plain JavaScript, and here is the code: import { useState } from 'react'; const useForm = (initialValues) => { const [state, setState] = ...

Struggling to transmit data to material dialog in Angular2+

I am facing an issue with my Material Dialog not working properly. Can anyone point out what I might be missing? product-thumbnail.ts I will use this to trigger the dialog export class ProductThumbnailComponent implements OnInit { @Input() product: Pr ...

"Utilizing TypeScript to assign specific types to recognized keys while also accommodating for undefined

Is there a way to declare an object in such a manner that it requires certain keys, while also allowing for the inclusion of any other keys? Let's say we have an object called student which must always include the keys name and gender, but can also h ...

You are unable to utilize ScrollView within BottomSheet in React Native

After developing a search feature and page in my app, I encountered an issue with displaying content in BottomSheets. Despite using a DataTable, I found that a ScrollView cannot be nested inside the BottomSheet, resulting in not all content fitting vertica ...

When using Angular 5's ngModel, the user interface displays the updated value dynamically without requiring the

When filling out my form, I encounter an issue with a select element and a bind variable. If I make a change to the value and save it, everything works as expected. However, if I make a change in a modal window but then close the modal without saving the v ...

Data retrieved from API not displaying in Angular Material table

I've hit a roadblock trying to understand why my mat-table isn't displaying the data for me. I'm working with Angular 15 and using Angular Material 15. Below is my HTML component code: <mat-divider></mat-divider> <table mat-t ...

The element 'fontFamily' is not recognized within the 'ThemeOptions' type in MUI theming

I'm diving into the world of React and MUI by building my own dashboard from scratch. Let's take a look at my App.tsx file: import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; i ...

The project graph creation for NX has encountered a setback and was unable to be completed. The worker has halted with exit

I've encountered an issue with my Angular project while using nx. Upon running npm install, I received the following error: > NX Nx Daemon was not able to compute the project graph. Log file with the error: ...\node_modules\.cache ...

Is it possible to effectively determine a roster of event names while implementing the defineEmits() feature in Vue 3?

Within a reusable component, my goal is to develop a simple function that creates proxies for props in order to bind them to child components. These proxies will maintain their own internal value and be initialized with the default prop value, which may be ...

A Comprehensive Guide to Exporting Coverage Reports for Visual Studio Code Extensions

While searching for tutorials on creating vscode extensions, I came across various resources like: https://code.visualstudio.com/docs/extensions/testing-extensions There are plenty of tutorials on coverage exports, each suggesting different methods. Howe ...

The 'subscribe' property is not available on the type '() => Observable<any>'

File for providing service: import { Observable } from 'rxjs/Rx'; import { Http, Response} from '@angular/http'; import { Injectable } from '@angular/core'; import 'rxjs/add/operator/Map'; @Injectable() export clas ...