diff --git a/.jshintrc b/.jshintrc
index 6b4c1a9..68d4c0a 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -1,5 +1,5 @@
{
- "curly": true,
+ "curly": false,
"eqeqeq": true,
"immed": true,
"latedef": true,
diff --git a/CHANGELOG b/CHANGELOG
index 6e20b16..688bb3d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,4 +1,11 @@
-v0.2.0:
+v0.3.0:
+ date: 2013-01-08
+ changes:
+ - Added JUnit xml output (via Kelvin Luck @vitch)
+ - Passing console.log from browser to verbose grunt logging
+ - Support for templates as separate node modules
+ - Removed internal requirejs template (see grunt-template-jasmine-requirejs)
+v0.2.0:
date: 2012-12-03
changes:
- Generalized requirejs template config
diff --git a/Gruntfile.js b/Gruntfile.js
index 60776c4..1c8dbb3 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -32,7 +32,10 @@ module.exports = function(grunt) {
jasmine: {
options: {
specs: 'test/fixtures/pivotal/spec/*Spec.js',
- helpers: 'test/fixtures/pivotal/spec/*Helper.js'
+ helpers: 'test/fixtures/pivotal/spec/*Helper.js',
+ junit: {
+ path: 'junit'
+ }
},
pivotal: {
src: 'test/fixtures/pivotal/src/**/*.js'
@@ -40,20 +43,10 @@ module.exports = function(grunt) {
customTemplate: {
src: 'test/fixtures/pivotal/src/**/*.js',
options: {
- template: 'test/fixtures/customTemplate/custom.tmpl'
- }
- },
- requirejs: {
- src: 'test/fixtures/requirejs/src/**/*.js',
- options: {
- specs: 'test/fixtures/requirejs/spec/*Spec.js',
- helpers: 'test/fixtures/requirejs/spec/*Helper.js',
- host: 'http://127.0.0.1:<%= connect.test.port %>/',
- template: 'requirejs',
- templateOptions: {
- requireConfig : {
- baseUrl: './test/fixtures/requirejs/src/'
- }
+ template: 'test/fixtures/customTemplate/custom.tmpl',
+ junit: {
+ path: 'junit/customTemplate',
+ consolidate: true
}
}
}
@@ -73,6 +66,6 @@ module.exports = function(grunt) {
grunt.registerTask('watch-test', ['connect', 'watch']);
- grunt.registerTask('test', ['jasmine:pivotal', 'jasmine:customTemplate', 'connect', 'jasmine:requirejs', 'nodeunit']);
- grunt.registerTask('default', ['jshint', 'test', 'build-contrib']);
+ grunt.registerTask('test', ['jshint', 'jasmine:pivotal', 'jasmine:customTemplate', 'nodeunit']);
+ grunt.registerTask('default', ['test', 'build-contrib']);
};
diff --git a/README.md b/README.md
index 9a66d81..9a2cb1a 100644
--- a/README.md
+++ b/README.md
@@ -31,11 +31,11 @@ Run your tests on your local filesystem or via a server task like [grunt-contrib
#### AMD Support
-Includes a SpecRunner template customized for use with AMD modules and requirejs.
+Supports AMD tests via the [grunt-template-jasmine-requirejs](https://github.com/jsoverson/grunt-template-jasmine-requirejs) module
#### Customize your SpecRunner with your own template
-Supply your own underscore template to automatically build your SpecRunner custom to your use.
+Supply your templates that will be used to automatically build the SpecRunner.
#### Example application usage
@@ -71,8 +71,20 @@ Type: `String|Array`
Type: `String`
Default: `_SpecRunner.html`
-This is the auto-generated specfile that phantomjs will use to run your tests. This is automatically deleted upon normal
-runs
+This is the auto-generated specfile that phantomjs will use to run your tests.
+This is automatically deleted upon normal runs
+
+#### options.junit.path
+Type: `String`
+Default: undefined
+
+Path to output JUnit xml
+
+#### options.junit.consolidate
+Type: `Boolean`
+Default: `false`
+
+Consolidate the JUnit XML so that there is one file per top level suite.
#### options.host
Type: `String`
@@ -95,13 +107,15 @@ host : 'http://127.0.0.1:<%= connect.port %>/'
Not defining a host will mean your specs will be run from the local filesystem.
#### options.template
-Type: `String`
-Default: `default`
-Options: `default`, `requirejs`, `yourcustomtemplate.tmpl`
+Type: `String` `Object`
+Default: undefined
-Specify a custom template to use when generating your Spec Runner. Templates are parsed as underscore templates and provided
+Specify a custom template used to generate your Spec Runner. Templates are parsed as underscore templates and provided
the expanded list of files needed to build a specrunner.
+You can specify an object with a `process` method that will be called as a template function.
+See the [Template API Documentation](needs-wiki-link) for more details.
+
#### options.templateOptions
Type: `Object`
Default: `{}`
@@ -124,32 +138,6 @@ watch: {
}
```
-### Template Options
-
-#### Default template
-
-No specific options are expected or used.
-
-#### RequireJS template
-
-##### templateOptions.requirejs
-Type: `String`
-
-The path to requirejs if you need to specify an alternate version.
-
-##### templateOptions.loaderPlugin
-Type: `String`
-
-The loader plugin to prefix all loaded `src` files. This is useful for processing
-your specs through the likes of CoffeeScript or TypeScript plugins. Keep in mind
-you will need to specify the path to the plugin in the require config.
-
-##### templateOptions.requireConfig
-Type: `Object`
-
-This object is `JSON.stringify()`-ed into the template and passed into `require.config()`
-
-
#### Basic Use
@@ -193,57 +181,12 @@ grunt.initConfig({
#### Sample RequireJS usage
-```js
-// Example configuration
-grunt.initConfig({
- connect: {
- test : {
- port : 8000
- }
- }
- jasmine: {
- requirejs: {
- src: 'src/**/*.js',
- options: {
- specs: 'spec/*Spec.js',
- helpers: 'spec/*Helper.js',
- host: 'http://127.0.0.1:8000/',
- template: 'requirejs',
- templateOptions: {
- requireConfig: {
- baseUrl: 'src/'
- }
- }
- }
- }
- }
-}
-```
-*Note* the usage of the 'connect' task configuration. You will need to use a task like
-[grunt-contrib-connect][] if you need to test your tasks on a running server.
-
-[grunt-contrib-connect]: https://github.com/gruntjs/grunt-contrib-connect
-
-#### RequireJS notes
-
-If you end up using the requirejs template, it's worth looking at the
-[RequireJS template source](https://github.com/gruntjs/grunt-contrib-jasmine/blob/master/tasks/jasmine/templates/RequireJSRunner.tmpl)
-in order to familiarize yourself with how it loads your files. The load process essentially
-consists of a series of nested `require` blocks, incrementally loading your source and specs:
-
-```js
-require([*YOUR SOURCE*], function() {
- require([*YOUR SPECS*], function() {
- require([*GRUNT-CONTRIB-JASMINE FILES*], function() {
- // at this point your tests are already running.
- }
- }
-}
-```
+Please see the [grunt-template-jasmine-requirejs](https://github.com/jsoverson/grunt-template-jasmine-requirejs)
## Release History
+ * 2013-01-07 v0.3.0 Added JUnit xml output (via Kelvin Luck @vitch) Passing console.log from browser to verbose grunt logging Support for templates as separate node modules Removed internal requirejs template (see grunt-template-jasmine-requirejs)
* 2012-12-02 v0.2.0 Generalized requirejs template config Added loader plugin Tests for templates Updated jasmine to 1.3.0
* 2012-11-23 v0.1.2 Updated for new grunt/grunt-contrib apis
* 2012-11-06 v0.1.1 Fixed race condition in requirejs template
@@ -253,4 +196,4 @@ require([*YOUR SOURCE*], function() {
Task submitted by [Jarrod Overson](http://jarrodoverson.com)
-*This file was generated on Thu Dec 13 2012 09:07:25.*
+*This file was generated on Tue Jan 08 2013 11:28:08.*
diff --git a/docs/jasmine-examples.md b/docs/jasmine-examples.md
index 00868cf..5aeb5c3 100644
--- a/docs/jasmine-examples.md
+++ b/docs/jasmine-examples.md
@@ -41,50 +41,4 @@ grunt.initConfig({
## Sample RequireJS usage
-```js
-// Example configuration
-grunt.initConfig({
- connect: {
- test : {
- port : 8000
- }
- }
- jasmine: {
- requirejs: {
- src: 'src/**/*.js',
- options: {
- specs: 'spec/*Spec.js',
- helpers: 'spec/*Helper.js',
- host: 'http://127.0.0.1:8000/',
- template: 'requirejs',
- templateOptions: {
- requireConfig: {
- baseUrl: 'src/'
- }
- }
- }
- }
- }
-}
-```
-*Note* the usage of the 'connect' task configuration. You will need to use a task like
-[grunt-contrib-connect][] if you need to test your tasks on a running server.
-
-[grunt-contrib-connect]: https://github.com/gruntjs/grunt-contrib-connect
-
-## RequireJS notes
-
-If you end up using the requirejs template, it's worth looking at the
-[RequireJS template source](https://github.com/gruntjs/grunt-contrib-jasmine/blob/master/tasks/jasmine/templates/RequireJSRunner.tmpl)
-in order to familiarize yourself with how it loads your files. The load process essentially
-consists of a series of nested `require` blocks, incrementally loading your source and specs:
-
-```js
-require([*YOUR SOURCE*], function() {
- require([*YOUR SPECS*], function() {
- require([*GRUNT-CONTRIB-JASMINE FILES*], function() {
- // at this point your tests are already running.
- }
- }
-}
-```
+Please see the [grunt-template-jasmine-requirejs](https://github.com/jsoverson/grunt-template-jasmine-requirejs)
diff --git a/docs/jasmine-options.md b/docs/jasmine-options.md
index f7fc016..1686402 100644
--- a/docs/jasmine-options.md
+++ b/docs/jasmine-options.md
@@ -25,8 +25,20 @@ Type: `String|Array`
Type: `String`
Default: `_SpecRunner.html`
-This is the auto-generated specfile that phantomjs will use to run your tests. This is automatically deleted upon normal
-runs
+This is the auto-generated specfile that phantomjs will use to run your tests.
+This is automatically deleted upon normal runs
+
+## options.junit.path
+Type: `String`
+Default: undefined
+
+Path to output JUnit xml
+
+## options.junit.consolidate
+Type: `Boolean`
+Default: `false`
+
+Consolidate the JUnit XML so that there is one file per top level suite.
## options.host
Type: `String`
@@ -49,27 +61,21 @@ host : 'http://127.0.0.1:<%= connect.port %>/'
Not defining a host will mean your specs will be run from the local filesystem.
## options.template
-Type: `String`
-Default: `default`
-Options: `default`, `requirejs`, `yourcustomtemplate.tmpl`
+Type: `String` `Object`
+Default: undefined
-Specify a custom template to use when generating your Spec Runner. Templates are parsed as underscore templates and provided
+Specify a custom template used to generate your Spec Runner. Templates are parsed as underscore templates and provided
the expanded list of files needed to build a specrunner.
+You can specify an object with a `process` method that will be called as a template function.
+See the [Template API Documentation](needs-wiki-link) for more details.
+
## options.templateOptions
Type: `Object`
Default: `{}`
These options will be passed to your template as an 'options' hash so that you can provide settings to your template.
-## options.junit
-Type: `Object`
-Default: `{}`
-
-Set `options.junit.path` to generate JUnit compatible XML from the task (for use in a CI system such as Jenkins).
-
-Set `options.junit.consolidate` to consolidate the generated XML files so that there is one file per top level suite.
-
# Flags
Name: `build`
@@ -85,29 +91,3 @@ watch: {
}
}
```
-
-# Template Options
-
-## Default template
-
-No specific options are expected or used.
-
-## RequireJS template
-
-### templateOptions.requirejs
-Type: `String`
-
-The path to requirejs if you need to specify an alternate version.
-
-### templateOptions.loaderPlugin
-Type: `String`
-
-The loader plugin to prefix all loaded `src` files. This is useful for processing
-your specs through the likes of CoffeeScript or TypeScript plugins. Keep in mind
-you will need to specify the path to the plugin in the require config.
-
-### templateOptions.requireConfig
-Type: `Object`
-
-This object is `JSON.stringify()`-ed into the template and passed into `require.config()`
-
diff --git a/docs/jasmine-overview.md b/docs/jasmine-overview.md
index 184783a..90164d3 100644
--- a/docs/jasmine-overview.md
+++ b/docs/jasmine-overview.md
@@ -12,11 +12,11 @@ Run your tests on your local filesystem or via a server task like [grunt-contrib
## AMD Support
-Includes a SpecRunner template customized for use with AMD modules and requirejs.
+Supports AMD tests via the [grunt-template-jasmine-requirejs](https://github.com/jsoverson/grunt-template-jasmine-requirejs) module
## Customize your SpecRunner with your own template
-Supply your own underscore template to automatically build your SpecRunner custom to your use.
+Supply your templates that will be used to automatically build the SpecRunner.
## Example application usage
diff --git a/package.json b/package.json
index 42402a6..99d4ba3 100644
--- a/package.json
+++ b/package.json
@@ -29,7 +29,8 @@
},
"dependencies": {
"grunt-lib-phantomjs": "~0.1.0",
- "grunt": "~0.4.0"
+ "grunt": "~0.4.0",
+ "rimraf": "~2.0.3"
},
"devDependencies": {
"grunt-contrib-internal": "~0.1.1",
diff --git a/tasks/jasmine.js b/tasks/jasmine.js
index 5dfd034..4b7e5a3 100644
--- a/tasks/jasmine.js
+++ b/tasks/jasmine.js
@@ -5,21 +5,21 @@
* Licensed under the MIT license.
*/
-/*jshint node:true, curly:false*/
-
'use strict';
module.exports = function(grunt) {
// node api
var fs = require('fs'),
- path = require('path');
+ path = require('path');
// npm lib
var phantomjs = require('grunt-lib-phantomjs').init(grunt);
// local lib
- var jasmine = require('./lib/jasmine');
+ var jasmine = require('./lib/jasmine').init(grunt);
+
+ var junitTemplate = __dirname + '/jasmine/templates/JUnit.tmpl';
var status = {
specs : 0,
@@ -30,18 +30,6 @@ module.exports = function(grunt) {
duration : 0
};
- var runners = {
- default : __dirname + '/jasmine/templates/DefaultRunner.tmpl',
- requirejs : __dirname + '/jasmine/templates/RequireJSRunner.tmpl',
- junit : __dirname + '/jasmine/templates/JUnit.tmpl'
- };
-
- var runnerOptions = {
- requirejs : {
- requirejs : jasmine.getRelativeFileList(__dirname + '/../vendor/require-2.1.1.js')[0]
- }
- };
-
grunt.registerMultiTask('jasmine', 'Run jasmine specs headlessly through PhantomJS.', function() {
// Merge task-specific options with these defaults.
@@ -52,15 +40,12 @@ module.exports = function(grunt) {
vendor : [],
outfile : '_SpecRunner.html',
host : '',
- template: 'default',
+ template : __dirname + '/jasmine/templates/DefaultRunner.tmpl',
templateOptions : {},
phantomjs : {},
junit: {}
});
- grunt.util._.defaults(options.templateOptions, runnerOptions[options.template] || {});
- if (!options.template.match(/\.tmpl$/)) options.template = runners[options.template];
-
if (grunt.option('debug')) {
grunt.log.debug(options);
}
@@ -84,7 +69,6 @@ module.exports = function(grunt) {
});
-
function phantomRunner(options,cb){
var file = options.outfile;
@@ -101,11 +85,11 @@ module.exports = function(grunt) {
cb(err,status);
}
});
-
}
function teardown(options) {
if (fs.statSync(options.outfile).isFile()) fs.unlink(options.outfile);
+ jasmine.cleanTemp();
// Have to explicitly unregister nested wildcards. Need to file a bug for EventEmitter2
phantomjs.removeAllListeners('*');
@@ -145,16 +129,6 @@ module.exports = function(grunt) {
grunt.event.emit.apply(grunt.event, args);
});
- // Not used?
-// phantomjs.on('jasmine.writeFile',function(type,filename, xml){
-// var dir = options[type] && options[type].output;
-// if (dir) {
-// grunt.file.mkdir(dir);
-// grunt.file.write(path.join(dir, filename), xml);
-// }
-// });
-
-
phantomjs.on('jasmine.reportRunnerStarting',function(suites) {
grunt.verbose.writeln('Starting...');
thisRun.start_time = (new Date()).getTime();
@@ -208,40 +182,17 @@ module.exports = function(grunt) {
phantomjs.on('jasmine.reportJUnitResults',function(junitData){
if (options.junit && options.junit.path) {
-
+ var template = grunt.file.read(junitTemplate);
if (options.junit.consolidate) {
-
- grunt.util._(junitData.consolidatedSuites).each(
- function(suites)
- {
- grunt.file.copy(runners.junit, path.join(options.junit.path, 'TEST-' + suites[0].name.replace(/[^\w]/g, '') + '.xml'), {
- process: function(src) {
- return grunt.util._.template(
- src,
- {
- testsuites: suites
- }
- );
- }
- });
- }
- );
+ 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}));
+ });
} else {
- junitData.suites.forEach(
- function(suiteData)
- {
- grunt.file.copy(runners.junit, path.join(options.junit.path, 'TEST-' + suiteData.name.replace(/[^\w]/g, '') + '.xml'), {
- process: function(src) {
- return grunt.util._.template(
- src,
- {
- testsuites: [suiteData]
- }
- );
- }
- });
- }
- );
+ 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] }));
+ });
}
}
});
diff --git a/tasks/jasmine/reporters/JUnitDataReporter.js b/tasks/jasmine/reporters/JUnitDataReporter.js
deleted file mode 100644
index 8ca899a..0000000
--- a/tasks/jasmine/reporters/JUnitDataReporter.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/*global jasmine */
-(function()
-{
- 'use strict';
-
- function getNestedSuiteName(suite)
- {
- var names = [];
- while (suite) {
- names.unshift(suite.description);
- suite = suite.parentSuite;
- }
- return names.join(' ');
- }
-
- function getTopLevelSuiteId(suite)
- {
- var id;
- while (suite) {
- id = suite.id;
- suite = suite.parentSuite;
- }
- return id;
- }
-
- jasmine.JUnitDataReporter = function()
- {
-
- };
-
- jasmine.JUnitDataReporter.prototype = {
- reportRunnerStarting: function(runner) {
- },
- reportRunnerResults: function(runner) {
- var suitesById = {},
- suites = runner.suites().map(
- function(suite)
- {
- var failures = 0,
- data = {
- topLevelSuiteId: getTopLevelSuiteId(suite),
- name: getNestedSuiteName(suite),
- time: suite.duration / 1000,
- timestamp: suite.timestamp,
- tests: suite.specs().length,
- errors: 0, // TODO: These exist in the JUnit XML but not sure how they map to jasmine things
- testcases: suite.specs().map(
- function(spec)
- {
- var failureMessages = [];
- if (spec.results().failedCount) {
- failures ++;
- spec.results().items_.forEach(
- function(expectation)
- {
- if (!expectation.passed()) {
- failureMessages.push(expectation.message);
- }
- }
- );
- }
- return {
- assertions: spec.results().items_.length,
- className: getNestedSuiteName(spec.suite),
- name: spec.description,
- time: spec.duration / 1000,
- failureMessages: failureMessages
- };
- }
- )
- };
- data.failures = failures;
- suitesById[suite.id] = data;
- return data;
- }
- );
- console.log('Suites:', suites);
- },
- reportSuiteResults: function(suite) {
- suite.timestamp = new Date();
- suite.duration = suite.timestamp.getTime() - suite.specs()[0].startTime;
- },
- reportSpecStarting: function(spec) {
- spec.startTime = (new Date()).getTime();
- },
- reportSpecResults: function(spec) {
- spec.duration = (new Date()).getTime() - spec.startTime;
- },
- log: function(str) {
- console.log(str);
- }
- };
-
-}());
\ No newline at end of file
diff --git a/tasks/jasmine/reporters/JUnitReporter.js b/tasks/jasmine/reporters/JUnitReporter.js
deleted file mode 100644
index b8703e5..0000000
--- a/tasks/jasmine/reporters/JUnitReporter.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/* Based off of https://github.com/larrymyers/jasmine-reporters/ */
-/*global phantom:false, jasmine:false*/
-
-// Unused right now. Logic needs to be brought onto the grunt side, not on the phantom side
-
-(function() {
- "use strict";
-
- function elapsed(startTime, endTime) {
- return (endTime - startTime)/1000;
- }
-
- function ISODateString(d) {
- function pad(n) { return n < 10 ? '0'+n : n; }
-
- return d.getFullYear() + '-' +
- pad(d.getMonth()+1) + '-' +
- pad(d.getDate()) + 'T' +
- pad(d.getHours()) + ':' +
- pad(d.getMinutes()) + ':' +
- pad(d.getSeconds());
- }
-
- function trim(str) {
- return str.replace(/^\s+/, "" ).replace(/\s+$/, "" );
- }
-
- function escapeInvalidXmlChars(str) {
- return str.replace(/\&/g, "&")
- .replace(//g, ">")
- .replace(/\"/g, """)
- .replace(/\'/g, "'");
- }
-
- /**
- * Generates JUnit XML for the given spec run.
- * Allows the test results to be used in java based CI
- * systems like CruiseControl and Hudson.
- *
- * @param {string} savePath where to save the files
- * @param {boolean} consolidate whether to save nested describes within the
- * same file as their parent; default: true
- * @param {boolean} useDotNotation whether to separate suite names with
- * dots rather than spaces (ie "Class.init" not
- * "Class init"); default: true
- */
- function JUnitXmlReporter(savePath, consolidate, useDotNotation) {
- this.savePath = savePath || '';
- this.consolidate = typeof consolidate === 'undefined' ? true : consolidate;
- this.useDotNotation = typeof useDotNotation === 'undefined' ? true : useDotNotation;
- }
-
- JUnitXmlReporter.finished_at = null; // will be updated after all files have been written
-
- JUnitXmlReporter.prototype = {
- reportSpecStarting: function(spec) {
- spec.startTime = new Date();
-
- if (!spec.suite.startTime) {
- spec.suite.startTime = spec.startTime;
- }
- },
-
- reportSpecResults: function(spec) {
- var results = spec.results();
- spec.didFail = !results.passed();
- spec.duration = elapsed(spec.startTime, new Date());
- spec.output = '