Permalink
Browse files

Merge pull request #19 from donedotcom/cuke-runner-rc

Cuke runner rc
  • Loading branch information...
2 parents 7f57fa2 + 477b3e8 commit ac59608183a13108c7b222c6218a822212e89de2 @indexzero indexzero committed Jan 3, 2012
View
235 bin/kyuri
@@ -1,156 +1,129 @@
#!/usr/bin/env node
var path = require('path'),
- sys = require('sys'),
fs = require('fs'),
events = require('events');
-//
-// Attempt to load Coffee-Script. If it's not available, continue on our
-// merry way, if it is available, set it up so we can include `*.coffee`
-// scripts and start searching for them.
-//
-var fileExt, specFileExt;
-
-try {
- var coffee = require('coffee-script');
- require.registerExtension('.coffee', function (content) { return coffee.compile(content) });
- stepExt = /\.(js|coffee)$/;
-} catch (_) {
- fileExt = /\.js$/;
-}
-
featureFileExt = /\.(feature)$/;
+stepsDirs = ['steps', 'step_definitions'];
+envDirs = ['support'];
var inspect = require('eyes').inspector({
stream: null,
styles: { string: 'grey', regexp: 'grey' }
});
-require.paths.unshift(path.join(__dirname, '..', 'lib'));
-
var kyuri = require('kyuri');
var help = [
- "usage: kyuri [FILE, ...] [options]",
- "",
- "options:",
- // Options compliant from 'cucumber --help'
- " --i18n LANG List keywords for in a particular language",
- " Run with \"--i18n help\" to see all languages",
- " -h, --help You're staring at it",
-
- // Options specific to Kyuri
- " --server Run the Kyuri web service. Default to port 9000",
- " --port Port to run server on",
-
+ "usage: kyuri [FILE, ...]"
].join('\n');
-/* Lets be compliant with Cucumber since this is essentially a pure javascript runner + some javascript options foo?
- (i.e. lets generate .coffee vs. .js step definitions :])
-
-
- -r, --require LIBRARY|DIR Require files before executing the features. If this
- option is not specified, all *.rb files that are
- siblings or below the features will be loaded auto-
- matically. Automatic loading is disabled when this
- option is specified, and all loading becomes explicit.
- Files under directories named "support" are always
- loaded first.
- This option can be specified multiple times.
- --i18n LANG List keywords for in a particular language
- Run with "--i18n help" to see all languages
- -f, --format FORMAT How to format features (Default: pretty). Available formats:
- debug : For developing formatters - prints the calls made to the listeners.
- html : Generates a nice looking HTML report.
- json : Prints the feature as JSON
- json_pretty : Prints the feature as pretty JSON
- junit : Generates a report similar to Ant+JUnit.
- pdf : Generates a PDF report. You need to have the
- prawn gem installed. Will pick up logo from
- features/support/logo.png or
- features/support/logo.jpg if present.
- pretty : Prints the feature as is - in colours.
- progress : Prints one character per scenario.
- rerun : Prints failing files with line numbers.
- stepdefs : Prints All step definitions with their locations. Same as
- the usage formatter, except that steps are not printed.
- tag_cloud : Prints a tag cloud of tag usage.
- usage : Prints where step definitions are used.
- The slowest step definitions (with duration) are
- listed first. If --dry-run is used the duration
- is not shown, and step definitions are sorted by
- filename instead.
- Use --format rerun --out features.txt to write out failing
- features. You can rerun them with cucumber @rerun.txt.
- FORMAT can also be the fully qualified class name of
- your own custom formatter. If the class isn't loaded,
- Cucumber will attempt to require a file with a relative
- file name that is the underscore name of the class name.
- Example: --format Foo::BarZap -> Cucumber will look for
- foo/bar_zap.rb. You can place the file with this relative
- path underneath your features/support directory or anywhere
- on Ruby's LOAD_PATH, for example in a Ruby gem.
- -o, --out [FILE|DIR] Write output to a file/directory instead of STDOUT. This option
- applies to the previously specified --format, or the
- default format if no format is specified. Check the specific
- formatter's docs to see whether to pass a file or a dir.
- -t, --tags TAG_EXPRESSION 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. The --tags option can be specified
- several times, and this represents logical AND. Example: --tags @foo,~@bar --tags @zap.
- This represents the boolean expression (@foo || !@bar) && @zap.
-
- Beware that if you want to use several negative tags to exclude several tags
- you have to use logical AND: --tags ~@fixme --tags @buggy.
-
- Positive tags can be given a threshold to limit the number of occurrences.
- Example: --tags @qa:3 will fail if there are more than 3 occurrences of the @qa tag.
- This can be practical if you are practicing Kanban or CONWIP.
- -n, --name NAME Only execute the feature elements which match part of the given name.
- If this option is given more than once, it will match against all the
- given names.
- -e, --exclude PATTERN Don't run feature files or require ruby files matching PATTERN
- -p, --profile PROFILE Pull commandline arguments from cucumber.yml which can be defined as
- strings or arrays. When a 'default' profile is defined and no profile
- is specified it is always used. (Unless disabled, see -P below.)
- When feature files are defined in a profile and on the command line
- then only the ones from the command line are used.
- -P, --no-profile Disables all profile loading to avoid using the 'default' profile.
- -c, --[no-]color Whether or not to use ANSI color in the output. Cucumber decides
- based on your platform and the output destination if not specified.
- -d, --dry-run Invokes formatters without executing the steps.
- This also omits the loading of your support/env.rb file if it exists.
- Implies --no-snippets.
- -a, --autoformat DIR Reformats (pretty prints) feature files and write them to DIRECTORY.
- Be careful if you choose to overwrite the originals.
- Implies --dry-run --formatter pretty.
- -m, --no-multiline Don't print multiline strings and tables under steps.
- -s, --no-source Don't print the file and line of the step definition with the steps.
- -i, --no-snippets Don't print snippets for pending steps.
- -q, --quiet Alias for --no-snippets --no-source.
- -b, --backtrace Show full backtrace for all errors.
- -S, --strict Fail if there are any undefined steps.
- -w, --wip Fail if there are any passing scenarios.
- -v, --verbose Show the files and features loaded.
- -g, --guess Guess best match for Ambiguous steps.
- -x, --expand Expand Scenario Outline Tables in output.
- --drb Run features against a DRb server. (i.e. with the spork gem)
- --port PORT Specify DRb port. Ignored without --drb
- --version Show version.
- -h, --help You're looking at it.
-
+var root = process.cwd();
+
+/**
+ Load .js files found in the directory or subdirectories of the feature files,
+ adding exports to the steps array (if any).
*/
+var _loadJavascripts = function (directory, steps) {
+ if (!directory.match(/^\//)) {
+ directory = path.join(root, directory);
+ }
+
+ if(path.existsSync(directory)) {
+ var files = fs.readdirSync(directory);
+ files.forEach(function (file) {
+ var fullPath = path.join(directory, file),
+ stats = fs.statSync(fullPath),
+ exported;
+
+ if (stats.isDirectory()) {
+ _loadJavascripts(fullPath, steps);
+ } else {
+ if (file.match(/\.js$/)) {
+ // Add root to all relative paths
+ if (!fullPath.match(/^\//)) {
+ fullPath = path.join(root, fullPath);
+ }
+ exported = require(fullPath);
+ if (exported && exported.forEach && steps) {
+ exported.forEach(function (obj) {
+ steps.push(obj); // Pass-by-reference array must be modified in place
+ })
+ }
+ }
+ }
+ });
+ }
+};
// Get rid of process runner
// ('node' in most cases)
var arg, args = [], argv = process.argv.slice(2);
-// Current directory index,
-// and path of test folder.
-var root, testFolder;
+kyuri.runner = kyuri.runners.cucumber;
+
+var features = [];
+var steps = [];
+var directories = [];
+
+argv.forEach(function (file) {
+ var stat = fs.statSync(file),
+ files;
+
+ if (stat.isDirectory()) {
+ files = fs.readdirSync(file);
+ for (var i = 0; i < files.length; i++) {
+ // Add the path
+ files[i] = path.join(file, files[i]);
+ }
+ } else {
+ files = [file];
+ }
+
+ files.forEach(function (file) {
+ if (file.match(featureFileExt)) {
+ // Load envDirs first and without steps
+ if (directories.indexOf(path.dirname(file)) === (-1)) {
+ directories.push(path.dirname(file));
+ }
+ features.push(kyuri.parse(fs.readFileSync(file).toString()));
+ }
+ });
+});
+
+directories.forEach(function (top) {
+ // Load environments first
+ envDirs.forEach(function (dir) {
+ _loadJavascripts(path.join(top, dir));
+ });
+
+ // Load steps
+ stepsDirs.forEach(function (dir) {
+ _loadJavascripts(path.join(top, dir), steps);
+ });
+});
+
+
+var complete = false;
+
+try {
+ kyuri.runners.cucumber.run(features, steps, function () {
+ complete = true;
+ });
+} catch (err) {
+ console.log('Errors');
+ if (err.stack) {
+ console.log(err.stack);
+ } else {
+ console.log(err);
+ }
+ complete = true;
+}
-sys.puts('Kyuri test runner not currently complete in 0.2.0. In the roadmap for 0.2.1');
+var _waitComplete = function () {
+ if (!complete) {
+ process.nextTick(_waitComplete);
+ }
+};
+_waitComplete();
View
@@ -2,9 +2,12 @@ Feature: Complex Addition
In order to avoid silly mistakes
As a math idiot
I want to be told the sum of two numbers
-
+
+ Background:
+ Given I have a calculator
+
Scenario: Add two numbers
- Given I have entered 50 into the calculator
+ Given I have entered "50" and "75" into the calculator
And I have entered 70 into the calculator
When I press add
Then the result should be 120 on the screen
@@ -20,7 +23,6 @@ Feature: Complex Addition
| number1 | number2 | number3 |
| 10 | 20 | 150 |
| 20 | 40 | 180 |
- | 40 | 60 | 220 |
Scenario: Add two numbers
Given I have entered 50 into the calculator
@@ -0,0 +1,8 @@
+var Steps = require('kyuri').Steps;
+
+Steps.Given(/^I have entered (\d+) into the calculator$/, function (step, num) {
+ console.log('Calculator: ' + num);
+ step.done();
+});
+
+Steps.export(module);
View
@@ -0,0 +1,24 @@
+/*
+ * Set up environmental configuration here, for example database events and functions
+ *
+ * (C) 2011 Paul Covell (paul@done.com)
+ * MIT LICENSE
+ *
+ */
+var Runner = require('kyuri').runner;
+
+Runner.on('beforeTest', function (done) {
+ console.log('beforeTest event');
+ done();
+});
+
+Runner.on('beforeBackground', function (done) {
+ console.log('beforeBackground event');
+ done();
+});
+
+Runner.on('afterTest', function (done) {
+ console.log('afterTest event');
+ done();
+});
+
View
@@ -6,27 +6,26 @@
*
*/
-require.paths.unshift(__dirname);
-
var kyuri = exports;
//
// Export core methods
//
kyuri.version = '0.1.0';
-kyuri.compile = require('kyuri/core').compile;
-kyuri.parse = require('kyuri/core').parse;
-kyuri.tokens = require('kyuri/core').tokens;
-kyuri.nodes = require('kyuri/core').nodes;
-kyuri.setLanguage = require('kyuri/core').setLanguage;
-kyuri.i18n = require('kyuri/core').i18n;
-kyuri.Steps = require('kyuri/steps');
+kyuri.compile = require('./kyuri/core').compile;
+kyuri.parse = require('./kyuri/core').parse;
+kyuri.tokens = require('./kyuri/core').tokens;
+kyuri.nodes = require('./kyuri/core').nodes;
+kyuri.setLanguage = require('./kyuri/core').setLanguage;
+kyuri.i18n = require('./kyuri/core').i18n;
+kyuri.Steps = require('./kyuri/steps');
//
// Export runners
//
kyuri.runners = {};
-kyuri.runners.vows = require('kyuri/runners/vows');
+kyuri.runners.vows = require('./kyuri/runners/vows');
+kyuri.runners.cucumber = require('./kyuri/runners/cucumber');
//
// Remark we should probably export the runner methods
View
@@ -25,6 +25,13 @@ exports.compile = function (code, options) {
// Default options are to generate steps only
options = options || {};
options.target = options.target || 'steps'
+ options.tabspace = options.tabspace || 8;
+
+ // Convert groups of spaces to tabs
+ code = code.replace(new RegExp(' {' + options.tabspace + '}', 'g'), '\t');
+
+ // we don't need this anymore
+ delete options.tabspace;
try {
ast = isText ? parser.parse(lexer.tokenize(code)) : code;
@@ -64,4 +71,4 @@ exports.setLanguage = function (language) {
lexer = new Lexer(language, i18n);
};
-exports.i18n = i18n;
+exports.i18n = i18n;
View
@@ -10,7 +10,7 @@ var _ = require('underscore')._,
fs = require('fs'),
path = require('path'),
eyes = require('eyes'),
- sys = require('sys');
+ util = require('util');
// Configure underscore to work like mustache
_.templateSettings = {
@@ -185,7 +185,7 @@ var StepGenerator = function (ast) {
};
// Make 'StepGenerator' inherit from 'Generator'
-sys.inherits(StepGenerator, Generator);
+util.inherits(StepGenerator, Generator);
exports.Generator = Generator;
exports.StepGenerator = StepGenerator;
Oops, something went wrong.

0 comments on commit ac59608

Please sign in to comment.