2012-11-02 13:03:09 +08:00
|
|
|
/*
|
|
|
|
* grunt-contrib-jasmine
|
|
|
|
* http://gruntjs.com/
|
|
|
|
*
|
|
|
|
* Licensed under the MIT license.
|
|
|
|
*/
|
|
|
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
module.exports = function(grunt) {
|
|
|
|
|
2012-11-02 13:03:09 +08:00
|
|
|
// node api
|
|
|
|
var fs = require('fs'),
|
2013-01-09 03:28:26 +08:00
|
|
|
path = require('path');
|
2012-11-02 13:03:09 +08:00
|
|
|
|
|
|
|
// npm lib
|
|
|
|
var phantomjs = require('grunt-lib-phantomjs').init(grunt);
|
|
|
|
|
|
|
|
// local lib
|
2013-01-09 03:28:26 +08:00
|
|
|
var jasmine = require('./lib/jasmine').init(grunt);
|
|
|
|
|
|
|
|
var junitTemplate = __dirname + '/jasmine/templates/JUnit.tmpl';
|
2012-11-02 13:03:09 +08:00
|
|
|
|
|
|
|
var status = {
|
|
|
|
specs : 0,
|
|
|
|
failed : 0,
|
|
|
|
passed : 0,
|
|
|
|
total : 0,
|
|
|
|
skipped : 0,
|
|
|
|
duration : 0
|
|
|
|
};
|
|
|
|
|
|
|
|
grunt.registerMultiTask('jasmine', 'Run jasmine specs headlessly through PhantomJS.', function() {
|
2012-11-02 13:03:09 +08:00
|
|
|
|
|
|
|
// Merge task-specific options with these defaults.
|
2012-11-02 13:03:09 +08:00
|
|
|
var options = this.options({
|
|
|
|
timeout : 10000,
|
|
|
|
specs : [],
|
|
|
|
helpers : [],
|
|
|
|
vendor : [],
|
|
|
|
outfile : '_SpecRunner.html',
|
|
|
|
host : '',
|
2013-01-09 03:28:26 +08:00
|
|
|
template : __dirname + '/jasmine/templates/DefaultRunner.tmpl',
|
2012-11-02 13:03:09 +08:00
|
|
|
templateOptions : {},
|
2013-01-08 07:04:44 +08:00
|
|
|
phantomjs : {},
|
|
|
|
junit: {}
|
2012-11-02 13:03:09 +08:00
|
|
|
});
|
|
|
|
|
2013-01-10 13:14:50 +08:00
|
|
|
if (options.template === 'requirejs') {
|
|
|
|
grunt.log.warn(
|
|
|
|
'The requirejs template is no longer included in grunt-contrib-jasmine core.\n' +
|
|
|
|
'Please see the https://github.com/gruntjs/grunt-contrib-jasmine README for details'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2012-11-02 13:03:09 +08:00
|
|
|
if (grunt.option('debug')) {
|
2012-11-02 13:03:09 +08:00
|
|
|
grunt.log.debug(options);
|
2012-11-02 13:03:09 +08:00
|
|
|
}
|
|
|
|
|
2012-11-02 13:03:09 +08:00
|
|
|
setup(options);
|
|
|
|
|
2013-01-10 13:14:50 +08:00
|
|
|
jasmine.buildSpecrunner(this.filesSrc,options);
|
2012-11-02 13:03:09 +08:00
|
|
|
|
|
|
|
// If we're just building (e.g. for web), skip phantom.
|
|
|
|
if (this.flags.build) return;
|
|
|
|
|
|
|
|
var done = this.async();
|
|
|
|
phantomRunner(options, function(err,status) {
|
|
|
|
if (err) grunt.log.error(err);
|
|
|
|
if (status.failed === 0) grunt.log.ok('0 failures');
|
|
|
|
else grunt.log.error(status.failed + ' failures');
|
|
|
|
teardown(options);
|
|
|
|
done(!err && status.failed === 0);
|
|
|
|
});
|
2012-11-02 13:03:09 +08:00
|
|
|
|
|
|
|
});
|
|
|
|
|
2012-11-02 13:03:09 +08:00
|
|
|
function phantomRunner(options,cb){
|
|
|
|
var file = options.outfile;
|
|
|
|
|
|
|
|
if (options.host) {
|
|
|
|
file = options.host + options.outfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
grunt.verbose.subhead('Testing jasmine specs via phantom').or.writeln('Testing jasmine specs via phantom');
|
|
|
|
|
|
|
|
phantomjs.spawn(file, {
|
|
|
|
failCode : 90,
|
|
|
|
options : options,
|
|
|
|
done : function(err){
|
|
|
|
cb(err,status);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function teardown(options) {
|
|
|
|
if (fs.statSync(options.outfile).isFile()) fs.unlink(options.outfile);
|
2013-01-09 03:28:26 +08:00
|
|
|
jasmine.cleanTemp();
|
2012-11-02 13:03:09 +08:00
|
|
|
|
|
|
|
// Have to explicitly unregister nested wildcards. Need to file a bug for EventEmitter2
|
|
|
|
phantomjs.removeAllListeners('*');
|
|
|
|
phantomjs.removeAllListeners('jasmine.*');
|
|
|
|
phantomjs.removeAllListeners('error.*');
|
|
|
|
phantomjs.removeAllListeners('jasmine.done.*');
|
|
|
|
}
|
|
|
|
|
|
|
|
function setup(options) {
|
|
|
|
var thisRun = {};
|
|
|
|
|
|
|
|
phantomjs.on('fail.timeout',function(){
|
|
|
|
grunt.log.writeln();
|
|
|
|
grunt.warn('PhantomJS timed out, possibly due to an unfinished async spec.', 90);
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('console',console.log.bind(console));
|
|
|
|
phantomjs.on('verbose',grunt.verbose.writeln.bind(grunt.verbose));
|
|
|
|
phantomjs.on('debug', grunt.log.debug.bind(grunt.log, 'phantomjs'));
|
|
|
|
phantomjs.on('write', grunt.log.write.bind(grunt.log));
|
|
|
|
phantomjs.on('writeln', grunt.log.writeln.bind(grunt.log));
|
|
|
|
phantomjs.on('error.onError',function(string, trace){
|
|
|
|
if (trace) {
|
|
|
|
grunt.log.error(string.red + ' at ');
|
|
|
|
trace.forEach(function(line) {
|
|
|
|
var file = line.file.replace(/^file:/,'');
|
|
|
|
var message = grunt.util._('%s:%d %s').sprintf(path.relative('.',file), line.line, line.function);
|
|
|
|
grunt.log.error(message.red);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
grunt.log.error(string.red);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.onAny(function() {
|
|
|
|
var args = [this.event].concat(grunt.util.toArray(arguments));
|
|
|
|
grunt.event.emit.apply(grunt.event, args);
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('jasmine.reportRunnerStarting',function(suites) {
|
|
|
|
grunt.verbose.writeln('Starting...');
|
|
|
|
thisRun.start_time = (new Date()).getTime();
|
|
|
|
thisRun.executed_specs = 0;
|
|
|
|
thisRun.passed_specs = 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('jasmine.reportSpecStarting',function(spec) {
|
|
|
|
thisRun.executed_specs++;
|
|
|
|
grunt.verbose.write(spec.suite.description + ':' + spec.description + '...');
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('jasmine.reportSuiteResults',function(suite){
|
|
|
|
//grunt.verbose.writeln(suite.description + ": " + suite.results.passedCount + " of " + suite.results.totalCount + " passed.");
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('jasmine.reportSpecResults',function(specId, result,summary) {
|
|
|
|
if (result.passed) thisRun.passed_specs++;
|
|
|
|
|
|
|
|
grunt.verbose.writeln(summary.passed ? result.msg.green : result.msg.red);
|
|
|
|
for (var i = 0; i < result.messages.length; i++) {
|
|
|
|
var item = result.messages[i];
|
|
|
|
|
|
|
|
if (item.type === 'log') {
|
|
|
|
grunt.verbose.writeln(item.toString());
|
|
|
|
} else if (item.type === 'expect' && !item.passed_) {
|
|
|
|
grunt.log.writeln(summary.description + ':' + result.msg.red);
|
|
|
|
phantomjs.emit('onError', item.message, item.trace);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
phantomjs.emit( 'jasmine.testDone', result.totalCount, result.passedCount, result.failedCount, result.skipped );
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('jasmine.reportRunnerResults',function(){
|
|
|
|
grunt.verbose.writeln('Runner finished');
|
|
|
|
var dur = (new Date()).getTime() - thisRun.start_time;
|
|
|
|
var failed = thisRun.executed_specs - thisRun.passed_specs;
|
|
|
|
var spec_str = thisRun.executed_specs + (thisRun.executed_specs === 1 ? " spec, " : " specs, ");
|
|
|
|
var fail_str = failed + (failed === 1 ? " failure in " : " failures in ");
|
|
|
|
grunt.log.writeln(spec_str + fail_str + (dur/1000) + "s.");
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('jasmine.testDone',function(totalAssertions, passedAssertions, failedAssertions, skippedAssertions){
|
|
|
|
status.specs++;
|
|
|
|
status.failed += failedAssertions;
|
|
|
|
status.passed += passedAssertions;
|
|
|
|
status.total += totalAssertions;
|
|
|
|
status.skipped += skippedAssertions;
|
|
|
|
});
|
|
|
|
|
2013-01-08 07:04:44 +08:00
|
|
|
phantomjs.on('jasmine.reportJUnitResults',function(junitData){
|
|
|
|
if (options.junit && options.junit.path) {
|
2013-01-09 03:28:26 +08:00
|
|
|
var template = grunt.file.read(junitTemplate);
|
2013-01-08 21:09:05 +08:00
|
|
|
if (options.junit.consolidate) {
|
2013-01-09 03:28:26 +08:00
|
|
|
grunt.util._(junitData.consolidatedSuites).each(function(suites){
|
|
|
|
var xmlFile = path.join(options.junit.path, 'TEST-' + suites[0].name.replace(/[^\w]/g, '') + '.xml');
|
|
|
|
grunt.file.write(xmlFile, grunt.util._.template(template, { testsuites: suites}));
|
|
|
|
});
|
2013-01-08 21:09:05 +08:00
|
|
|
} else {
|
2013-01-09 03:28:26 +08:00
|
|
|
junitData.suites.forEach(function(suiteData){
|
|
|
|
var xmlFile = path.join(options.junit.path, 'TEST-' + suiteData.name.replace(/[^\w]/g, '') + '.xml');
|
|
|
|
grunt.file.write(xmlFile, grunt.util._.template(template, { testsuites: [suiteData] }));
|
|
|
|
});
|
2013-01-08 21:09:05 +08:00
|
|
|
}
|
2013-01-08 07:04:44 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2012-11-02 13:03:09 +08:00
|
|
|
phantomjs.on('jasmine.done',function(elapsed){
|
|
|
|
phantomjs.halt();
|
|
|
|
status.duration = elapsed;
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('jasmine.done.PhantomReporter',function(){
|
|
|
|
phantomjs.emit('jasmine.done');
|
|
|
|
});
|
|
|
|
|
|
|
|
phantomjs.on('jasmine.done_fail',function(url){
|
|
|
|
grunt.log.error();
|
|
|
|
grunt.warn('PhantomJS unable to load "' + url + '" URI.', 90);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-01-08 07:04:44 +08:00
|
|
|
};
|