diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..6b4c1a9 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,14 @@ +{ + "curly": true, + "eqeqeq": true, + "immed": true, + "latedef": true, + "newcap": true, + "noarg": true, + "sub": true, + "undef": true, + "boss": true, + "eqnull": true, + "node": true, + "es5": true +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..49b6000 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog + + +## v 0.2.0 + +* Update to Grunt `0.4.0`. +* Update to CucumberJS `0.3.0`. diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..dafb8fc --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,25 @@ +module.exports = function (grunt) { + 'use strict'; + + grunt.initConfig({ + jshint: { + files: ['grunt.js', 'tasks/*.js'], + options: { + jshintrc: '.jshintrc' + } + }, + cucumberjs: { + files: 'features', + options: { + steps: 'features/step_definitions', + format: 'pretty' + } + } + }); + + grunt.loadNpmTasks('grunt-contrib-jshint'); + + grunt.loadTasks('tasks'); + + grunt.registerTask('default', ['jshint', 'cucumberjs']); +}; diff --git a/README.md b/README.md index a9bd00f..7983bf0 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,88 @@ -# grunt-cucumber-js +# grunt-cuccumber-js + +> Run all you your cucumber features through Grunt. + +**Warning:** This task requires a Grunt version of at least `0.4.0`. -A grunt.js task to run your cucumber.js feature suite. ## Getting Started -Install this grunt plugin next to your project's grunt.js gruntfile with: `npm install grunt-cucumber` +If you haven't used [Grunt](http://gruntjs.com/) before, be sure to +check out the [Getting Started](http://gruntjs.com/getting-started) +guide, as it explains how to create a +[Gruntfile](http://gruntjs.com/sample-gruntfile) as well as install +and use Grunt plugins. Once you're familiar with that process, you may +install this plugin with this command: + +```shell +$ npm install grunt-cucumber --save-dev +``` +Then add this configuration to your project's `Gruntfile.js`. + +```js +grunt.loadNpmTasks('grunt-cucumber'); +``` + +## Cucumberjs Task +_Run this task with the `grunt cucumberjs` command._ + +### Options + +#### steps +Type: `String` + +Default: `''` + +Require files before executing the features. If this option is not +specified, all *.js and *.coffee files that are siblings or below the +features will be loaded automatically. Automatic loading is disabled +when this option is specified, and all loading becomes explicit. -Then add this line to your project's `grunt.js` gruntfile: +Files under directories named "support" are always loaded first. -```javascript +#### tags +Type: `String` + +Default: `''` + +Only execute the features or scenarios with tags +matching TAG_EXPRESSION. Scenarios inherit tags +declared on the Feature level. The simplest +TAG_EXPRESSION is simply a tag. Example: +`tags: '@dev'` + +When a tag in a tag expression starts with a ~, +this represents boolean NOT. Example: +`tags: '~@dev'` + + A tag expression can have several tags separated +by a comma, which represents logical OR. Example: +`tags: '@dev,@wip'` + +#### format +Type: `String` +Default: `''` + +How to format features (default: progress). +Available formats: +* pretty : prints the feature as is +* progress: prints one character per scenario +* json : prints the feature as JSON +* summary : prints a summary only, after all scenarios were executed + +### Usage Examples + + +#### Basic Use +```js +// Project configuration. grunt.initConfig({ cucumberjs: { - executable: "../path/to/custom/cucumberjs", - features: "path/to/features", - steps: "path/to/step_definitions", - tags: "@dev" + files: 'path/to/features', + options: { + steps: "path/to/step_definitions" + } } }); - -grunt.loadNpmTasks('grunt-cucumber'); - -grunt.registerTask('default', 'cucumberjs'); ``` ## Bugs @@ -28,8 +91,8 @@ Help us squash them by submitting an issue that describes how you encountered it ## Release History -see [CHANGELOG](/s9tpepper/grunt-cucumber-js/blob/master/CHANGELOG). +see [CHANGELOG](CHANGELOG.md). ## License Copyright (c) 2012 "s9tpepper" Omar Gonzalez & contributors. -Licensed under the MIT license. \ No newline at end of file +Licensed under the MIT license. diff --git a/bin/grunt-cucumber b/bin/grunt-cucumber deleted file mode 100644 index 75e638f..0000000 --- a/bin/grunt-cucumber +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('grunt').npmTasks('grunt-cucumber').cli(); diff --git a/features/step_definitions/Testing_steps.js b/features/step_definitions/Testing_steps.js index 9b3b847..a700b64 100644 --- a/features/step_definitions/Testing_steps.js +++ b/features/step_definitions/Testing_steps.js @@ -1,26 +1,26 @@ function Testing_steps() { - var firstNumber; - var secondNumber; - var sum = 0; + var firstNumber; + var secondNumber; + var sum = 0; - this.Given(/^I have the number (\d+) and (\d+)$/, function(arg1, arg2, callback) { - firstNumber = parseInt(arg1); - secondNumber = parseInt(arg2); - callback(); - }); + this.Given(/^I have the number (\d+) and (\d+)$/, function(arg1, arg2, callback) { + firstNumber = parseInt(arg1); + secondNumber = parseInt(arg2); + callback(); + }); - this.When(/^I add them together$/, function(callback) { - sum = firstNumber + secondNumber; - callback(); - }); + this.When(/^I add them together$/, function(callback) { + sum = firstNumber + secondNumber; + callback(); + }); - this.Then(/^I should have (\d+)$/, function(arg1, callback) { - var expectedSum = parseInt(arg1); - if (expectedSum !== sum) { - throw new Error("It doesn't add up! " + arg1 + " !== " + sum); - } - callback(); - }); + this.Then(/^I should have (\d+)$/, function(arg1, callback) { + var expectedSum = parseInt(arg1); + if (expectedSum !== sum) { + throw new Error('It doesn\'t add up! ' + arg1 + ' !== ' + sum); + } + callback(); + }); }; diff --git a/grunt.js b/grunt.js deleted file mode 100644 index d09460d..0000000 --- a/grunt.js +++ /dev/null @@ -1,36 +0,0 @@ -module.exports = function (grunt) { - 'use strict'; - - grunt.initConfig({ - lint: { - all: ['grunt.js', 'tasks/*.js'] - }, - jshint: { - options: { - curly: true, - eqeqeq: true, - immed: true, - latedef: true, - newcap: true, - noarg: true, - sub: true, - undef: true, - boss: true, - eqnull: true, - node: true, - es5: true - }, - globals: {} - }, - cucumberjs: { - executable: "../node_modules/cucumber/lib/cucumber.js", /* Relative to /tasks folder */ - features: "features", - steps: "features/step_definitions" - } - }); - - grunt.loadTasks("tasks"); - - grunt.registerTask('default', 'lint cucumberjs'); - -}; \ No newline at end of file diff --git a/package.json b/package.json index cfba9c4..d19442d 100644 --- a/package.json +++ b/package.json @@ -1,44 +1,43 @@ { - "name" : "grunt-cucumber", - "description" : "Grunt task for running Cucumber.js", - "version" : "0.1.1", - "homepage" : "https://github.com/s9tpepper/grunt-cucumber-js", - "author" : { - "name" : "Omar Gonzalez", - "email" : "s9tpepper@apache.org", - "url" : "http://omar.likesflex.com" - }, - "repository" : { - "type" : "git", - "url" : "git://github.com/s9tpepper/grunt-cucumber-js.git" - }, - "bugs" : { - "url" : "https://github.com/s9tpepper/grunt-cucumber-js/issues" - }, - "licenses" : [ - { - "type" : "MIT", - "url" : "https://github.com/s9tpepper/grunt-cucumber-js/blob/master/LICENSE-MIT" - } - ], - "main" : "grunt.js", - "bin" : "bin/grunt-cucumber", - "engines" : { - "node" : "*" - }, - "scripts" : { - }, - "dependencies" : { - }, - "devDependencies" : { - "grunt" : "~0.3.9", - "cucumber": "~0.2.19" - }, - "keywords" : [ - "gruntplugin", - "grunt", - "plugins", - "builds", - "ci" - ] -} \ No newline at end of file + "name": "grunt-cucumber", + "description": "Grunt task for running Cucumber.js", + "version": "0.2.0", + "homepage": "https://github.com/s9tpepper/grunt-cucumber-js", + "author": { + "name": "Omar Gonzalez", + "email": "s9tpepper@apache.org", + "url": "http://omar.likesflex.com" + }, + "repository": { + "type": "git", + "url": "git://github.com/s9tpepper/grunt-cucumber-js.git" + }, + "bugs": { + "url": "https://github.com/s9tpepper/grunt-cucumber-js/issues" + }, + "licenses": [ + { + "type": "MIT", + "url": "https://github.com/s9tpepper/grunt-cucumber-js/blob/master/LICENSE-MIT" + } + ], + "main": "Gruntfile.js", + "engines": { + "node": "*" + }, + "scripts": {}, + "dependencies": { + "cucumber": "~0.3.0" + }, + "devDependencies": { + "grunt": "~0.4.0", + "grunt-contrib-jshint": "~0.2.0" + }, + "keywords": [ + "gruntplugin", + "grunt", + "plugins", + "builds", + "ci" + ] +} diff --git a/tasks/cucumber-js-task.js b/tasks/cucumber-js-task.js index fa0ac0b..dd92e72 100644 --- a/tasks/cucumber-js-task.js +++ b/tasks/cucumber-js-task.js @@ -1,52 +1,71 @@ module.exports = function (grunt) { - grunt.registerTask("cucumberjs", "Runs cucumber.js", function () { - - var cucumberPath = grunt.config("cucumberjs.executable") || 'cucumber'; - var Cucumber = require(cucumberPath); - - var features = grunt.config("cucumberjs.features") || 'features'; - var steps = grunt.config("cucumberjs.steps") || 'features/step_definitions'; - var tags = grunt.config("cucumberjs.tags") || '~@Pending'; - - var options = [ 'node', - 'cucumber-js-task.js', - features, - '-r', - steps, - '-t', - tags ]; - - var cli = Cucumber.Cli(options); - - var done = this.async(); - cli.run(function(succeeded) { - var code = succeeded ? 0 : 1; - var exitFunction = function() { - if (code !== 0) { - process.exit(code); - } else { - done(); - } - }; - - // --- exit after waiting for all pending output --- - var waitingIO = false; - process.stdout.on('drain', function() { - if (waitingIO) { - // the kernel buffer is now empty - exitFunction(); - } - }); - if (process.stdout.write("")) { - // no buffer left, exit now: - exitFunction(); - } else { - // write() returned false, kernel buffer is not empty yet... - waitingIO = true; - } - }); - - }); + var cucumber = require('cucumber'); + var _ = grunt.util._; + // The Cucumber Task + grunt.registerMultiTask('cucumberjs', 'Runs cucumber.js', function () { + // Make this task async + var done = this.async(); + + // Load all the options + var options = this.options(); + + var steps = options.steps; + var tags = options.tags; + var format = options.format; + + grunt.verbose.writeflags(options, 'Options'); + + var callback = function(succeeded) { + var code = succeeded ? 0 : 1; + var exitFunction = function() { + done(code); + }; + + // --- exit after waiting for all pending output --- + var waitingIO = false; + process.stdout.on('drain', function() { + if (waitingIO) { + // the kernel buffer is now empty + exitFunction(); + } + }); + if (process.stdout.write("")) { + // no buffer left, exit now: + exitFunction(); + } else { + // write() returned false, kernel buffer is not empty yet... + waitingIO = true; + } + }; + + var files = this.filesSrc; + + + var execOptions = ['node', 'node_modules/.bin/cucumber-js']; + + if (! _.isEmpty(files)) { + execOptions = execOptions.concat(files); + } + + if (! _.isEmpty(steps)) { + execOptions.push('-r'); + execOptions.push(steps); + } + + if (! _.isEmpty(tags)) { + execOptions.push('-t'); + execOptions.push(tags); + } + + if (! _.isEmpty(format)) { + execOptions.push('-f'); + execOptions.push(format); + } + + grunt.verbose.writeln('Exec Options: ' + execOptions.join(' ')); + cucumber.Cli(execOptions).run(callback); + + }); };