Minesweepers Anonymous

Once upon a time there lived a couple who loved playing massively multiplayer online role-playing video games with each other (World of Warcraft or Destiny or something). The thing about these games is that they’re a bit like exercise/fitness where you need to keep playing them to keep your score high, and if you don’t you play them (or exercise) enough your score (or fitness) starts dropping which makes it much less fun overall.

So playing these games all went well for the couple, for a while.

Continue reading “Minesweepers Anonymous”

Handling JavaScript alerts when leaving a page with WebDriver

You’ve most probably seen the sometimes-useful-but-often-annoying browser alerts when navigating away from a page:JavaScript onbeforeunload alert

How do we deal with these using WebDriver?

Continue reading “Handling JavaScript alerts when leaving a page with WebDriver”

AMA: Learning JavaScript automation & starting e2e tests

Edwin asks…

How should someone approach learning JavaScript strictly for the purpose of test automation? Should they learn it the way a front-end developer would or is there a better way to learn it for purposes of writing automation?

anil also asks…

I need to do automation by using mocha chai framework with selenum webdriver. can you please guide me or suggest any site or video on how to start and what are the basic things need to know.

Continue reading “AMA: Learning JavaScript automation & starting e2e tests”

AMA: more details about our JS e2e tests

Satyajit Malugu asks…

Saw your recent post on JS vs Ruby. As a recent migrant from Ruby to JS for mobile test automation – couple of questions 1) how are you doing page objects (ES6 works too) 2) Are you able to run your E2E tests in parallel? 3)Is there anything like binding.pry for debugging JS whilst execution?)

My response…

  1. This post explains how we’re doing our page objects in ES6, and since all our e2e tests are open source, you can see for yourself :)
  2. We use CircleCI which supports parallel test execution, which I enabled in the past, but it’s currently disabled as it was consuming too many build containers which are shared across our organization. Since we have a lot more containers available now I have it on my list to renable these.
  3. I believe WebStorm supports debugging Node Mocha tests; I’ve been meaning to investigate this over console.log statements; I’ll report back when I get around to it.

AMA: Mocha this.timeout Duplication

 Alex C asks…

I notice that the “this.timeout” code is duplicated across the before and test suite. This seems mentally uncomfortable to me and the logical question is: “Why duplicate code that is in a before method?” Right now, the only thing I can think would be an explanation is “because it’s just a workaround to how the Javascript binding does things.”

import assert from 'assert';
import webdriver from 'selenium-webdriver';
import test from 'selenium-webdriver/testing';
import config from 'config';
import RalphSaysPage from '../lib/ralph-says-page.js';

let driver;

const mochaTimeoutMS = config.get( 'mochaTimeoutMS' );

test.before( function() {
	this.timeout( mochaTimeoutMS );
	driver = new webdriver.Builder().withCapabilities( webdriver.Capabilities.chrome() ).build();
} );

test.describe( 'Ralph Says', function() {
	this.timeout( mochaTimeoutMS );

	test.it( 'shows a quote container', function() {
		var page = new RalphSaysPage( driver, true );
		page.quoteContainerPresent().then( function( present ) {
			assert.equal( present, true, 'Quote container not displayed' );
		} );
	} );

	test.it( 'shows a non-empty quote', function() {
		var page = new RalphSaysPage( driver, true );
		page.quoteTextDisplayed().then( function( text ) {
			assert.notEqual( text, '', 'Quote is empty' );
		} );
	} );
} );

test.afterEach( () => driver.manage().deleteAllCookies() );

test.after( () => driver.quit() );

My response…

Mocha has a low default timeout (2000ms) as it wasn’t really written to be used for e2e testing. In the way I’ve written the above code, all the four test. blocks don’t share any instance state, so setting this.timeout in one will not effect the other, hence why I wrote it that way.

Having a few months experience behind me, I can see it’s easy to rewrite the above tests to avoid this duplication (and to have less lines of code):

import assert from 'assert';
import webdriver from 'selenium-webdriver';
import test from 'selenium-webdriver/testing';
import config from 'config';
import RalphSaysPage from '../lib/ralph-says-page.js';

let driver;

const mochaTimeoutMS = config.get( 'mochaTimeoutMS' );

test.describe( 'Ralph Says', function() {
	this.timeout( mochaTimeoutMS );

	test.before( function() {
		driver = new webdriver.Builder().withCapabilities( webdriver.Capabilities.chrome() ).build();
	} );

	test.it( 'shows a quote container', function() {
		var page = new RalphSaysPage( driver, true );
		page.quoteContainerPresent().then( function( present ) {
			assert.equal( present, true, 'Quote container not displayed' );
		} );
	} );

	test.it( 'shows a non-empty quote', function() {
		var page = new RalphSaysPage( driver, true );
		page.quoteTextDisplayed().then( function( text ) {
			assert.notEqual( text, '', 'Quote is empty' );
		} );
	} );

	test.afterEach( () => driver.manage().deleteAllCookies() );

	test.after( () => driver.quit() );
} );

But you still would have to duplicate this across different test files though, even though it’s stored as a config value. I’ve since realised Mocha allows you to globally override this timeout using test/mocha.opts.

AMA: R.Y.O. Page Objects 2.0

Michael Karlovich asks…

Do you have any updated thoughts on rolling your own page objects with Watir? The original post is almost 4 years old but is still the basis (loosely) of every page object framework I’ve built since then.

My response…

Wow, I can’t believe that post is almost four years old. I have also have used this for the basis of every page object framework I have built since then.

I recently had a look at our JavaScript (ES2015) code of page objects and despite ES2015 not having meta-programming support like ruby, our classes are remarkably similar to what I was proposing ~4 years ago.

I believe this is because some patterns are classic and therefore almost timeless, they can be applied over and over again to different contexts. There’s a huge amount of negativity towards best practices of late, but I could seriously say that page objects are a best practise for test automation of ui systems, which isn’t saying they will be exactly the same in every context, but there’s a common best-practice pattern there which you most likely should be using.

Page objects, as a pattern, typically:

  • Inherit from a base page object/container which stores common actions like:
    • instantiating the object looking for a known element that defines that page’s existence
    • optionally allow a ‘visit’ to the page during instantiation using some defined URL/path
    • provides actions and properties common to all pages, for example: waiting for the page, checking the page is displayed, getting the title/url of the page, and checking cookies and local storage items for that page;
  • Define actions as methods which are ways of interacting with that page (such as logging in);
  • Do not expose internals about the page outside the page – for example they typically don’t expose elements or element selectors which should only be used within actions/methods for that page which are exposed; and
  • Can also be modelled as components for user interfaces that are built using components to give greater reusability of the same components across different pages.

The biggest benefit I have found from using page objects as a pattern is having more deterministic end-to-end tests since instantiating a page I know I am on that page, so my tests will fail more reliably with a better understanding of what went wrong.

Are there any other pattern attributes you would consider vital for page objects?