Getting Started with Cypress and TypeScript

Cypress Tree

Cypress is a front-end testing utility that allows you to write UI tests using Mocha and Chai. It has auto-waits, time-travel (look back at snapshots from within test runs), and automatic discovery of tests. This blog provides a quick start for getting started with Cypress and TypeScript.

Cypress NPM Packages

Your package.json file will need the following minimal development dependencies.

{
  "name": "test",
  "dependencies": {
  },
  "devDependencies": {
    "typescript": "^2.9.1",
    "cypress": "^3.0.1",
    "@types/cypress": "^1.1.3"
  }
}

Run an npm install and then check that the UI works okay by running ./node_modules/.bin/cypress open. Leave it running as you continue as it will auto-load changes and you can run your tests as you go.

Code Location and TS Config

I am putting my TypeScript files in the root of the test app, with component object models in a sub folder. I am moving these into the Cypress folder ./cypress/integration during compilation. You could use a task runner to do that instead if you wanted to. Here is the tsconfig.json to support this.

{
    "compilerOptions": {
        "outDir": "./cypress/integration",
        "strict": true,
        "baseUrl": "../node_modules",
        "target": "es5",
        "lib": [
            "es5",
            "dom"
        ],
        "types": [
            "cypress"
        ]
    },
    "exclude": [
        "./node_modules/**.ts"
    ]
}

First Test

I won’t patronise you with a “true equals true” assertion. We’ll just put together an entire test. Tests use Mocha and Chai, so anyone who has used these (or Jasmine, or Jest)… will know exactly how to write their tests. Anyone who has used Selenium will know to use classes to represent components. You’ll hear this referred to as Page Object Models; but actually you should represent components, or widgets, rather than whole pages.

Let’s throw a complete set of files into the mix to show this in action. If you are following along, please point your tests at a website you own!

First of all, here are some component object models to represent a home page, a search component, and a search result page.

You’ll see call to cy, which is the global Cypress variable. You will also notice that I tend to return the component, or a substitute component, from each method. This makes things chainable and also makes using the right object super-easy.

./pages/home.ts

import { Search } from './search';

export class Home {
    navigate() {
        cy.visit('https://www.example.com/');
        return this;
    }

    openSearch() {
        return new Search();
    }
}

./pages/search.ts

import { Result } from "./result";

export class Search {
    search(term: string) {
        const field = cy.get('.search-field');
        field.type(term);

        cy.get('.search-submit').click();
        return new Result();
    }
}

./pages/result.ts

export class Result {
    count() {
        return 6;
    }

    assertUrl(term: string) {
        const query = `?s=${term}`;
        cy.url().should('include', query)
    }
}

Cypress Specification

You can use these component object models from a specification file.

./specification.ts

import { Home } from './pages/home';

describe('Site Search', () => {
    it ('should query for the user entered term', () => {
        const home = new Home().navigate();
        const search = home.openSearch();
        const result = search.search('cypress');

        result.assertUrl('cypress');
    });
});

Hopefully you’ll notice that the specification itself knows nothing about Cypress, or the DOM, or element selectors.

As soon as the compiler outputs the JavaScript files for this application, the UI will pick them up and list them.

Cypress UI

You can then click on it and it will run.

Cypress Runner

You can click on the steps displayed on the left-hand side of the runner (which is within whichever browser you selected) and it will show you the state of the system under test at that time.

Summary

Cypress is a neat tool for running front-end tests, but you need to lean on all the knowledge that has come from tools such as Selenium to ensure you organise your code in a nice way. Front-end tests tend to be harder to maintain, so good design is needed to minimize this overhead. The familiarity of the tool to anyone who has used JavaScript testing frameworks, and other front-end test frameworks makes it easy to use, and it has some nice features such as the time-travel utility.

Find out more on the official website.

Lone cypress tree Monterey, CA, photo D. Ramey Logan (Resized, but otherwise unmodified). CC BY-SA 3.0