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.

Author: Alister Scott

Alister is an Excellence Wrangler for Automattic.

2 thoughts on “AMA: Mocha this.timeout Duplication”

  1. Thanks for doing these! One thing I always aim for is DAMP, not DRY test code. “Descriptive and meaningful phrases” instead of “don’t repeat yourself”. Duplication isn’t always evil.

    Liked by 1 person

Comments are closed.