grunt-casper-teamcity
Version:
Run Casper CLI Scripts With Grunt + Hudl changes to support teamcity logs. This is fork of grunt-casper
238 lines (203 loc) • 7.45 kB
JavaScript
/*global exports, require, process*/
//node
var path = require('path'),
fs = require('fs');
//npm
var _ = require('lodash');
var additionalLogFilePath = 'testOutput.log';
//npm install wrapper
var phantomjs = require('phantomjs-prebuilt');
var slimerjs = require('slimerjs');
function getTeamCityNowDate() {
var date = new Date();
return date.toISOString().replace("Z", "+0000");;
}
/**
* Initializer For Grunt
* @param grunt
*/
exports.init = function(grunt) {
'use strict';
var instantLog = function instantLog() {
var args = Array.prototype.slice.call(arguments);
var dataToWrite = args.join(' ');
fs.appendFile(additionalLogFilePath, dataToWrite, function(err) {
grunt.verbose.write('Could not appended to instant log file. Err:', err, '\n');
});
};
var casper = {
testableOptions: {
pre: true,
post: true,
includes: true,
verbose: true,
'log-level': true,
'fail-fast': true,
'concise': true,
'xunit': true,
'no-colors': true
},
supportedEngines: [
'phantomjs',
'slimerjs'
],
modulePaths: [
path.resolve(__dirname, '../../node_modules'), //local
path.resolve(__dirname, '../../..'), //sibling
'/usr/local/lib/node_modules' //global
],
/**
* Spawn Casperjs Child Process
* @param cwd
* @param args
* @param next
*/
spawn: function(cwd, args, next) {
grunt.verbose.write('Spawning casperjs with args: ', args, '\n');
instantLog('Spawning casperjs with args: ', args, '\n');
//No CasperBin Found Yet
var casperBin = null;
//Set PhantomJS Path only if the file exists, otherwise fall back to ENV
if (fs.existsSync(phantomjs.path)) {
grunt.verbose.write('Found PhantomJS Executable', phantomjs.path, '\n');
instantLog('Found PhantomJS Executable', phantomjs.path, '\n');
process.env["PHANTOMJS_EXECUTABLE"] = phantomjs.path;
}
if (fs.existsSync(slimerjs.path)) {
grunt.verbose.write('Found SlimerJS Executable', slimerjs.path, '\n');
instantLog('Found SlimerJS Executable', slimerjs.path, '\n');
process.env["SLIMERJS_EXECUTABLE"] = slimerjs.path;
}
//Is environment variable `CASPERJS_EXECUTABLE` set?
if (process.env["CASPERJS_EXECUTABLE"] && fs.existsSync(process.env["CASPERJS_EXECUTABLE"])) {
casperBin = process.env["CASPERJS_EXECUTABLE"];
} else {
//Windows Check
var isWindows = /^win/.test(process.platform),
//NPM Module Path
moduleBinPath = "/casperjs-teamcity/bin/casperjs";
//Loop through local/global node_modules dirs
casper.modulePaths.every(function(path) {
var moduleBin = path + moduleBinPath + (isWindows ? ".exe" : "");
if (fs.existsSync(moduleBin)) {
casperBin = moduleBin;
//essentially a break
return false;
}
return true;
});
}
//Did we find casper in the module Paths?
if (casperBin === null) {
grunt.log.error("CasperJS Binary Not Found, try `npm install`");
return next(true);
}
grunt.verbose.write('Found CasperJS Executable', casperBin);
instantLog('Found CasperJS Executable', casperBin);
//Spawn Casper Process
grunt.util.spawn({
cmd: casperBin,
args: args,
opts: {
cwd: cwd //,
//see CasperJs output live
// stdio: 'inherit'
}
}, function(errorObj, result, code) {
if (code > 0) {
grunt.log.error(result.stdout);
return next(true);
}
grunt.log.write("##teamcity[testSuiteStarted name='" + args[1] + "' timestamp='" + getTeamCityNowDate() + "']\n");
instantLog("##teamcity[testSuiteStarted name='" + args[1] + "' timestamp='" + getTeamCityNowDate() + "']\n");
if (result.stdout) {
grunt.log.write(result.stdout + '\n\n');
instantLog(result.stdout + '\n\n');
}
if (result.stderr) {
grunt.log.write(result.stderr + '\n\n');
instantLog(result.stderr + '\n\n');
}
grunt.log.write("##teamcity[testSuiteFinished name='" + args[1] + "' timestamp='" + getTeamCityNowDate() + "']\n");
instantLog("##teamcity[testSuiteFinished name='" + args[1] + "' timestamp='" + getTeamCityNowDate() + "']\n");
next();
});
}
};
return {
execute: function(src, dest, options, args, next) {
grunt.verbose.write('Preparing casperjs spawn\n');
var spawnOpts = [];
var cwd = options.cwd || process.cwd();
//add verbose flag for printing logs to screen
if (options['log-level'] && !options.verbose) spawnOpts.push('--verbose');
_.forEach(options, function(value, option) {
if (!options.test && casper.testableOptions[option]) {
grunt.log.warn('Option ' + option + ' only available in test mode');
return;
}
if (option) {
switch (option) {
case 'test':
//Test requires specific order logic
break;
case 'xunit_out':
if (typeof options.xunit_out === 'function') {
//src passed as array reference
options.xunit = options.xunit_out(src);
} else {
options.xunit = options.xunit_out;
}
break;
case 'args':
if (args && args.length) spawnOpts.push(args);
value.forEach(function(arg) {
spawnOpts.push(arg);
});
break;
//add engine support outside of phantomJS
case 'engine':
if (casper.supportedEngines.indexOf(options['engine']) !== -1) {
spawnOpts.push('--engine=' + options['engine']);
} else {
grunt.log.warn('Engine ' + options['engine'] + ' not available. [' + casper.supportedEngines.join(',') + ']');
}
break;
default:
var currentOption = '--' + option + '=' + value;
grunt.verbose.write('Adding Option ' + currentOption + '\n');
spawnOpts.push(currentOption);
}
}
});
if (dest) {
if (typeof dest === 'function') {
dest = dest(src);
}
spawnOpts.push('--xunit=' + dest);
}
if (typeof src === 'object') {
src.reverse().filter(function(file) {
if (!grunt.file.exists(file)) {
grunt.log.warn('Source file "' + file + '" not found.');
return false;
}
return true;
}).map(function(file) {
//Make path absolute for SlimerJS
if (!grunt.file.isPathAbsolute(file)) {
file = path.join(cwd, file);
}
spawnOpts.unshift(file);
});
} else {
spawnOpts.unshift(src);
}
if (options.test) {
spawnOpts.unshift('test');
}
//Spawn Child Process
casper.spawn(cwd, spawnOpts, next);
}
};
};