Skip to content

Commit

Permalink
play around
Browse files Browse the repository at this point in the history
  • Loading branch information
bevacqua committed Dec 20, 2013
1 parent f59da7f commit 226602a
Show file tree
Hide file tree
Showing 7 changed files with 261 additions and 1 deletion.
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -0,0 +1,3 @@
# 0.1.0 Sauce

- Initial Release
11 changes: 11 additions & 0 deletions README.markdown
@@ -1,6 +1,17 @@
# grunt-integration [![Build Status](https://travis-ci.org/bevacqua/grunt-integration.png?branch=master)](https://travis-ci.org/bevacqua/grunt-integration) [![Dependency Status](https://gemnasium.com/bevacqua/grunt-integration.png)](https://gemnasium.com/bevacqua/grunt-integration) [![help me on gittip](http://gbindex.ssokolow.com/img/gittip-43x20.png)](https://www.gittip.com/bevacqua/) [![flattr.png](https://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=nzgb&url=https%3A%2F%2Fgithub.com%2Fbevacqua%2Fgrunt-integration)

# Configuration

Here are the default configuration values.

```js
{
program: 'node app',
program_port: process.env.TEST_PORT || 3333,
program_inherit: true,
selenium_inherit: false
}
```

# License

Expand Down
54 changes: 54 additions & 0 deletions lib/mocha.js
@@ -0,0 +1,54 @@
var Mocha = require('mocha');
var path = require('path');
var Module = require('module');
var fs = require('fs');
var path = require('path');
var domain = require('domain');

module.exports = function (opts, fileGroup, browser, grunt, done) {
var mocha = new Mocha(opts);

mocha.suite.on('pre-require', function (context, file, m) {
this.ctx.browser = browser;
this.ctx.wd = opts.wd;
});

grunt.file.expand({ filter: 'isFile' }, fileGroup.src).forEach(function (file) {
var filePath = path.resolve(file);
if (Module._cache[filePath]) {
delete Module._cache[filePath];
}
mocha.addFile(filePath);
});

if (mocha.files.length) {
mocha.loadFiles();
}

var context = domain.create();
var mochaOptions = mocha.options;
var mochaRunner = new Mocha.Runner(mocha.suite);
var mochaReporter = new mocha._reporter(mochaRunner);

mochaRunner.ignoreLeaks = (mochaOptions.ignoreLeaks !== false);
mochaRunner.asyncOnly = mochaOptions.asyncOnly;

if (mochaOptions.grep) {
mochaRunner.grep(mochaOptions.grep, mochaOptions.invert);
}

if (mochaOptions.globals) {
mochaRunner.globals(mochaOptions.globals);
}

context.on('error', mochaRunner.uncaught.bind(mochaRunner));
context.run(function () {
mochaRunner.run(function (errCount) {
var err;
if (errCount !== 0) {
err = new Error('Tests encountered ' + errCount + ' errors.');
}
done(err);
});
});
};
3 changes: 3 additions & 0 deletions lib/standalone.js
@@ -0,0 +1,3 @@
'use strict';

module.exports = require('selenium-standalone-painful');
49 changes: 49 additions & 0 deletions lib/testdrive.js
@@ -0,0 +1,49 @@
'use strict';

var wd = require('wd');
var async = require('async');
var runner = require('./lib/mocha.js');

module.exports = function (files, opts, done) {

async.forEachSeries(files, function (fileGroup, next) {
var queue = async.queue(function (browserOpts, dequeue) {
prepare(browserOpts, fileGroup, dequeue);
}, next, opts.concurrency);

opts.browsers.forEach(enqueue.bind(null, queue));

}, done);

function prepare(browserOpts, fileGroup, next) {
var style = opts.usePromises ? 'promiseChainRemote': 'remote';

browser = wd[style](opts);
browser.browserTitle = browserOpts.browserTitle;
browser.init(browserOpts, function (err) {
if (err) {
return next(err);
}
run(fileGroup, browser, next);
});
}

function run(fileGroup, browser, next) {
opts.wd = wd;

runner(opts, fileGroup, browser, grunt, function (err) {
browser.quit();
next(err);
});
}

function enqueue(queue, browserOpts) {
browserOpts.browserTitle = browserOpts.browserName;

queue.push(browserOpts, function (err) {
if (err) {
testResult = new Error('One or more tests on Selenium failed.');
}
});
}
};
12 changes: 11 additions & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "grunt-integration",
"description": "",
"description": "Run Integration Tests using Selenium, Mocha, a Server, and a Browser",
"homepage": "https://github.com/bevacqua/grunt-integration",
"author": {
"name": "Nicolas Bevacqua",
Expand Down Expand Up @@ -36,5 +36,15 @@
},
"peerDependencies": {
"grunt": "~0.4.2"
},
"dependencies": {
"lodash": "~2.4.1",
"spawn-machine": "~0.1.0",
"chalk": "~0.4.0",
"selenium-standalone-painful": "~2.39.0-2.7.0",
"process-finder": "0.0.7",
"async": "~0.2.9",
"mocha": "~1.16.0",
"wd": "~0.2.7"
}
}
130 changes: 130 additions & 0 deletions tasks/integration.js
@@ -0,0 +1,130 @@
'use strict';

module.exports = function (grunt) {
var _ = require('lodash');
var async = require('async');
var chalk = require('chalk');
var spawn = require('spawn-machine');
var finder = require('process-finder');
var pkg = require('../package.json');
var context = {};

grunt.registerMultiTask('integration', pkg.description, function () {
var done = this.async();
var name = this.target;

var ctx = context[name] = {
name: name,
options: this.options({
program: 'node app',
program_port: process.env.TEST_PORT || 3333,
program_inherit: true,
selenium_inherit: false,
tests: {
concurrency: 1,
usePromises: true
}
}),
files: this.files
};

async.series([
async.apply(selenium, ctx),
async.apply(program, ctx),
async.apply(tests, ctx)
], done);
});

function selenium (ctx, next) {
var standalone = require('../lib/standalone.js');
var rready = /Started org\.openqa\.jetty\.jetty\.Server/i;
var rwarning = /\b(warn(ing)?|error|exception)\b/i;

console.log('Spawning selenium server...');

var child = standalone.start({ stdio: 'pipe' });

ctx.selenium = {
name: 'Selenium',
child: child
};

var teardown = cleanup.bind(null, ctx.selenium);

child.stdout.on('data', function (data) {
var stdout = data.toString();
if (ctx.options.selenium_inherit) {
process.stdout.write(stdout);
}

if (rready.test(stdout)) {
console.log(chalk.magenta('Selenium server operational'));
next();
}
});

child.stderr.on('data', function (data) {
if (ctx.options.selenium_inherit) {
process.stderr.write(data);
} else {
var print = rwarning.test(data);
if (print) {
process.stderr.write(chalk.red('[SELENIUM] ' + data));
}
}
});

process.on('exit', teardown);
}


function program (ctx, next) {
var port = ctx.options.port;
var watcher = finder.watch({ port: port, frequency: 400 });
var env = _.clone(process.env);
env.PORT = port;

console.log('Spawning application...');

var child = spawn(ctx.options.program, {
stdio: ctx.options.program_inherit ? 'inherit' : 'pipe',
env: env
});

ctx.app = {
name: 'Application',
child: child
};

var teardown = cleanup.bind(null, ctx.app);

watcher.on('listen', function () {
console.log('Application online', chalk.magenta(port));
next();
});

process.on('exit', teardown);
}

function tests (ctx, next) {
var testdrive = require('../lib/testdrive.js');

console.log('Executing tests...');
testdrive(ctx.files, ctx.options.tests, next);
}

function cleanup (target) {
if (target.terminated) {
return;
}

target.terminated = true;

if (target.child) {
target.child.kill('SIGHUP');
console.log('%s process %s shutting down', chalk.magenta(target.name), chalk.yellow(target.child.pid));
} else {
console.log(chalk.magenta(target.name), chalk.red('process not found'));
}
}
};

0 comments on commit 226602a

Please sign in to comment.