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

Can a wasm file be registered in a similar way to a JavaScript file?

My JavaScript file is calling a WebAssembly (wasm) file, but it is fetching the file from the wrong location when I register the script in a specific part of the code. To address this issue, what is considered the best practice? Here's the current s ...

bind a class property dynamically in real-time

I need to dynamically generate a TypeScript class and then add a property to it on the go. The property could be of any type like a function, Promise, etc., and should use this with the intention that it refers to the class itself. let MyClass = class{ ...

What is the best way to remove a particular element from an array stored in Local Storage?

Currently working on a web application that features a grade calculator allowing users to add and delete grades, all saved in local storage. However, encountering an issue where attempting to delete a specific grade ends up removing the most recently add ...

Implementing auto-suggest functionality in a React-Bootstrap Select component

I am seeking to create a specialized react select component that can search through a constantly updating list pulled from a server api in JSON format. I am currently exploring other options aside from React-select because it is not compatible with my proj ...

"Is there a way to extract a specific value from an XML file based on another element

<dataset> <study recNO="0" seriesRecCount="1"> <patientID>123456</patientID> <accessionNumber>M120170428105320</accessionNumber> <patientIDID>35</patientIDID> <studyUID>2.25.1439 ...

Halt the program's process until the ajax request has finished

Struggling with what seems like a common issue of the "Asynchronous Problem" and finding it difficult to find a solution. Currently, I am working on a custom bootstrap form wizard which functions as tabs/slideshow. Each step in the wizard is represented b ...

Subscriber client successfully activated and operational via the command line interface

I have incorporated a script into my PHP file that reads the Pusher channel and performs various actions when a new event occurs on the specified channel. If I access the following URL in my browser: http:/localhost/pusher.php and keep it open, the p ...

Securing your Angular application with user authentication and route guarding ensures

In the process of developing an Angular single-page application (SPA) front-end that interacts with a GraphQL endpoint, I encountered a challenge. Upon user login, I store the token in local storage and update the authentication state in my AuthService com ...

Configuring .env files for both production and development environments in Node.js

As I observed, there were various approaches to setting up environments in NodeJS - some seemed straightforward while others appeared more intricate. Is it possible to utilize package.json scripts to manage environment variables? If so, what is the best p ...

Effortlessly sending multiple forms on a single page via POST in Express JS without the need for page refresh

I am creating a new application using ExpressJS and I want to include the following HTML code in a jade file. On one of my pages, I have 4 form buttons: <div class="dog"> <div class="dog_wrapper clearfix"> <div cla ...

Can anyone provide guidance on how to simulate a click on a JavaScript action for an iPhone?

I am attempting to trigger a click on a "javascript:void(0)" link so that I can retrieve HTML data within the script. Can someone advise me on how to achieve this without using illegal APIs like UITouchEvent, as I only work with NSUrl? Thank you in advan ...

"Learn how to easily format specific characters in JavaScript using the text plugin to create bold text strings with a unique

I would like to transform this text into something like "|| something 1 || something 2 || more || last one ||" and then make all of that string bold by adding "|" around it then it would look like this "|| something 1 || something 2 || more || last one | ...

The references to the differential loading script in index.html vary between running ng serve versus ng build

After the upgrade to Angular 8, I encountered a problem where ng build was generating an index.html file that supported differential loading. However, when using ng serve, it produced a different index.html with references to only some 'es5' scri ...

How to show the raw image content-type using Vue.js

When retrieving an image from a REST API through an HTTP GET with a request body, I have successfully verified the returned content using node.js and chai.js: expect(res).to.have.header('Content-Type', 'image/jpeg'); expect ...

What are the best practices for managing user forms and uploading files?

How should data in text fields and file upload fields be handled according to best practices? This question is a more generalized version of one I previously asked, which can be found here. Let's consider the scenario of a user registering an accoun ...

What is the most creative way you can think of to create a CSS/JS animated

Is using an animated SVG the best way to create these wavy blobs for mobile compatibility? What approach would you take? Here is a similar example I found var wave = document.createElement("div"); wave.className += " wave"; docFrag.appendChil ...

Ways to display a different landing page when navigating to the homepage of a website

In the Next application, I have set up a dynamic route at the root of my pages folder as src/pages/[page].js While this works smoothly for pages with slugs like example.com/my-page, it poses a challenge when trying to access a designated slug named homepa ...

Click on the link or tab to update the marker location on the Google Map

Can you click on Tab 2 to change the marker/location, and then go back to Tab 1 to switch it back to the original location? [Links to Fiddle] http://jsfiddle.net/ye3x8/ function initialize() { var styles = [{ stylers: [{ saturati ...

Transfer the local environment variable from .env.local to the Vercel project

Is there a way to efficiently transfer all environment variables from the .env.local file to a Vercel project? Must I painstakingly add each one individually using the command vercel env add [name] [environment] [gitbranch] < [file] as outlined in the ...

Modifying the hue of Material UI tab label

I attempted to modify the label color of a tab to black, but it seems to be stuck as white. Is this color hard-coded in material-ui? If not, how can I change it? Here's what I've tried: const customStyles = { tab: { padding: '2p ...