diff --git a/test/e2e/lib/mocha-e2e.js b/test/e2e/lib/mocha-e2e.js index 16aeba06..96c557a2 100644 --- a/test/e2e/lib/mocha-e2e.js +++ b/test/e2e/lib/mocha-e2e.js @@ -1,217 +1,217 @@ -'use strict'; - -const Mocha = require('mocha'); -const color = Mocha.reporters.Base.color; -const Semaphore = require('./semaphore'); -const fs = require('fs-extra'); -const config = require('./config'); -const webdriver = require('selenium-webdriver'); - -const driver = new webdriver.Builder() - .forBrowser(config.app.seleniumwebdriver.browser || 'phantomjs') - .build(); - - -const failHandlerRunning = new Semaphore(); - - -function UseCaseReporter(runner) { - Mocha.reporters.Base.call(this, runner); - - const self = this; - let indents = 0; - - function indent () { - return Array(indents).join(' '); - } - - runner.on('start', function () { - console.log(); - }); - - runner.on('suite', suite => { - ++indents; - console.log(color('suite', '%s%s'), indent(), suite.title); - }); - - runner.on('suite end', () => { - --indents; - if (indents === 1) { - console.log(); - } - }); - - runner.on('use-case', useCase => { - ++indents; - console.log(); - console.log(color('suite', '%sUse case: %s'), indent(), useCase.title); - }); - - runner.on('use-case end', () => { - --indents; - }); - - runner.on('steps', useCase => { - ++indents; - console.log(color('pass', '%s%s'), indent(), useCase.title); - }); - - runner.on('steps end', () => { - --indents; - }); - - runner.on('step pass', step => { - console.log(indent() + color('checkmark', ' ' + Mocha.reporters.Base.symbols.ok) + color('pass', ' %s'), step.title); - }); - - runner.on('step fail', step => { - console.log(indent() + color('fail', ' %s'), step.title); - }); - - runner.on('pending', test => { - const fmt = indent() + color('pending', ' - %s'); - console.log(fmt, test.title); - }); - - runner.on('pass', test => { - let fmt; - if (test.speed === 'fast') { - fmt = indent() + - color('checkmark', ' ' + Mocha.reporters.Base.symbols.ok) + - color('pass', ' %s'); - console.log(fmt, test.title); - } else { - fmt = indent() + - color('checkmark', ' ' + Mocha.reporters.Base.symbols.ok) + - color('pass', ' %s') + - color(test.speed, ' (%dms)'); - console.log(fmt, test.title, test.duration); - } - }); - - runner.on('fail', (test, err) => { - failHandlerRunning.enter(); - (async () => { - const currentUrl = await driver.getCurrentUrl(); - const info = `URL: ${currentUrl}`; - await fs.writeFile('last-failed-e2e-test.info', info); - await fs.writeFile('last-failed-e2e-test.html', await driver.getPageSource()); - await fs.writeFile('last-failed-e2e-test.png', new Buffer(await driver.takeScreenshot(), 'base64')); - failHandlerRunning.exit(); - })(); - - console.log(indent() + color('fail', ' %s'), test.title); - console.log(); - console.log(err); - console.log(); - console.log(`Snaphot of and info about the current page are in last-failed-e2e-test.*`); - }); - - runner.on('end', () => { - const stats = self.stats; - let fmt; - - console.log(); - - // passes - fmt = color('bright pass', ' ') + color('green', ' %d passing'); - console.log(fmt, stats.passes); - - // pending - if (stats.pending) { - fmt = color('pending', ' ') + color('pending', ' %d pending'); - console.log(fmt, stats.pending); - } - - // failures - if (stats.failures) { - fmt = color('fail', ' %d failing'); - console.log(fmt, stats.failures); - } - - console.log(); - }); -} - - -const mocha = new Mocha() - .timeout(120000) - .reporter(UseCaseReporter) - .ui('tdd'); - -mocha._originalRun = mocha.run; - - -let runner; -mocha.run = fn => { - runner = mocha._originalRun(async () => { - await failHandlerRunning.waitForEmpty(); - await driver.quit(); - - fn(); - }); -}; - - -async function useCaseExec(name, asyncFn) { - runner.emit('use-case', {title: name}); - - try { - await asyncFn(); - runner.emit('use-case end'); - } catch (err) { - runner.emit('use-case end'); - throw err; - } -} - -function useCase(name, asyncFn) { - if (asyncFn) { - return test('Use case: ' + name, () => useCaseExec(name, asyncFn)); - } else { - // Pending test - return test('Use case: ' + name); - } -} - -useCase.only = (name, asyncFn) => { - return test.only('Use case: ' + name, () => useCaseExec(name, asyncFn)); -}; - -useCase.skip = (name, asyncFn) => { - return test.skip('Use case: ' + name, () => useCaseExec(name, asyncFn)); -}; - -async function step(name, asyncFn) { - try { - await asyncFn(); - runner.emit('step pass', {title: name}); - } catch (err) { - runner.emit('step fail', {title: name}); - throw err; - } -} - -async function steps(name, asyncFn) { - try { - runner.emit('steps', {title: name}); - await asyncFn(); - runner.emit('steps end'); - } catch (err) { - runner.emit('step end'); - throw err; - } -} - -async function precondition(preConditionName, useCaseName, asyncFn) { - await steps(`Including use case "${useCaseName}" to satisfy precondition "${preConditionName}"`, asyncFn); -} - -module.exports = { - mocha, - useCase, - step, - steps, - precondition, - driver -}; \ No newline at end of file +'use strict'; + +const Mocha = require('mocha'); +const color = Mocha.reporters.Base.color; +const Semaphore = require('./semaphore'); +const fs = require('fs-extra'); +const config = require('./config'); +const webdriver = require('selenium-webdriver'); + +const driver = new webdriver.Builder() + .forBrowser(config.app.seleniumwebdriver.browser || 'phantomjs') + .build(); + + +const failHandlerRunning = new Semaphore(); + + +function UseCaseReporter(runner) { + Mocha.reporters.Base.call(this, runner); + + const self = this; + let indents = 0; + + function indent () { + return Array(indents).join(' '); + } + + runner.on('start', function () { + console.log(); + }); + + runner.on('suite', suite => { + ++indents; + console.log(color('suite', '%s%s'), indent(), suite.title); + }); + + runner.on('suite end', () => { + --indents; + if (indents === 1) { + console.log(); + } + }); + + runner.on('use-case', useCase => { + ++indents; + console.log(); + console.log(color('suite', '%sUse case: %s'), indent(), useCase.title); + }); + + runner.on('use-case end', () => { + --indents; + }); + + runner.on('steps', useCase => { + ++indents; + console.log(color('pass', '%s%s'), indent(), useCase.title); + }); + + runner.on('steps end', () => { + --indents; + }); + + runner.on('step pass', step => { + console.log(indent() + color('checkmark', ' ' + Mocha.reporters.Base.symbols.ok) + color('pass', ' %s'), step.title); + }); + + runner.on('step fail', step => { + console.log(indent() + color('fail', ' %s'), step.title); + }); + + runner.on('pending', test => { + const fmt = indent() + color('pending', ' - %s'); + console.log(fmt, test.title); + }); + + runner.on('pass', test => { + let fmt; + if (test.speed === 'fast') { + fmt = indent() + + color('checkmark', ' ' + Mocha.reporters.Base.symbols.ok) + + color('pass', ' %s'); + console.log(fmt, test.title); + } else { + fmt = indent() + + color('checkmark', ' ' + Mocha.reporters.Base.symbols.ok) + + color('pass', ' %s') + + color(test.speed, ' (%dms)'); + console.log(fmt, test.title, test.duration); + } + }); + + runner.on('fail', (test, err) => { + failHandlerRunning.enter(); + (async () => { + const currentUrl = await driver.getCurrentUrl(); + const info = `URL: ${currentUrl}`; + await fs.writeFile('last-failed-e2e-test.info', info); + await fs.writeFile('last-failed-e2e-test.html', await driver.getPageSource()); + await fs.writeFile('last-failed-e2e-test.png', new Buffer(await driver.takeScreenshot(), 'base64')); + failHandlerRunning.exit(); + })(); + + console.log(indent() + color('fail', ' %s'), test.title); + console.log(); + console.log(err); + console.log(); + console.log(`Snaphot of and info about the current page are in last-failed-e2e-test.*`); + }); + + runner.on('end', () => { + const stats = self.stats; + let fmt; + + console.log(); + + // passes + fmt = color('bright pass', ' ') + color('green', ' %d passing'); + console.log(fmt, stats.passes); + + // pending + if (stats.pending) { + fmt = color('pending', ' ') + color('pending', ' %d pending'); + console.log(fmt, stats.pending); + } + + // failures + if (stats.failures) { + fmt = color('fail', ' %d failing'); + console.log(fmt, stats.failures); + } + + console.log(); + }); +} + + +const mocha = new Mocha() + .timeout(120000) + .reporter(UseCaseReporter) + .ui('tdd'); + +mocha._originalRun = mocha.run; + + +let runner; +mocha.run = fn => { + runner = mocha._originalRun(async () => { + await failHandlerRunning.waitForEmpty(); + await driver.quit(); + + fn(); + }); +}; + + +async function useCaseExec(name, asyncFn) { + runner.emit('use-case', {title: name}); + + try { + await asyncFn(); + runner.emit('use-case end'); + } catch (err) { + runner.emit('use-case end'); + throw err; + } +} + +function useCase(name, asyncFn) { + if (asyncFn) { + return test('Use case: ' + name, () => useCaseExec(name, asyncFn)); + } else { + // Pending test + return test('Use case: ' + name); + } +} + +useCase.only = (name, asyncFn) => { + return test.only('Use case: ' + name, () => useCaseExec(name, asyncFn)); +}; + +useCase.skip = (name, asyncFn) => { + return test.skip('Use case: ' + name, () => useCaseExec(name, asyncFn)); +}; + +async function step(name, asyncFn) { + try { + await asyncFn(); + runner.emit('step pass', {title: name}); + } catch (err) { + runner.emit('step fail', {title: name}); + throw err; + } +} + +async function steps(name, asyncFn) { + try { + runner.emit('steps', {title: name}); + await asyncFn(); + runner.emit('steps end'); + } catch (err) { + runner.emit('step end'); + throw err; + } +} + +async function precondition(preConditionName, useCaseName, asyncFn) { + await steps(`Including use case "${useCaseName}" to satisfy precondition "${preConditionName}"`, asyncFn); +} + +module.exports = { + mocha, + useCase, + step, + steps, + precondition, + driver +}; diff --git a/test/e2e/lib/semaphore.js b/test/e2e/lib/semaphore.js index 7c30c900..d22b8f71 100644 --- a/test/e2e/lib/semaphore.js +++ b/test/e2e/lib/semaphore.js @@ -1,35 +1,35 @@ -'use strict'; - -const Promise = require('bluebird'); - -class Semaphore { - constructor() { - this.counter = 0; - } - - enter() { - this.counter++; - } - - exit() { - this.counter--; - } - - async waitForEmpty() { - const self = this; - - function wait(resolve) { - if (self.counter == 0) { - resolve(); - } else { - setTimeout(wait, 500, resolve); - } - } - - return new Promise(resolve => { - setTimeout(wait, 500, resolve); - }) - } -} - -module.exports = Semaphore; \ No newline at end of file +'use strict'; + +const Promise = require('bluebird'); + +class Semaphore { + constructor() { + this.counter = 0; + } + + enter() { + this.counter++; + } + + exit() { + this.counter--; + } + + async waitForEmpty() { + const self = this; + + function wait(resolve) { + if (self.counter == 0) { + resolve(); + } else { + setTimeout(wait, 500, resolve); + } + } + + return new Promise(resolve => { + setTimeout(wait, 500, resolve); + }) + } +} + +module.exports = Semaphore;