ProNextJS
    lesson

    End-to-End Testing with Cypress

    Jack HerringtonJack Herrington

    Cypress is an end-to-end (E2E) testing tool that creates a headless browser and navigates through your site, interacting with elements and running tests.

    Let's build out a set of E2E tests.

    Creating a New Next.js App

    As before, we'll create a new Next.js application using the create-next-app command:

    pnpm dlx create-next-app@latest e2e-with-cypress --use-pnpm
    

    Choose TypeScript, ESLint, Tailwind CSS, and the App Router when prompted.

    Installing Cypress

    Next, let's install Cypress:

    npx cypress install
    pnpm add cypress -D
    

    After the installation is complete, launch the Cypress UI with:

    npx cypress open
    
    The Cypress UI

    Choose "E2E Testing", and Cypress will create the necessary configuration files and directories for you.

    Configuring Cypress

    In the root of your project, you'll find a new cypress.config.ts file. Open it and set the baseUrl property to http://localhost:3000. This tells Cypress to use http://localhost:3000 as the base URL for all tests.

    // cypress.config.ts
    export default {
      e2d: {
        setupNodeEvents(on, config) {
          // implement node event listeners here
        },
        baseUrl: "http://localhost:3000",
      },
    };
    

    Inside of the cypress directory is where we will create a test, but first we need to create a component to test.

    Creating a Test Component

    Open app/page.tsx and replace it with the following source code:

    export default async function Home() {
      const pokemon = (await fetch("https://pokeapi.co/api/v2/pokemon").then(
        (res) => res.json()
      )) as { results: { name: string }[] };
    
      return (
        <div className="bg-black text-white p-5">
          <h1>Pokemon</h1>
          <ul>
            {pokemon.results.map((p) => (
              <li key={p.name}>{p.name}</li>
            ))}
          </ul>
        </div>
      );
    }
    

    This component makes a request to the Pokemon API and displays a list of Pokemon names.

    Start your development server with pnpm dev and navigate your browser to http://localhost:3000. You should see a list of Pokemon names, including "bulbasaur".

    the Pokemon listing

    Writing a Cypress Test

    Now that we have a component to test, let's write our first Cypress test.

    Create a new directory called e2e inside the cypress directory, and add a new file named home.cy.ts:

    // inside cypress/e2e/home.cy.ts
    
    describe("Home page test", () => {
      it("Visits the home page and looks for bulbasaur", () => {
        cy.visit("/");
        cy.contains("bulbasaur");
      });
    });
    

    This test will launch the browser, navigate to the base URL, then check if the page contains the text "bulbasaur".

    Running the Cypress Tests

    Inside of package.json, we need to create a new script called e2e:test that starts the application and runs the Cypress tests concurrently:

    // inside package.json
    ...
    "scripts": {
      "dev": "next dev",
      "e2e:test": "concurrently \"npm run dev\" \"cypress run\"",
      ...
    }
    

    Using the Cypress UI

    Run pnpm e2e:test to start the development server and run the Cypress test application:

    cypress ui

    From the Cypress UI, select "E2E Testing", then click on the home.cy.ts file to run the test.

    The Cypress UI will show you a live preview of the test running in the browser, which can be helpful for debugging and understanding how your tests work.

    cypress test preview

    Wrapping Up

    You have successfully run your first E2E test! As your application grows, you can follow this process to add more tests to cover different user flows and edge cases. Learn more about Cypress in their docs.

    Transcript

    Another popular framework for doing end-to-end testing is Cypress. So what is end-to-end testing? Well, it is testing where you actually create a headless browser, navigate to your site, and then run tests against you. Click on things, expect certain values. It's a great way to get a smoke test of the whole application.

    So let's go and build out our E2E with Cypress app router application so we can test out Cypress and see how to install it. So I'll use all the defaults TypeScript, ESLint, Tailwind, the source directory. I will of course pick AppWriter and I will not customize the import alias. I'll launch that directory with VS Code. Now it's created.

    Let's go and install a Cypress. We're going to want to bring up our console. And in there, run Cypress install. After that, I'm going to want to run Cypress open. Now things turn towards UI.

    So it's actually launched its own little app. I hit continue and we get to decide whether we want to use it for EDE testing or component testing. I'm gonna choose EDE testing. Now it's gonna create a bunch of configuration files locally and then I'm going to close this out. Now let's take a look at what it's actually done.

    So we'll go back into our project and we can see that we now have a Cypress config. So one of the things we're going to want to do is set up the base URL. That is a base URL for testing. That just means whenever I visit, say, slash, it's going to use localhost 3000 slash. What else has it done?

    Well, it's gone and created this Cypress directory, which has some fixtures for data and some support. We're going to go and create our tests inside of this Cypress directory. But we do need something to test, so I'm going to go back over into our source directory. I'm going to change out page for a very simple Pokemon listing page. The code for this component is in your instructions.

    It's going to make a simple request against the Pokemon API that's going to get back about 20 Pokemon and it's going to list those out in an in-order list. So let's hit save and try this out. So I'll go back over to the console and then launch dev. Okay, so it's looking pretty good. We got localhost 3000.

    It's listing out our Pokemon. We've got a list of them here. We're going to look for Bulbasaur. So that is what our Cypress test is going to look for. It's going to launch our browser.

    It's going to navigate to slash on localhost 3000 because of that base URL. And then it's going to expect to see Bulbasaur. That's going to give us a complete test of our application. Our application is going to hit its back end of the Pokemon API, and it's going to then render those results. And so we'll have a complete end-to-end test of our application.

    So back over in our app, I'm gonna create a new directory called ede inside of Cypress. And in there, I'm gonna create a test file. So it's gonna be testing the home route, so home and CY for Cypress and TS for TypeScript. So our test is going to visit the page, and then it's going to see that the page contains Bulbasaur. Pretty clear.

    So let's go and try and run this. To do that, I'm going to go over to our package.json, and I'll create a script that calls cypress run. So I'll copy and paste that. Now our application actually has to be running so I'll create another terminal and in that terminal I'll do pmpmdev. That's gonna run our app and then I'll run it and it looks like Cypress is not found so I think I know what I have to do, so I'll add Cypress.

    To be honest, I'm kind of surprised that this doesn't happen during the installation. All right, it looks good And even better, we get our TypeScript typing. Great. OK, let's try it now. Fantastic.

    All specs passed. Of course, I'm not a big fan of having to run the dev server myself. I'd rather it do both. So I'm gonna stop this terminal and then I'm going to add a library called concurrently. What that's gonna allow us to do is concurrently run our EDE tests as well as our dev server.

    I can go and adjust our EDE test script to concurrently run dev and Cypress run. Try that again. And now it's running the dev server first and then running our tests. One more fun thing with Cypress in particular to try is their UI. It's actually quite nice.

    So I'm going to use PMPM Cypress Open. And I'm going to go to EDE testing. Now it's telling us that we don't have our server running. That's true. Let's go bring up our server.

    We'll try again. Oh, looks good. Let's hit Electron here. And now look at that. We've got our home test and we can actually run it.

    And you can actually see it run. It's pretty cool. So an end-to-end testing system like Cypress here is a good thing to get set up early on in the development because you want to have smoke tests for your application to know that your application is end-to-end working. So we'll take a look at smoke testing and unit testing and how they all work together later in the course as we take a more holistic approach to testing.