How I Tricked Our Testers Into Becoming JavaScript Developers

Craig

TRADE ME

@phenomnominal

Testing user interfaces is really hard

REALLY HARD

OLD SITE

 

COMPLICATED

 

Lots of manual testing

SLOWING US DOWN

AUTOMATED USER INTERFACE TESTING?

ROBOT FRAMEWORK + RIDE

SLOW & HARD

UNRELIABLE

HARD TO MAINTAIN

BUT!

THEY WORK!

(ish)

WE DON'T TRUST OUR TESTS

BUILDING TRUST...

CAN WE USE BETTER TOOLS?

GHERKIN + CUCUMBER

# doSomething.feature
Feature: Do something
    In order to feel good about myself
    As a human
    I want to do something

    Scenario: Do a thing
       When I do something
       Then I should feel good about myself

FEATURES:

# whenIDoSomething.js
this.When(/^I do something$/, function(done) {
    done.pending();
});

# thenIShouldFeelGoodAboutMyself.js
this.Then(/^I should feel good about myself$/, function(done) {
    done.pending();
});

STEP DEFINITIONS:

YAY!

EASY TO UNDERSTAND LANGUAGE

REUSABLE CHUNKS OF INTERACTION

NICELY ALIGNED WITH BUSINESS RULES

& ACCEPTANCE CRITERIA

ANGULARJS + PROTRACTOR

WEB DRIVER JS

PROMISES (NO WAITS)

WORKS WITH CUCUMBER!

ROBUSTNESS++

RELIABILITY++

But...

NEW FUNCTIONALITY = FAST

NEW TESTS = SLOW

UI TESTS NOW WRITTEN IN JAVASCRIPT?

Tests not getting written

TESTERS GOING BACK TO ROBOT FRAMEWORK

TESTS BREAK EASILY AS THE CODEBASE CHANGES...

BETTER:

Modular reuseable step definitions

UI tests written in JavaScript

More reliable & ROBUST tests

NOT BETTER:

STILL SLOW TO CREATE TESTS

NEW PROBLEM:

WHOSE RESPONSIBILITY?

WHAT NEXT?

TRACTOR!

A UI FOR CREATING AUTOMATED UI TESTS WITH PROTRACTOR

COMPONENTS

FEATURES

STEP DEFINITIONS

MOCK DATA

COMPONENTS

Just like page objects in Selenium

ENCAPSULATED BEHAVIOUR

this.When(/^I type in my username$/, function (done) {
    element(by.css('#UserName')).sendKeys('username');
    done();
});

this.When(/^I type in my password$/, function (done) {
    element(by.css('#Password')).sendKeys('secret');
    done();
});

this.When(/^I click the login button$/, function (done) {
    element(by.css('#LoginButton')).click();
    done();
});

BEFORE:

// UserLogin.component.js
function UserLogin () {
    this.userNameInput = element(by.css('#UserName'));
    this.passwordInput = element(by.css('#Password'));
    this.loginButton = element(by.css('#LoginButton'));
}

UserLogin.prototype.login = function (username, password) {
    this.userNameInput.sendKeys(username);
    this.passwordInput.sendKeys(password);
    this.loginButton.click();
};

// WhenILogIn.step.js
this.When(/^I log in$/, function (done) {
    var UserLogin = new UserLogin();
    UserLogin.login('username', 'secret');
});

AFTER:

FEATURES + STEP DEFINITIONS

GIVEN - SET UP MOCK DATA

WHEN - INTERACT WITH PAGE

THEN - CHECK EXPECTATIONS

MOCK DATA

DATA IS EXPECTED TO BE MOCKED BY DEFAULT

YOU CAN JUST PASS-THROUGH TO REAL DATA

Everything is just files!

DEMO

JSONDIR

BE CAREFUL?

ESPRIMA + ESCODEGEN

ACTUAL MAGIC

ESQUERY

ESTEMPLATE

NODE + WINDOZE

JUST USE PATH FOR EVERYTHING

SRSLY.

REWIRE - Node DI

BROWSERIFY

GUlp

GITHUB: TRADE ME / TRACTOR