What steps are involved in testing a nextjs endpoint with Jest?

One of my challenges is an endpoint responsible for user sign up:

import { createToken } './token'; // Unable to mock
import { sendEmail } './email'; // Unable to mock

export default async function signUp(
  req: NextApiRequest,
  res: NextApiResponse
): Promise<any> {
  try {
    // Generate a verification token
    const token = await createToken(req.user);

    // Email the token
    await sendEmail(req.user, token);

    return res.status(200).send({ done: true });
  } catch (error: any) {
    console.error(error);
    return res.status(500).end(error.message);
  }
}

I am wondering how I can properly mock these dependencies in my Jest unit tests:

import signup from './signup';

describe('signup', () => {
  it('should return success', async () => {
    const req: IncomingMessage = {} as unknown as IncomingMessage;
    const res: ServerResponse = {
      end: jest.fn(),
    } as unknown as ServerResponse;

    const actual = await signup(req, res);

    ...
  });
});

Is it possible that nested dependencies cannot be mocked by Jest directly? Should I consider implementing a DI pattern in this endpoint? If so, what are some DI patterns that can support unit testing for Nextjs endpoints?

Answer №1

Unfortunately, it appears that jest.mock cannot mock dependencies for imports that are external to the test file (such as .spec.ts and .test.ts). This is a problem I encountered when dealing with numerous dependencies in my Next API endpoint.

As a workaround, I decided to employ Nextjs's middleware pattern to assess the logic of my endpoint instead.

// A utility function used to ensure a middleware runs before proceeding
// It also handles errors that may occur within a middleware
function runMiddleware(req: NextApiRequest, res: NextApiResponse, fn: Function) {
  return new Promise((resolve, reject) => {
    fn(req, res, (result: any) => {
      if (result instanceof Error) {
        return reject(result)
      }

      return resolve(result)
    })
  })
}

The solution involves extracting the endpoint logic into a function and concentrating on testing solely this extracted function.

// Testing this function, rather than the entire endpoint
export function post(
  _createToken: Function,
  _sendEmail: Function,
) {
  return async function(req: NextApiRequest, res: NextApiResponse) {
    ...
  }
}

Below is an overview of how the testing can be structured. While my actual implementation uses classes instead of functions, the testing principles remain similar.

describe('signup', () => {
  let createToken: Function;
  let sendEmail: Function;

  beforeAll(() => {
    createToken = jest.fn();
    sendEmail = jest.fn();
  });

  it('should complete the happy path', async () => {
    const req: NextApiRequest = {} as unknown as NextApiRequest;
    const res: NextApiResponse = {} as unknown as NextApiResponse;

    await (
      await post(createToken, sendEmail)
    )(req, res);

    // expect
  });
});

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

Alert: Prop type validation error: The `component` prop provided to `ForwardRef(Link)` is invalid

We are facing an issue with our NextJS app where it works fine in production, and locally it renders correctly. However, we are encountering some unsightly warnings that we are trying to suppress. client.js:1 Warning: Failed prop type: Invalid prop `compon ...

Filtering multiple rows in a table using Javascript

I'm currently working on creating a filter that can filter based on multiple inputs, with each input filtering in a separate column. Here is the JavaScript & code I am using: function myFunction(column, input) { var filter, table, tr, td, i, t ...

Issue with popup display in React Big Calendar

I'm currently working on a calendar project using React-Big-Calendar, but I've run into an issue with the popup feature not functioning properly. <div className={styles.calendarContainer} style={{ height: "700px" }}> <C ...

Struggling to fix errors within a nested div element?

I'm currently utilizing AngularJS to perform basic form validation. Below is the current code snippet: <form name="myForm" id="form_id" method="post" novalidate> <div class="form-group"> <label for="myField_input" class="c ...

Tips for adding a text input field within a dropdown menu

Could someone provide guidance on how to place an input text box within a dropdown without using bootstrap? I came across this image showing what I am looking for: https://i.stack.imgur.com/f7Vl9.png I prefer to achieve this using only HTML, CSS, and Jav ...

Dealing with lag problems while feeding a massive dataset into the Autocomplete component of Material-UI

In my React project, I have integrated the Autocomplete component from Material-UI to enhance user experience. However, when attempting to pass a large dataset of 10,000 items to the Autocomplete component as a prop, there is a noticeable delay of approxim ...

Real-time chart updates through REST API integration with JavaScript

I am searching for a JavaScript library that is capable of creating line charts and making calls to a REST API every few seconds (such as 5s or 3s) in order to update the line chart dynamically. I have found some libraries that support live chart updatin ...

Choice of product variations as a package

I am currently working on a project and here is the data structure I have set up for options and combinations: Options: "options": [ { "id": "96ce60e9-b09b-4cf6-aeca-83f75af9ef4b", "position": 0, "name": & ...

Element was removed upon clicking only once

Can anyone help me figure out why the behavior of .remove() with $postNav.remove(); is different here? When you click on "I'm a tag" for the first time, both the <li> and <ol> are deleted as expected. However, on the second click, only the ...

A beginner's guide to integrating Socket.io with Express.JS using the Express application generator

Currently, I am attempting to utilize Socket.io alongside Express.JS by using the Express application generator. While searching for solutions, I came across some helpful advice on how to achieve this (check out Using socket.io in Express 4 and express-gen ...

Is there a proper method for populating an HTML text with values from a form?

As a newcomer, I could really use some guidance here :) I'm trying to populate text with various words, numbers, and calculation results from a form. This is my initial attempt for just one field/word, and it appears to be functioning correctly. Do y ...

Combining a standard JSS class with Material-UI's class overrides using the classnames library

I am exploring the method of assigning multiple classes to an element in React by utilizing the classnames package from JedWatson, along with Material-UI's "overriding with classes" technique. For reference, you can see an instance in MUI's docu ...

Can you explain how to utilize prop values for setting attributes in styled-components v4 with TypeScript?

Overview Situation: const Link = styled.a` border: solid 1px black; border-radius: 5px; padding: 5px; margin: 10px 5px; `; type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement>; const LinkAsButton = styled(Link).attrs<ButtonP ...

What is causing the consistent error message "unable to read property 'logged' of undefined"?

Here is the code snippet from my app.js: var express = require('express'); var path = require('path'); var favicon = require('serve-favicon'); var logger = require('morgan'); var cookieParser = require('cookie- ...

Steps for instructing Google Maps to identify the location of a provided Google Maps URL

Is it possible to extract longitude and latitude data from a shared URL and place them into a marker? For example, users might copy and paste the 'Share' URL from Google Maps. For instance: or Direct Location: https://www.google.co.nz/maps/plac ...

The utilization of media within the meta in Next.js is not allowed

Recently, I came across an interesting article about PWAs on web.dev. The article discusses color schemes and at one point, they talk about it in detail, I'm currently working with Next.js and decided to try implementing the following code snippet: & ...

Is it necessary to implement clustering for each route in an Express.js application?

Currently, I am utilizing the cluster module to fork my application within my index.js, which serves as the primary file in the root directory of my website. My application consists of numerous routes. Should I incorporate the cluster code to encapsulate a ...

Transform a nested JSON Object into a customized array structure

My task involves converting a nested JSON object into a specific format, as demonstrated below: let jsonObj ={"data": { "cardShop": { "cardData": { "cardTitle": "The Platinum Card<sup> ...

Attempting to conceal image previews while incorporating pagination in Jquery

I'm working on implementing pagination at the bottom of a gallery page, allowing users to navigate between groups of thumbnail images. On this page, users can click on thumbnails on the left to view corresponding slideshows on the right. HTML <di ...

Is it necessary to use both observer.unobserve and observer.disconnect at the same time?

Is it unnecessary to use both observer.unobserve and observer.disconnect together? Should I just stick with one of them? I have implemented the IntersectionObserver within a useEffect. The code snippet provided is the clean-up function for that useEffect. ...