Modern Integration Testing for JavaScript Applications

Dr Gleb Bahmutov PhD

VP of Eng

C / C++ / C# / Java / CoffeeScript / JavaScript / Node / Angular / Vue / Cycle.js / functional


virtual tours


MatLab on the web


finance dashboards

Testing sucks

It is too hard

It takes too long

It is not that useful

Testing is

a drag

Testing Pyramid

Unit tests pass...

We write more unit tests because our tools make it EASY

$ npm install -D jest
const add = require('./add')
describe('addition', () => {
  it('adds numbers', () => {
    expect(add(1, 2)).toBe(3)
$ npm test

How test end to end

  1. During a full moon sacrifice two goats

  2. Install Selenium

  3. Quickly write E2E tests and throw them into Selenium before it gets angry

E2E should be easy

  • Easy to install

  • Easy to write tests

  • Simple to run

Easy to debug when a test fails

$ npm install -D cypress

Tip: cache "node_modules" folder on CI

Let's test "TodoMVC"!

Is the app focused on "New Todo" input?

this looks close

it('is focused on new item', () => {

that's result of "cy.focused()"

it('is focused on new item', () => {
  cy.focused().should('have.class', 'new-todo')

I know exactly what happens

it('is focused on new item', () => {
  cy.focused().should('have.class', 'new-todo')

Every command

outputs detailed info

in DevTools

Making Assertions

Chai, Chai-jQuery, Sinon-Chai

Default Assertions

  • cy.visit() expects the page to send text/html content with a 200 status code
  • cy.get() expects the element to eventually exist in the DOM
  • .type() expects the element to eventually be in a typeable state

and many more ...

Failing Test

The first time one of your

tests fails in Cypress

will be one of your best days

as a developer

zero elements found


Trying to type into a list item element

Cypress team

carefully hand crafts

each and every

error message

Giant API

80 commands + events + utilities (lodash, moment, jQuery) + assertions

Every command is described in excruciating detail

  • Syntax
  • Correct usage
  • Incorrect usage
  • Options
  • What it logs
  • Examples and best practices

Test whatever you want

const url = ''
  "baseUrl: ""
$ export CYPRESS_baseUrl=
$ $(npm bin)/cypress run

Need for Speed

Cypress is VERY FAST


var webdriverio = require('webdriverio');
var options = { desiredCapabilities: { browserName: 'chrome' } };
var client = webdriverio.remote(options);
    .setValue('#search_form_input_homepage', 'WebdriverIO')
    .getTitle().then(function(title) {
        console.log('Title is: ' + title);
        // outputs:
        // "Title is: WebdriverIO (Software) at DuckDuckGo"
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
       .withTimeout(30, SECONDS)
       .pollingEvery(5, SECONDS)

Timeouts, timeouts everywhere!


Test continues as soon as DOM updates

But wait, there is more ...

  • Add your commands

  • Server stubbing

  • Screenshots and videos

  • Chromium-based browsers

  • Easy CI setup

Is there is a catch?

  • Multi-browser support is coming

  • Windows support is coming

  • Plugin system is coming

This week đŸ¤”

Giving Cypress Away

This week đŸ¤”

Cypress Dashboard

See, share, and fix failing tests.

Cypress Dashboard

  • Is a paid Saas complement to Cypress app
  • Perfect place to store test results, screenshots and videos
  • Helps find why and when a test started failing

Thank you

$ npm install -D cypress