how-to-add-cypress-end-to-end-tests-to-a-gatsby-typescript-project

How to add Cypress End-To-End tests to a Gatsby TypeScript project

End-To-End tests are vital for any front-end project if you’re concerned about the quality of the experience you provide to users with your application.

In this post, I will go through the process of adding E2E tests to a Gatsby TypeScript project with Cypress (opens in a new tab).

Pre-requisites

You will need a Gatsby application to try this out. I will be using the Gatsby Starter (opens in a new tab) project that I built. Feel free to use the same or you can use this approach on any Gatsby TypeScript project.

Read the docs (opens in a new tab) to learn how to create a Gatsby app or explore other TypeScript starters (opens in a new tab).

Let’s get started

Install Cypress

npm i --save-dev cypress

Add helper npm scripts

Add the following two scripts in the script section in package.json.

"cy:headless": "cypress run",  
"cy:interactive": "cypress open",

cy:headless

Runs Cypress in headless mode (opens in a new tab). Headless mode runs the tests without using any browser and outputs to the terminal.

cy:interactive

Runs Cypress in the interactive mode on a test runner (opens in a new tab).

Initial Run

Let’s run cypress in the interactive mode.

npm run cy:interactive

Cypress will recognize that this is the first time, and will set up the necessary files and configurations, and will open up the test runner.

Initial Autogenerated Files & FoldersInitial Test Runner

Add configurations

Let’s configure some basics in the cypress.json file.

{
    "baseUrl": "http://localhost:8000",
    "integrationFolder": "cypress/e2e",
    "testFiles": "**/*.spec.*",
    "viewportHeight": 720,
    "viewportWidth": 1080
}

baseUrl

URL used as a prefix for cy.visit() Since my starter runs on localhost port 8000, I will be using that. You can add the URL for your own app here.

integrationFolder

Where tests are held. I prefer to rename this as e2e when I’m writing End-To-End tests using Cypress. Since integration could convey the wrong meaning in the context of e2e testing 😉.

testFiles

Glob patterns of the test files to load. I like to name my test files as *.spec.*. You can use any pattern you want.

viewportHeight

Height in pixels for the application in the test runner. The default is 660 and for my starter, it activates the tablet view. Hence, I prefer to go with 720.

viewportWidth

Width in pixels for the application in the test runner. The default is 1000 and I prefer to go with 1080.

Setup e2e folder

Remove the cypress/integration folder inside the cypress directory and create a new folder called e2e inside the cypress directory.

Prepare for TypeScript

Configure tsconfig

To write the tests in TypeScript, we need to have a tsconfig.json file inside the cypress directory.

Cypress documentation (opens in a new tab) recommends the following configuration.

{
    "compilerOptions": {
        "target": "es5",
        "lib": [
            "es5",
            "dom"
        ],
        "types": [
            "cypress"
        ]
    },
    "include": [
        "**/*.ts"
    ]
} 

Migrate existing JavaScript files to TypeScript

  1. Rename the index.js file inside cypress/support directory to index.ts

2. Rename the index.js file inside cypress/plugins directory to index.ts

The IDE will start to complain that it cannot find the name ‘module’(TS2591). To fix this follow the steps below.

npm i --save-dev [@types/node](http://twitter.com/types/node "Twitter profile for @types/node")
  • Add “node” to types array in tsconfig.json.
{
    "compilerOptions": {
        ...
        "types": [
            ...
            "node"
        ]
    },
    ...
} 

Let’s write our first test

Create a new file called smoke.spec.ts

In this test, I will assert if the app can navigate to the Home page and Pricing page successfully.

/// describe("The App works as expected.", () => {
 
    context("Can navigate to pages without issues.", () => {
 
        it("Can navigate to the home page.", () => {
            cy.visit("/");
        });
 
        it("Can navigate to the pricing page.", () => {
            cy.visit("/pricing");
        });
    });
}); 

Test Runner after running the smoke.spec.ts

Let’s write our first custom command

In my project, I use data-testid in elements as a unique id for testing. So I’m going to write a custom command to query elements using a data test id.

I will create a new file called dom.ts inside the cypress/support directory and will add a command there.

/**
 * Custom command to select DOM element by data-testid attribute.
 *
 * @example
 *    cy.dataTestId("") -> [data-testid=]
 *
 * @param {string} value - Attribute value.
 * @param {string} options - Attribute value.
 * @returns {Cypress.CanReturnChainable}
 */
Cypress.Commands.add("dataTestId", (value: string): Cypress.CanReturnChainable => {
 
    return cy.get(`[data-testid=${ value }]`);
});

Now if I try to use the command in my smoke test file, I will get an error like this.

Custom Command Error

This happens because TypeScript can not find any declaration file for the command. As of now, we have to write the typings manually to avoid these errors (Read official docs here (opens in a new tab)).

Inside the cypress directory**,** create a new folder called types. And inside that, create a new file called index.d.ts

Now define the typings for the custom command.

/// 
 
declare namespace Cypress {
    interface Chainable {
        /**
         * Custom command to select DOM element by data-testid attribute.
         * @example cy.dataTestId("index-heading")
         */
        dataTestId(value: string): Chainable;
    }
}

With this fix, the error should be gone and we should be able to invoke the custom command inside the test files.

Additional Step

With the existing configurations, we have to fist start the application and then run the test suite.

This is a cumbersome process and it would be better if there is a ways to fire up the server and run the tests with a single command.

For this purpose, we can use the start-server-and-test (opens in a new tab) package.

  1. Install
npm install --save-dev start-server-and-test

2. Create an npm script.

"test:e2e": "start-server-and-test start [http://localhost:8000](http://localhost:8000) cy:interactive"

Now if you execute npm run test:e2e , the script will execute npm run start and will fire up the application and after it is up, it’ll run Cypress in interactive mode.

Conclusion

Hope you found this blog post useful. Feel free to try this out and if you have any suggestions regarding the blog you can log an issue in this repo (opens in a new tab).

Links

Signing off… ✌️❤️