Raphael Ugwu Writer, Software Engineer and a lifelong student.

Testing and error handling patterns in Next.js 

3 min read 1041

Testing Error Handling Nextjs

With time, more developers are bullish on frameworks built on leading JavaScript libraries such as React and Vue. One of these is Next.js: a web framework that improves the ease of working with React by offering flexibility in scaling applications.

Two valid concepts worth exploring when using every framework are testing and error handling. It’s no different with Next.js. This article aims to reveal the different ways to run tests and handle errors in a Next.js application.

Testing elements with Cypress

One way to run tests on a Next.js application is through Cypress, an end-to-end, JavaScript-based testing framework. First, you need to create a basic application with Next.js, then install Cypress and run tests. Begin by navigating to your terminal and creating your application:

npx create-next-app nextjs-starter-app

# then navigate to the application and begin the development server

cd nextjs-starter-app

# then start a development server on http://localhost:3000

npm run dev

Next, open the app on http://localhost:3000 . This launches a generic welcome page:

Generic Welcome Page Localhost

Now you’ll install Cypress to demonstrate how basic tests can be run. Navigate back to the terminal and run a command to set up Cypress in your application:

npm install cypress --save-dev

Once this is done, you need to include a way to launch Cypress from the terminal. To do this, create a test key in the scripts object of the application’s package.json file and assign cypress open as a property:

// package.json

  "scripts": {
    "test": "cypress open"
  }

Now, input the following command in the terminal to launch Cypress:

npm run test

This opens up Cypress’ test suite where you can view and run tests on your project. You’ll notice there are a handful of example tests already in place to demonstrate how Cypress works. You can learn more by running the sample integration specs seen below:

Cypress Test Suite Example Tests

We made a custom demo for .
No really. Click here to check it out.

To build and run your first test, navigate to the newly created Cypress folder in your application. Write the scripts for your tests and save them in the integrations folder. It’s recommended you delete the sample tests in the folder first. Create a file and name it deploy.spec.js.

# integration/examples/deploy.spec.js

context('Deploy', () => {
    beforeEach(() => {
      cy.visit('http://localhost:3000');
    });

    it('should click on the Deploy section in the homepage', () => {
      cy.get('h3')
        .contains('Deploy')
        .click()
    });
  });

In the code sample above, tests should carry out the following functions:

  • Visit the homepage before each test
  • Navigate through the homepage and select any header with the text “Deploy”
  • Click on this header and open the link attached to it

The third function exposes your test to CORS errors. To prevent this, disable web security in the cypress.json file:

{
    "chromeWebSecurity": false
}

#  Do note that this isn't advisable as a practice in production

You need to autostart your development server before executing your tests. To achieve this, navigate to the terminal and install a tool called start-server-and-test.

npm install start-server-and-test --save-dev

Next, in your package.json file, you’ll set up instructions in the scripts object. This will enable you to launch your development server first and then open Cypress:

"scripts": {
    "test": "cypress open",
    "server": "start-server-and-test dev 3000 test"
  }

Now you’re all set! Navigate to your terminal and launch your server and tests with the command npm run server. Your tests should launch just like this:

https://youtu.be/m26U48mqMuM

Testing API routes in Next.js

When dealing with bigger applications, you may find out that you need to test routes and endpoints. You can achieve this with Cypress. In your application, navigate to the pages folder and create a new folder called api. In this folder, create a file called books.js, which will store the data and functions you need for your API:

// pages/api/books.js

export default function books(req, res) {
  res.statusCode = 200;
  res.setHeader("Content-Type", "application/json");
  return res.json([
    {
      id: 1,
      book: "The Firm",
      author: "John Grisham",
    },
    {
      id: 2,
      book: "Cracking the PM interview",
      author: "Jackie Bavaro",
    },
    {
      id: 3,
      book: "Fools Die",
      author: "Mario Puzo",
    },
  ]);
}

Next, you’ll create a script for testing. Navigate to the integrations/examples folder in cypress where you’ll define the tests for your API route:

// integration/examples/books.spec.js

describe("Book test", () => {
  it("Confirms the number of books in your local library", () => {
    cy.visit("http://localhost:3000");
    cy.request("GET", "api/books").as("books");
    cy.get("@books").should((response) => {
      expect(response.status).to.eq(200);
      expect(response).to.have.property("headers");
      expect(response).to.have.property("duration");
      expect(response.body).to.have.length(3);
    });
  });
});

Basically, the test expects the following from the books endpoint’s response:

  • Response status equals 200
  • API response includes a header
  • API response body contains three objects
  • Response time is included

Now, take a look. Launch your server and tests like before; you should have this result:

https://youtu.be/hB61q-0yCOI

Rendering error pages in Next.js

Next.js provides a built-in error page, which can be used to display both server and client errors. This file resides in the pages directory by default:

// pages/_error.js

function Error({ statusCode }) {
  return (
    <p>
      {statusCode
        ? `An error ${statusCode} occurred on server`
        : 'An error occurred on client'}
    </p>
  )
}

Error.getInitialProps = ({ res, err }) => {
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404
  return { statusCode }
}

export default Error

To reuse the Error component in any part of your application, import it and then use the getServerSideProps() function to pre-render your error on each request:

import Error from 'next/_error'

export async function getServerSideProps({ res }) {
  const data = await fetch("http://localhost:3000/api/books");
  const errorCode = data.ok ? false : data.statusCode;
  if (errorCode) {
    res.statusCode = errorCode;
  }
  const json = await data.json();

  return {
    props: { errorCode, books: json.books_count },
  };
}

export default function Page({ errorCode, books }) {
  if (errorCode) {
    return <Error statusCode={errorCode} />;
  }
}

Summary

Next.js provides an awesome experience that is geared towards giving developers a lot of options when working with this framework. Working with Cypress equips you with methods and functions that let you freely define and alter your tests as needed. An error in Next.js can be customized as needed and imported into multiple components.

LogRocket: Full visibility into production Next.js apps

Debugging Next applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your Next app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your Next.js apps — .

Raphael Ugwu Writer, Software Engineer and a lifelong student.

Leave a Reply