How to create integration test with Cypress in your Next.js project
Tags: nextjs, cypress, integrationtest
Published: 2021-07-07 11:42:21

In this tutorial we'll describe how you can use Cypress to test your Next.js application, so that you can be more confident when writing or refactoring code.

# What is Cypress ?

Cypress is a Javascript end-to-end test framework. It allows you to test your application directly in the browser, with React it's a perfect match because you can test each of your component in the browser and visually see what's wrong and where.
You can learn more about it and how it works  [here](https://www.cypress.io/)

# Generate a Next.js app

`npx create-next-app`
or
`yarn create next-app`
and follow the instructions

If you prefer to use Typescript

`npx create-next-app --typescript`
 or
`yarn create next-app --typescript`

# Install Cypress

`npm install cypress --save-dev` or `yarn add cypress -D`

In your _**package.json**_ add a script line

```
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "cypress:open": "cypress open"
  },
```

If you use Typescript make sure you add cypress types in your _**tsconfig.json**_ file

```
"compilerOptions": {
    ...
    "types": ["cypress"]
  },
```

# Run Cypress

`npm run cypress:open` or `yarn cypress:open` will run Cypress for the first time. It will generate automatically every necessary files for you and tests examples in a **cypress** folder at the root of your project, and open a dedicated page in your browser

![Cypress in browser screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cw1broew604cu7cnh6i.png)

You can try running the integration tests examples

![Integration tests examples running screenshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/83m4kzeg1nva1kvhug0t.png)

These files can be found in your `cypress/integration` folder. You can delete all of them as we'll write our own one.

# Write your first integration test

Under `cypress/integration` folder create a *home.spec.js* file (or *home.spec.tsx* if you use typescript) and add

```
/// <reference types="cypress"/>

context("Home Page", () => {
  beforeEach(() => {
    cy.visit("http://localhost:3000");
  });

  it("should render the home page and display a message", () => {
    cy.get("h1").contains("Welcome");
  });
});
```

If you use Typescript add `export {}` to bypass Eslint compilation error

```
/// <reference types="cypress"/>

context("Home Page", () => {
  beforeEach(() => {
    cy.visit("http://localhost:3000");
  });

  it("should render the home page and display a message", () => {
    cy.get("h1").contains("Welcome");
  });
});

export {}
```

Here we are telling Cypress each time it runs the test it should first navigate to the homepage, and search for a `<h1>` tag containing "Welcome"

If your run this test now it will fail and that's normal

![Failed test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/figvt5izgwqfekub3193.png)

To make it work we need to run our server first and launch the tests, to automate this behavior we will install a library called _**start-server-and-test**_

`npm install start-server-and-test --save-dev`
or
`yarn add start-server-and-test -D`

Add a script in your _**package.json**_

```
"scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "cypress:open": "cypress open",
    "test": "start-server-and-test dev 3000 cypress:open"
  },
```
You can now run 
`npm run test`
or
`yarn test`

To execute your test and it should work

![Working test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qsnqhq0zckaqox35uza8.png)

I will make the test fail again by replacing the word "Welcome" by "Bonjour" and Cypress automatically detect where the test has failed

![Second test failed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1efbz383gkln8lwvx65.png)

Now that you understand how Cypress is testing your component you can write your own tests based on what you want to test, and enjoy the visual regression tool in the browser embedded by Cypress 🥳

# How to test *getStaticProps*

To show how we can perform Cypress test on props coming from *getStaticProps* I have created a file called _**stack.js**_ under `pages` folder

```
// stack.js

const Stack = (props) => {
  const favorites = props.stack;

  return (
    <div style={{display: 'flex', justifyContent: 'center', padding: '2rem'}}>
      <main>
        <h1>My Favorites Stack</h1>
        <ul>
          {favorites.map((favorite) => {
            return <li key={favorite}>{favorite}</li>;
          })}
        </ul>
      </main>
    </div>
  );
};

export default Stack;

export async function getStaticProps() {
  const favoriteStack = [
    'Javascript',
    'TypeScript',
    'React.js',
    'Next.js',
    'GraphQL',
    'Amazon Web Services',
    'Firebase',
  ];

  return {
    props: {
      stack: favoriteStack
    }
  }
}
```
The goal is to make sure that we receive the correct props, so 
we can create a _**stack.spec.js**_

```
/// <reference types="cypress"/>

const favoriteStack = [
  'Javascript',
  'TypeScript',
  'React.js',
  'Next.js',
  'GraphQL',
  'Amazon Web Services',
  'Firebase',
];

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

  it('should render the stack page and display the favorite stack', () => {
    cy.get('ul>li').each((item, index) => {
      cy.wrap(item).should('contain.text', favoriteStack[index]);
    });
  });
});
```
Here the test should pass because we are receiving the exact same props that we are passing in our component

![Stack test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ub0o8y09489p7iuf404h.png)

You can make the test fails by modifying any of the array item and Cypress should show you where it failed, for example here I expect to find "MongoDB" value instead of "Firebase"

![Stack test failed](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lck8d8dqx3s8wgnerxq4.png)

# How to test *getServerSideProps*

It should work the same way as for `getStaticProps`. To demonstrate this we create a new file under `pages` _**platforms.js**_

```
const Platforms = (props) => {
  const favorites = props.stack;

  return (
    <div style={{display: 'flex', justifyContent: 'center', padding: '2rem'}}>
      <main>
        <h1>My Favorites Freelance platforms</h1>
        <ul>
          {favorites.map((favorite) => {
            return <li key={favorite}>{favorite}</li>;
          })}
        </ul>
      </main>
    </div>
  );
};

export default Platforms;

export async function getServerSideProps() {
  const favoritesPlatforms = [
    'Toptal',
    'Upwork',
    'Malt',
    'Comet'
  ];

  return {
    props: {
      stack: favoritesPlatforms
    }
  }
}
```
Then we add our test **platforms.spec.js**

```
/// <reference types="cypress"/>

const favoritePlatforms = ['Toptal', 'Upwork', 'Malt', 'Comet'];

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

  it('should render the platforms page and display the favorite platforms', () => {
    cy.get('ul>li').each((item, index) => {
      cy.wrap(item).should('contain.text', favoritePlatforms[index]);
    });
  });
});
```
And you can see it's working 🎉

![getServerSideProps test](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l96s27h02f164rfqy15p.png)

# Conclusion
Now you understand how Cypress can work with your Next.js project you can create your own tests based on your scenarios. Enjoy it!