Integrating Percy and Cypress to your Next.js application.
Karthikeyan ・ Nov 20th, 2021 ・ Views

Integrating Percy and Cypress to your Next.js application.

In this blog post, we will be seeing how to integrate Percy and Cypress to your Next.js application.

Outline:

  1. Visual Testing
  2. End to End Testing
  3. Intro on Percy
  4. Intro on Cypress
  5. Writing your first E2E test with Cypress.
  6. Connecting Percy with Cypress.
  7. Integrating Visual Testing with CI pipeline
  8. Conclusion

Visual testing :

Visual testing makes sure that UI looks the same for all the users. At the end of the build, a visual testing tool takes a screenshot so that it can check , analyse and give us information as how our application gets rendered on multiple environments like browsers, devices and how screen size can affect the layout of the application.

Below are some of the visual testing tools

  • Percy (BrowserStack)
  • Kobiton
  • Applitools
  • LambdaTest
  • CrossBrowserTesting (SMARTBEAR)
  • Chromatic
  • Screener by SauceLabs (Sauce Visuals)

End to End Testing :

E2E or End-to-end testing is a test strategy where we subject our application to test scenario which will closely impersonate how an end user will interact with application.

  • WebdriverJS.
  • Protractor.
  • WebdriverIO.
  • NightwatchJS.
  • Cypress.
  • TestCafe.

https://media.giphy.com/media/3oKIPlLZEbEbacWqOc/giphy.gif

Alright now we know about the two high level testing strategies. Let's see short intro about the tools which we are going to use.

Percy:

Percy helps teams automate visual testing. It captures screenshots, compares them against the baseline, and highlights visual changes.

Cypress:

Cypress is a JavaScript-based end-to-end testing framework built on top of Mocha which runs on the browser. It's make the testing process more reliable and faster.

Let's code.

Checkout our latest product - the ultimate tailwindcss page creator πŸš€

https://media.giphy.com/media/2GjgvS5vA6y08/giphy.gif

Note: I will not be going in depth about writing E2E test. Please refer to the cypress documentation on writing your first test.

Bootstrapping your Next.js application:

We will be using the create-next-app cli to bootstrap our demo application. Go to your terminal and type the following command.

npx create-next-app cypress-next-demo --ts

cd cypress-next-demo

yarn dev

The above command will start up a brand new next.js application and spin up in your local machine.

You can now visit localhost:3000 in your browser.

image.png

Before writing our first test. Let's clean up the boilerplate code in the index.tsx file. Paste the following in your pages/index.tsx file.

import type { NextPage } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'

const Home: NextPage = () => {
  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <h1 className={styles.title}>
          Cypress + Next.js + Percy
        </h1>

        <p className={styles.description}>
         playing around with cypress , next and percy
        </p>

     </main>
    </div>
  )
}

export default Home

We are having a simple h1 and p tags in our demo app. Save it and check in your browser to verify the changes.

image.png

Writing your first E2E test with Cypress:

Let's first install cypress. Head over to the terminal and run the following command.

yarn add cypress --dev

Once the installation is done , open the package.json add the following line to the script

"cypress:open": "cypress open"

and run the following command in your terminal


yarn run cypress:open

This is will open up the cypress and generate the examples with recommended folder structure

➜  cypress git:(main) ls -ltra

total 0
drwxr-xr-x   3 karthikeyan.shanmuga  253301862   96 Nov 16 22:11 plugins
drwxr-xr-x   6 karthikeyan.shanmuga  253301862  192 Nov 16 22:11 .
drwxr-xr-x   3 karthikeyan.shanmuga  253301862   96 Nov 16 22:11 fixtures
drwxr-xr-x   4 karthikeyan.shanmuga  253301862  128 Nov 16 22:11 support
drwxr-xr-x   3 karthikeyan.shanmuga  253301862   96 Nov 16 22:12 integration
drwxr-xr-x  19 karthikeyan.shanmuga  253301862  608 Nov 17 00:22 ..

You can run the sample test in the Cypress UI to see how it is working.

image.png

Now let's remove the example test and create our own. Do the following,

cd integrations

touch app.spec.ts

Add the following content to the app.spec.ts file


// app.spec.ts 

describe('home page', () => {
  it('checking for tags', () => {
      cy.visit('/')
      cy.get('h1').should('be.visible')
      cy.get('p').should('be.visible')
  });
});

Make sure to add the "baseUrl": "http://localhost:3000" to  cypress.json configuration file.

Code Walkthrough:

  1. describe and it come from Mocha.
  2. expect comes from Chai.
  3. Since we have configured the baseUrl to our local development url. We will be replacing We can just straight away visit the root of our application with cy.visit('/').
  4. In next two consecutive lines , we are checking to see if h1 and p we added to our index.tsx file is visible in the DOM

Running your Cypress tests:

Since Cypress is testing a real Next.js application, it requires the Next.js server to be running prior to starting Cypress.

Run npm run build and npm run start, then run npm run cypress in another terminal window to start Cypress.

Alright before automating by connecting it with Github actions CI. Let's connect it with Percy.

Connecting with Percy :

Install @percy/cypress and @percy/cli:

$ yarn add --dev @percy/cli @percy/cypress

In order to add Percy snapshots to your Cypress tests, you'll need to first import the @percy/cypress package into your cypress/support/index.js file:

import '@percy/cypress';

Head over to the app.spec.ts file and add the following line.

// for visual diffing
cy.percySnapshot('Home page')

Once done your app.spec.ts file should look something like this.

describe('home page', () => {
    it('checking for the tags', () => {
      cy.visit('/')
      cy.get('h1').should('be.visible')
      cy.get('p').should('be.visible')
      
	    // Take a snapshot for visual diffing
	    cy.percySnapshot();

    });
});

Note: Since our project is using typescript, please include the following types in the tsconfig.json.

"types": ["cypress","@percy/cypress"]

Since we have not connected to the CI yet , let's see how we can run the test in our local and send the screenshot to Percy for visual diffing. We need PERCY_TOKEN for this.

Create an account in Browserstack if you don't have one and navigate to Percy.

  • Create a new project and give the name as percy-cypress-demo and connect it your github repository.

image.png

  • Copy PERCY_TOKEN from the new project screen, then run:

export PERCY_TOKEN=your_token_here

npx percy exec -- cypress run

This will run the Percy test in your local environment and send the build to Percy. since it is the first build it will be considered as the base build and used for comparison.

image.png

Let's automate the process shall we.

Connecting with CI - Github Action

Let's connect it with our CI pipeline. We will be using Github actions to achieve this. Create a workflow file in our root directory.

From Next.js docsπŸ‘‡

You can install the start-server-and-test package and add it to the package.json . In the scripts field: "test": "start-server-and-test start http://localhost:3000 cypress" to start the Next.js production server in conjunction with Cypress. Remember to rebuild your application after new changes.

We will also be doing the same. After updating the package.json as mentioned it should look something like this

{
  "name": "cypress-percy-demo",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint",
    "cypress:open": "cypress open",
    "cypress:run": "cypress run",
    "percy:cypress": "percy exec -- cypress run",
    "start:server": "serve -l 3000 .",
    "test": "start-server-and-test start http://localhost:3000 percy:cypress"
  },
  "dependencies": {
    "next": "12.0.4",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "@percy/cli": "^1.0.0-beta.70",
    "@percy/cypress": "^3.1.1",
    "@types/node": "16.11.7",
    "@types/react": "17.0.35",
    "cypress": "^9.0.0",
    "eslint": "7",
    "eslint-config-next": "12.0.4",
    "serve": "^13.0.2",
    "start-server-and-test": "^1.14.0",
    "typescript": "4.4.4"
  }
}

we will using the above configured command yarn run test in our CI.

# .github/workflows/main.yml

name: CI
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Install
        run: yarn
      - name: Build Next.js 
        run: yarn run build
      - name: Run tests
        uses: percy/exec-action@v0.3.1
        with:
          custom-command: "npm test"
        env:
          PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}

Walkthrough:

  1. Whenever we push the code to the main branch or send a pull request test will be triggered.
  2. Install the dependencies and build your Next.js application
  3. Run the test.

Note: Please add the PERCY_TOKEN to your Github secrets.

What is the need to run the test when code gets pushed to main branch ?

Percy needs a base screenshot which it can use it to compare with fixes which will be sent it's way. If it does not have the screenshots to compare to , then you will have only one screenshot of your pull-request branch.

From Percy docs πŸ‘‡

We encourage you to run Percy builds for every commit on the main branch, as these provide the baseline builds for the pull request and feature builds.

More info on docs .

You can also add Percy to your pull/merge requests to be notified when visual changes are detected, and when those changes are approved and ready to merge.

Head to your settings to give Percy access to GitHub or GitLab. Once you’ve given access, connect your project on Percy to your project’s source repository. Then the next time you commit, Percy will show up in your pull/merge request checks:

image.png

Since the there is no visual difference , you don't have to approve the build in percy. Now head over to the pages/index.tsx file and change the p tag content and send in the pull request.

Once the test run, you will get the screenshot appearing on Percy.

image.png

Once you approve it , you will be able to merge the Pull request and then it will trigger another action to compare the new and old main branch screenshot. Since the new main branch screenshot is the latest one , it will auto-approved and considered as the base screenshot for the further comparison

https://media.giphy.com/media/xT0xezQGU5xCDJuCPe/giphy.gif

What have we achieved so far ?

  • Learnt about visual and e2e testing.
  • How to write your first e2e test using Cypress.
  • How to connect Percy with Cypress.
  • Automating visual test with CI pipeline.

I have attached some reference blog post to get more familiar on Github actions and creating your own workflow.

Conclusion:

That's pretty much it. Thank you for taking the time to read the blog post. If you found the post useful , add ❀️ to it and let me know if I have missed something in the comments section. Feedback on the blog are most welcome.

Link to the repository: https://github.com/skarthikeyan96/cypress-next-demo

Let's connect on twitter : (https://twitter.com/karthik_coder)

https://media.giphy.com/media/eujb1tWaj3ZxS/giphy.gif

Resources:

  1. Cypress Framework tutorial β€” Browserstack
  2. Next.js docs β€” testing
  3. Visual testing with percy - digital ocean.
  4. Creating your first github action

Comments (0)