HomePhabricator
Fanboying Cypress
My quick terse on Cypress.io

Software development is pretty agile in its nature in that things normally tend to move pretty quickly. However, the faster you move, the more things break. As a codebase grows in size, its pieces become more and more complex, with every line adding a potential bug. In Wikimedia Foundation, we keep a handle on this through rigorous amounts of testing. Manual testing requires a lot of effort especially when you have a large core repository with a plethora of plugins and extensions that need to be tested. One of the hot frameworks on the scene is Cypress, a complete end to end testing solution.

We have undoubtedly entered into the era of automated testing. Despite this, web end-to-end testing has always been a tricky beast. Good ol’ Selenium has been the main solution for quite some time now and has a huge history. Despite its impressive browser compatibility, having tests that are more consistent and less flakey can be a non-trivial matter mainly because Selenium was not designed for app testing. Enter Cypress, a modern automated testing tool, which not only promises to fix the old and broken ways of past framework but also make the entire process more developer centric. After spending over two months trying to migrate the tests written in WebdriverIO to Cypress, I wanted to share my journey with Cypress thus far.

What Cypress brings to the Party?

cypress_overview.png (597×1 px, 128 KB)

End-to-end testing is notoriously known for its fragmented experience. You need to bring a lot of your own tools, for example, you need:

  • a test runner
  • an assertion library
  • some reporters
  • mocks, etc

Cypress includes all of these good stuff out of the box, making setup and configuration dead simple. At the same time, Cypress gives developers an immense amount of freedom when it comes to plugging in things of your own preference. In short,

Cypress takes a batteries included but removable approach

Documentation

A good software should be accompanied by a great documentation for it to be complete.

Cypress has a documentation that is some of the best I have ever read. They have guides on everything that you are likely to encounter. They do a great job telling you how to use the product. In fact, they even have in-depth explanations on the architecture, flakey tests and best practices.

Prototyping

If you have the chance, before adopting anything of this scale, I always think it’s a good idea to test it on a small project first, just to get a feel. Before advocating for it, I added it to my personal blog, just to see how the experience was.

A very simple scenario:

Load an app -> Go to index page -> Click blog link -> Assert content shows up

This was really as simple as writing a few lines of Javascript for the test itself, the npm script in package.json and running it on the CI. I was blown away with how fast it took me, under an hour. I had toiled hard trying to set up video recording with Puppeteer and Jest. Not only did Cypress perform the assertions but also it was recording videos!

Page Object Model in Cypress

Page Object Model is an object design pattern in Selenium, where web pages are represented as classes, and the various elements on the page are defined as variables on the class. All possible user interactions can then be implemented as methods on the class.

Since well-named methods in classes are easy to read, this works as an elegant way to implement test routines that are both readable and easier to maintain or update in the future. Let us take an example of a page model for testing user account creation in WebdriverIO.

wdio_createaccount.page.js
"use strict";

class CreateAccountPage {
    get username() {
        return $("#username");
    }

    get password() {
        return $("#password");
    }

    get confirmPassword() {
        return $("#retypePassword");
    }

    get create() {
        return $("#createBtn");
    }

    get heading() {
        return $("#firstHeading");
    }

    open() {
        browser.url("https://some_url.com/account/create");
    }

    createAccount(username, password) {
        this.open();
        this.username.setValue(username);
        this.password.setValue(password);
        this.confirmPassword.setValue(password);
        this.create.click();
    }
}

module.exports = new CreateAccountPage();

All you need to do is now call the CreateAccountPage.createAccount method with proper parameters in order to create a user account. Let us have a look at the Cypress version for this:

cypress_createaccount.page.js
"use strict";

class CreateAccountPage {
    constructor() {
        this.username = "#username";
        this.password = "#password";
        this.confirmPassword = "#retypePassword";
        this.create = "#createBtn";
        this.heading = "#firstHeading";
    }

    open() {
        cy.visit("https://some_url.com/account/create");
    }

    createAccount(username, password) {
        this.open();
        cy.get(this.username).type(username);
        cy.get(this.password).type(password);
        cy.get(this.confirmPassword).type(password);
        cy.get(this.create).click();
    }
}

module.exports = new CreateAccountPage();

Writing Scenarios with Gherkin

1-78i-I8tt-O4cw-D1k7i-Vs-FVyw.png (878×1 px, 162 KB)

If you have written end-to-end tests before, you may be familiar with Gherkin syntax, used by Cucumber. This is an expressive, English-like way to write test scenarios. It can help with documenting your features and non-developers can contribute to writing test cases. I found a way to integrate this file syntax into Cypress using a plugin.

Feature: Searching on Wikipedia
    As a programmer, I want to search Wikipedia, so that I can learn new things.

    Background:
        Given I am on Wikipedia

    Scenario: Simple Wikipedia search
        When the search phrase "Bayesian"  is entered
        Then results for "Bayesian" are shown

After writing these commands, the plugin will then go to Cypress to actually run the implementations:

import { Given } from 'cypress-cucumber-preprocessor/steps';

Given('I am on Wikipedia website', () => {
  cy.visit('https://en.wikipedia.com');
});

When('the search phrase "Bayesian" is entered', () => {
  ...
});

When('results for "Bayesian" are shown', () => {
  ...
});

Asserting Elements and Best Practices

js-testing.png (600×1 px, 12 KB)

End-to-end testing is all about making sure elements on the page have the right content. When writing Cypress tests, you will likely be spending 70% of your time selecting elements and peering inside them. Cypress has a standard get() command which exposes a jQuery-like selector to you. This should be familiar to those with some experience in Selenium.

However, a problem with this selector is that it can be used incorrectly and there is no way to enforce (with code) it’s usage. Welcome cypress-testing-library. This plugin exposes a myriad of commands prefixed with find which work similarly to how get() does in native Cypress. All of these commands make for selectors that are resilient to change. This can have a dramatic effect on how your tests stay consistent as your application progresses.

Time for Some Debugging

Debugging end-to-end tests with Selenium can be somewhat of a nightmare. With Cypress, this pain is at an all-time low. One of the biggest focuses of the core product is to be able to debug is one of the more pleasant experiences in your Cypress journey. Like for most things, they have a great guide to get you started.

Browser Support

Unfortunately, if your organization needs to have support for IE11, you are out of luck. The Cypress team has explicitly said they won’t be supporting it. There is an incredible thread on Github that I really hope you read through. It goes into why they are rolling this out slowly and didn’t choose WebDriver from the beginning and wrote their own custom driver. This is the only place where Cypress falls behind Selenium. However, it does support most of the Chromium-based browsers and is starting to roll-out support for Firefox too and this should serve the needs for most organisations.

I highly recommend everyone in the end-to-end testing community to give Cypress a shot. The quick setup, smooth documentation, fluid construction of tests and warm and supportive community will likely make you fall in love with it.

Originally published at https://www.sohamp.dev/blog/2020-06-29-fanboying-cypress

Written by Soham on Jul 7 2020, 11:50 AM.
User
Projects
Subscribers
Vqktabwire, mmodell, Chandanareddy123
Tokens
"Party Time" token, awarded by zeljkofilipin.