Skip to content
Browse files

Add colors to CLI (close #104)

Implemented colors and filenames, line number display in progress,
pretty and summary formatters along with support for environment
variable CUCUMBER_COLORS.

Squashed commit of the following:

commit 44c6757
Merge: 0411c18 53c3501
Author: Julien Biezemans <jb@jbpros.com>
Date:   Wed Nov 27 15:49:39 2013 +0100

    Merge branch 'master' into colors

    Conflicts:
    	lib/cucumber/cli.js
    	lib/cucumber/cli/argument_parser.js
    	lib/cucumber/cli/configuration.js
    	lib/cucumber/listener/progress_formatter.js
    	lib/cucumber/listener/summary_formatter.js
    	lib/cucumber/support_code.js
    	lib/cucumber/support_code/step_definition_snippet_builder_syntax.js
    	package.json
    	spec/cucumber/cli/configuration_spec.js
    	spec/cucumber/support_code/step_definition_snippet_builder_syntax_spec.js

commit 0411c18
Author: Julien Biezemans <jb@jbpros.com>
Date:   Tue Dec 25 23:28:48 2012 +0100

    Fix indentation

commit 0a62aea
Author: Julien Biezemans <jb@jbpros.com>
Date:   Tue Dec 25 23:14:39 2012 +0100

    Rename "coffee" internal formatter option to "coffeeScriptSnippets"

commit df69e13
Author: Julien Biezemans <jb@jbpros.com>
Date:   Tue Dec 25 23:12:19 2012 +0100

    Organize methods

commit fc662ed
Author: Julien Biezemans <jb@jbpros.com>
Date:   Tue Dec 25 23:11:39 2012 +0100

    Add missing specs to CLI configuration

commit 5ff71bb
Author: Julien Biezemans <jb@jbpros.com>
Date:   Tue Dec 25 22:17:01 2012 +0100

    Add argument parser specs for --coffee option

commit 38f5600
Author: Julien Biezemans <jb@jbpros.com>
Date:   Tue Dec 25 22:07:47 2012 +0100

    Remove useless newline

commit 9035433
Author: Julien Biezemans <jb@jbpros.com>
Date:   Tue Dec 25 22:06:51 2012 +0100

    Rename "feature tags" to "inherited tags"

commit 817c34c
Author: Julien Biezemans <jb@jbpros.com>
Date:   Tue Dec 25 21:53:06 2012 +0100

    Remove useless stub

commit 8a0ecab
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Thu Dec 13 00:18:00 2012 +0530

    removed debug code

commit c46cffb
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Wed Dec 12 23:03:45 2012 +0530

    Implemented stricter color formatting to prevent bugs with newline character. Added tags to pretty formatter output.

commit 260b595
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Wed Dec 12 04:10:21 2012 +0530

    Fixed bug with pretty formatter output in scenario without a background

commit 9403fa5
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Tue Dec 11 21:19:05 2012 +0530

    Fixed wrongly indented output for datatables when using colors.

commit e603982
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Tue Dec 11 14:52:35 2012 +0530

    Added proper filename and line indentation for background steps

commit 335b2da
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Tue Dec 11 12:12:45 2012 +0530

    Added coffeescript snippet support to the pretty formatter

commit ea2c3aa
Merge: f2c63c2 c09d4c6
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Mon Dec 10 15:04:32 2012 +0530

    Merge branch 'johngeorgewright'

commit f2c63c2
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Mon Dec 10 07:03:23 2012 +0530

    Updated step definitions for colored output.

commit e61e995
Author: Johny Jose <johny.aiesec@gmail.com>
Date:   Mon Dec 10 06:28:09 2012 +0530

    Implemented colors and filenames, line number display in progress, pretty and summary formatters along with support for environment variable CUCUMBER_COLORS.

commit c09d4c6
Author: John Wright <johngeorge.wright@gmail.com>
Date:   Thu Sep 13 22:29:04 2012 +1000

    Added a spec file for the syntax classes.

commit bdbf7a6
Author: John Wright <johngeorge.wright@gmail.com>
Date:   Thu Sep 13 22:24:57 2012 +1000

    Updated StepDefinitionSnippetBuilder spec file.

commit db0b8c3
Author: John Wright <johngeorge.wright@gmail.com>
Date:   Wed Sep 12 08:47:30 2012 +1000

    Updated tests for summary formatter.

commit aead79d
Author: John Wright <johngeorge.wright@gmail.com>
Date:   Wed Sep 12 08:46:55 2012 +1000

    The syntax construction now is created by a separate method. This makes things easier to test.

commit 705aca4
Author: John Wright <johngeorge.wright@gmail.com>
Date:   Tue Sep 11 20:31:38 2012 +1000

    #65 Getting Jamsine to pass.

commit b8b4780
Author: John Wright <johngeorge.wright@gmail.com>
Date:   Tue Sep 11 20:11:33 2012 +1000

    #65 Forgot about replacing the definition matching group parameters.

commit 878e8b8
Author: John Wright <johngeorge.wright@gmail.com>
Date:   Tue Sep 11 17:02:31 2012 +1000

    #65 The --coffee option will now switch the step definition builder between syntaxs.

commit d6ca30d
Author: John Wright <johngeorge.wright@gmail.com>
Date:   Tue Sep 11 17:01:26 2012 +1000

    #65 The step defintions snippets builder now uses a syntax behaviour rather then static properties. The CoffeeScript flavour has also been added here.
  • Loading branch information...
1 parent 53c3501 commit 7dc33d46e5ff2b06250ed35a64b34ab328073410 @atrniv atrniv committed with jbpros Nov 27, 2013
View
13 features/step_definitions/cucumber_world.js
@@ -254,27 +254,27 @@ proto.assertPassedFeature = function assertPassedFeature() {
proto.assertPassedFeatures = function assertPassedFeatures() {
this.assertNoPartialOutput("failed", this.runOutput);
- this.assertPartialOutput("3 scenarios (3 passed)", this.runOutput);
+ this.assertPartialOutput("3 scenarios ("+this.color.format("passed","3 passed")+")", this.runOutput);
this.assertSuccess();
};
proto.assertPassedScenario = function assertPassedScenario() {
- this.assertPartialOutput("1 scenario (1 passed)", this.runOutput);
+ this.assertPartialOutput("1 scenario ("+this.color.format("passed","1 passed")+")", this.runOutput);
this.assertSuccess();
};
proto.assertFailedScenario = function assertFailedScenario() {
- this.assertPartialOutput("1 scenario (1 failed)", this.runOutput);
+ this.assertPartialOutput("1 scenario ("+this.color.format("failed","1 failed")+")", this.runOutput);
this.assertFailure();
};
proto.assertPendingScenario = function assertPendingScenario() {
- this.assertPartialOutput("1 scenario (1 pending)", this.runOutput);
+ this.assertPartialOutput("1 scenario ("+this.color.format("pending","1 pending")+")", this.runOutput);
this.assertSuccess();
};
proto.assertUndefinedScenario = function assertUndefinedScenario() {
- this.assertPartialOutput("1 scenario (1 undefined)", this.runOutput);
+ this.assertPartialOutput("1 scenario ("+this.color.format("undefined", "1 undefined")+")", this.runOutput);
this.assertSuccess();
};
@@ -394,4 +394,7 @@ proto.indentCode = function indentCode(code, levels) {
return indented;
};
+proto.color = require('../../lib/cucumber/util/colors');
+
exports.World = World;
+
View
2 lib/cucumber/ast/assembler.js
@@ -42,7 +42,7 @@ var Assembler = function(features, filter) {
applyCurrentFeatureTagsToElement: function applyCurrentFeatureTagsToElement(element) {
var currentFeature = self.getCurrentFeature();
var featureTags = currentFeature.getTags();
- element.addTags(featureTags);
+ element.addInheritedtags(featureTags);
},
applyStashedTagsToElement: function applyStashedTagsToElement(element) {
View
11 lib/cucumber/ast/background.js
@@ -36,7 +36,16 @@ var Background = function(keyword, name, description, uri, line) {
getSteps: function getSteps() {
return steps;
- }
+ },
+
+ getMaxStepLength: function () {
+ var max = 0;
+ steps.syncForEach(function(step) {
+ var output = step.getKeyword() + step.getName();
+ if (output.length > max) max = output.length;
+ });
+ return max;
+ }
};
return self;
};
View
20 lib/cucumber/ast/scenario.js
@@ -3,6 +3,7 @@ var Scenario = function(keyword, name, description, uri, line) {
var background;
var steps = Cucumber.Type.Collection();
+ var inheritedTags = [];
var tags = [];
var self = {
@@ -44,11 +45,28 @@ var Scenario = function(keyword, name, description, uri, line) {
return steps.getLast();
},
- addTags: function setTags(newTags) {
+ getMaxStepLength: function () {
+ var max = 0;
+ steps.syncForEach(function(step) {
+ var output = step.getKeyword() + step.getName();
+ if (output.length > max) max = output.length;
+ });
+ return max;
+ },
+
+ addTags: function addTags(newTags) {
tags = tags.concat(newTags);
},
+ addInheritedtags: function addInheritedtags(newTags) {
+ inheritedTags = tags.concat(newTags);
+ },
+
getTags: function getTags() {
+ return tags.concat(inheritedTags);
+ },
+
+ getOwnTags: function getOwnTags() {
return tags;
},
View
54 lib/cucumber/cli/argument_parser.js
@@ -64,12 +64,12 @@ var ArgumentParser = function(argv) {
getKnownOptionDefinitions: function getKnownOptionDefinitions() {
var definitions = {};
- definitions[ArgumentParser.REQUIRE_OPTION_NAME] = [path, Array];
- definitions[ArgumentParser.TAGS_OPTION_NAME] = [String, Array];
- definitions[ArgumentParser.FORMAT_OPTION_NAME] = String;
- definitions[ArgumentParser.HELP_FLAG_NAME] = Boolean;
- definitions[ArgumentParser.VERSION_FLAG_NAME] = Boolean;
- definitions[ArgumentParser.COFFEE_SNIPPETS] = Boolean;
+ definitions[ArgumentParser.REQUIRE_OPTION_NAME] = [path, Array];
+ definitions[ArgumentParser.TAGS_OPTION_NAME] = [String, Array];
+ definitions[ArgumentParser.FORMAT_OPTION_NAME] = String;
+ definitions[ArgumentParser.HELP_FLAG_NAME] = Boolean;
+ definitions[ArgumentParser.VERSION_FLAG_NAME] = Boolean;
+ definitions[ArgumentParser.COFFEE_SCRIPT_SNIPPETS_FLAG_NAME] = Boolean;
return definitions;
},
@@ -91,9 +91,9 @@ var ArgumentParser = function(argv) {
return isVersionRequested;
},
- shouldSnippetsBeInCoffee: function shouldSnippetsBeInCoffee() {
- var coffeeDisplay = self.getOptionOrDefault(ArgumentParser.COFFEE_SNIPPETS, ArgumentParser.DEFAULT_COFFEE_SNIPPETS);
- return coffeeDisplay;
+ shouldSnippetsBeInCoffeeScript: function shouldSnippetsBeInCoffeeScript() {
+ var areSnippetsInCoffeeScript = self.getOptionOrDefault(ArgumentParser.COFFEE_SCRIPT_SNIPPETS_FLAG_NAME, ArgumentParser.DEFAULT_COFFEE_SCRIPT_SNIPPETS_FLAG_VALUE);
+ return areSnippetsInCoffeeScript;
},
storeOptions: function storeOptions(newOptions) {
@@ -112,24 +112,24 @@ var ArgumentParser = function(argv) {
};
return self;
};
-ArgumentParser.NUMBER_OF_LEADING_ARGS_TO_SLICE = 2;
-ArgumentParser.DEFAULT_FEATURES_DIRECTORY = "features";
-ArgumentParser.FEATURE_FILENAME_REGEXP = /[\/\\][^\/\\]+\.feature$/i;
-ArgumentParser.LONG_OPTION_PREFIX = "--";
-ArgumentParser.REQUIRE_OPTION_NAME = "require";
-ArgumentParser.REQUIRE_OPTION_SHORT_NAME = "r";
-ArgumentParser.FORMAT_OPTION_NAME = "format";
-ArgumentParser.FORMAT_OPTION_SHORT_NAME = "f";
-ArgumentParser.DEFAULT_FORMAT_VALUE = "progress";
-ArgumentParser.TAGS_OPTION_NAME = "tags";
-ArgumentParser.TAGS_OPTION_SHORT_NAME = "t";
-ArgumentParser.HELP_FLAG_NAME = "help";
-ArgumentParser.HELP_FLAG_SHORT_NAME = "h";
-ArgumentParser.DEFAULT_HELP_FLAG_VALUE = false;
-ArgumentParser.VERSION_FLAG_NAME = "version";
-ArgumentParser.DEFAULT_VERSION_FLAG_VALUE = false;
-ArgumentParser.COFFEE_SNIPPETS = "coffee";
-ArgumentParser.DEFAULT_COFFEE_SNIPPETS = false;
+ArgumentParser.NUMBER_OF_LEADING_ARGS_TO_SLICE = 2;
+ArgumentParser.DEFAULT_FEATURES_DIRECTORY = "features";
+ArgumentParser.FEATURE_FILENAME_REGEXP = /[\/\\][^\/\\]+\.feature$/i;
+ArgumentParser.LONG_OPTION_PREFIX = "--";
+ArgumentParser.REQUIRE_OPTION_NAME = "require";
+ArgumentParser.REQUIRE_OPTION_SHORT_NAME = "r";
+ArgumentParser.FORMAT_OPTION_NAME = "format";
+ArgumentParser.FORMAT_OPTION_SHORT_NAME = "f";
+ArgumentParser.DEFAULT_FORMAT_VALUE = "progress";
+ArgumentParser.TAGS_OPTION_NAME = "tags";
+ArgumentParser.TAGS_OPTION_SHORT_NAME = "t";
+ArgumentParser.HELP_FLAG_NAME = "help";
+ArgumentParser.HELP_FLAG_SHORT_NAME = "h";
+ArgumentParser.DEFAULT_HELP_FLAG_VALUE = false;
+ArgumentParser.VERSION_FLAG_NAME = "version";
+ArgumentParser.DEFAULT_VERSION_FLAG_VALUE = false;
+ArgumentParser.COFFEE_SCRIPT_SNIPPETS_FLAG_NAME = "coffee";
+ArgumentParser.DEFAULT_COFFEE_SCRIPT_SNIPPETS_FLAG_VALUE = false;
ArgumentParser.FeaturePathExpander = require('./argument_parser/feature_path_expander');
ArgumentParser.PathExpander = require('./argument_parser/path_expander');
ArgumentParser.SupportCodePathExpander = require('./argument_parser/support_code_path_expander');
View
8 lib/cucumber/cli/configuration.js
@@ -7,8 +7,8 @@ var Configuration = function(argv) {
var self = {
getFormatter: function getFormatter() {
var formatter;
- var format = argumentParser.getFormat();
- var options = {coffee: self.shouldSnippetsBeInCoffee()};
+ var format = argumentParser.getFormat();
+ var options = {coffeeScriptSnippets: self.shouldSnippetsBeInCoffeeScript()};
switch(format) {
case Configuration.JSON_FORMAT_NAME:
formatter = Cucumber.Listener.JsonFormatter(options);
@@ -68,8 +68,8 @@ var Configuration = function(argv) {
return isVersionRequested;
},
- shouldSnippetsBeInCoffee: function shouldSnippetsBeInCoffee() {
- var coffeeDisplay = argumentParser.shouldSnippetsBeInCoffee();
+ shouldSnippetsBeInCoffeeScript: function shouldSnippetsBeInCoffeeScript() {
+ var coffeeDisplay = argumentParser.shouldSnippetsBeInCoffeeScript();
return coffeeDisplay;
}
View
87 lib/cucumber/listener/pretty_formatter.js
@@ -1,8 +1,13 @@
var PrettyFormatter = function(options) {
- var Cucumber = require('../../cucumber');
+ var Cucumber = require('../../cucumber');
+ var color = Cucumber.Util.ConsoleColor;
var self = Cucumber.Listener.Formatter(options);
- var summaryFormatter = Cucumber.Listener.SummaryFormatter({logToConsole: false});
+ var summaryFormatter = Cucumber.Listener.SummaryFormatter({
+ coffeeScriptSnippets: options.coffeeScriptSnippets,
+ logToConsole: false
+ });
+ var currentMaxStepLength = 0;
var parentHear = self.hear;
self.hear = function hear(event, callback) {
@@ -13,14 +18,39 @@ var PrettyFormatter = function(options) {
self.handleBeforeFeatureEvent = function handleBeforeFeatureEvent(event, callback) {
var feature = event.getPayloadItem('feature');
- var source = feature.getKeyword() + ": " + feature.getName() + "\n\n";
+ var tags = feature.getTags();
+ var tagNames = [];
+ for (var idx = 0; idx < tags.length; idx++) {
+ tagNames.push(tags[idx].getName());
+ }
+ var source = color.format('tag', tagNames.join(" ")) + "\n" + feature.getKeyword() + ": " + feature.getName() + "\n";
self.log(source);
+ self.logIndented(feature.getDescription() + "\n\n", 1);
callback();
};
self.handleBeforeScenarioEvent = function handleBeforeScenarioEvent(event, callback) {
var scenario = event.getPayloadItem('scenario');
- var source = scenario.getKeyword() + ": " + scenario.getName() + "\n";
+ var tags = scenario.getOwnTags();
+ var tagNames = [];
+ for (var idx = 0; idx < tags.length; idx++) {
+ tagNames.push(tags[idx].getName());
+ }
+ var tagSource = color.format("tag", tagNames.join(" ")) + "\n" ;
+ var source = scenario.getKeyword() + ": " + scenario.getName();
+ var lineLengths = [source.length, scenario.getMaxStepLength()];
+ if (scenario.getBackground() !== undefined) {
+ lineLengths.push(scenario.getBackground().getMaxStepLength());
+ }
+ lineLengths.sort(function(a,b) { return b-a; });
+ currentMaxStepLength = lineLengths[0];
+
+ source = tagSource + self._pad(source, currentMaxStepLength + 3);
+
+ uri = color.format('comment', "# " + scenario.getUri().replace(process.cwd(),'').slice(1) + ":" + scenario.getLine());
+
+ source += uri + "\n";
+
self.logIndented(source, 1);
callback();
};
@@ -30,23 +60,52 @@ var PrettyFormatter = function(options) {
callback();
};
+ self.applyColor = function (stepResult, source) {
+ if (stepResult.isFailed()) source = color.format('failed', source);
+ else if (stepResult.isPending()) source = color.format('pending',source);
+ else if (stepResult.isSkipped()) source = color.format('skipped',source);
+ else if (stepResult.isSuccessful()) source = color.format('passed',source);
+ else if (stepResult.isUndefined()) source = color.format('undefined',source);
+ return source;
+ };
+
+ self.setColorFormat = function (stepResult) {
+ if (stepResult.isFailed()) color.setFormat('failed');
+ else if (stepResult.isPending()) color.setFormat('pending');
+ else if (stepResult.isSkipped()) color.setFormat('skipped');
+ else if (stepResult.isSuccessful()) color.setFormat('passed');
+ else if (stepResult.isUndefined()) color.setFormat('undefined');
+ };
+
+ self.resetColorFormat = function() {
+ color.resetFormat();
+ }
+
self.handleStepResultEvent = function handleStepResultEvent(event, callback) {
var stepResult = event.getPayloadItem('stepResult');
var step = stepResult.getStep();
- var source = step.getKeyword() + step.getName() + "\n";
+
+ var uri = "";
+
+ uri = color.format('comment', "# " + step.getUri().replace(process.cwd(),'').slice(1) + ":" + step.getLine());
+
+ var source = self.applyColor(stepResult, step.getKeyword() + step.getName());
+
+ source = self._pad(source, currentMaxStepLength + 10);
+
+ source += uri + "\n";
self.logIndented(source, 2);
if (step.hasDataTable()) {
var dataTable = step.getDataTable();
- self.logDataTable(dataTable);
+ self.logDataTable(stepResult, dataTable);
}
if (step.hasDocString()) {
var docString = step.getDocString();
- self.logDocString(docString);
+ self.logDocString(stepResult, docString);
}
- stepResult.isFailed();
if (stepResult.isFailed()) {
var failure = stepResult.getFailureException();
var failureDescription = failure.stack || failure;
@@ -62,28 +121,28 @@ var PrettyFormatter = function(options) {
callback();
};
- self.logDataTable = function logDataTable(dataTable) {
+ self.logDataTable = function logDataTable(stepResult, dataTable) {
var rows = dataTable.raw();
var columnWidths = self._determineColumnWidthsFromRows(rows);
var rowCount = rows.length;
var columnCount = columnWidths.length;
-
for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) {
var cells = rows[rowIndex];
var line = "|";
for (var columnIndex = 0; columnIndex < columnCount; columnIndex++) {
var cell = cells[columnIndex];
var columnWidth = columnWidths[columnIndex];
- line += " " + self._pad(cell, columnWidth) + " |"
+ line += " " + self.applyColor(stepResult, self._pad(cell, columnWidth)) + " |"
}
line += "\n";
self.logIndented(line, 3);
}
};
- self.logDocString = function logDocString(docString) {
- var contents = docString.getContents();
- self.logIndented('"""\n' + contents + '\n"""\n' , 3);
+ self.logDocString = function logDocString(stepResult, docString) {
+ var contents = '"""\n' + docString.getContents() + '\n"""\n';
+ contents = self.applyColor(stepResult, contents)
+ self.logIndented(contents, 3);
};
self.logIndented = function logIndented(text, level) {
View
17 lib/cucumber/listener/progress_formatter.js
@@ -1,11 +1,14 @@
+var ConsoleColor = require('../util/colors');
var ProgressFormatter = function(options) {
var Cucumber = require('../../cucumber');
-
if (!options)
options = {};
var self = Cucumber.Listener.Formatter(options);
- var summaryFormatter = Cucumber.Listener.SummaryFormatter({coffee: options.coffee, logToConsole: false});
+ var summaryFormatter = Cucumber.Listener.SummaryFormatter({
+ coffeeScriptSnippets: options.coffeeScriptSnippets,
+ logToConsole: false
+ });
var parentHear = self.hear;
self.hear = function hear(event, callback) {
@@ -58,9 +61,9 @@ var ProgressFormatter = function(options) {
return self;
};
-ProgressFormatter.PASSED_STEP_CHARACTER = '.';
-ProgressFormatter.SKIPPED_STEP_CHARACTER = '-';
-ProgressFormatter.UNDEFINED_STEP_CHARACTER = 'U';
-ProgressFormatter.PENDING_STEP_CHARACTER = 'P';
-ProgressFormatter.FAILED_STEP_CHARACTER = 'F';
+ProgressFormatter.PASSED_STEP_CHARACTER = ConsoleColor.format('passed', '.');
+ProgressFormatter.SKIPPED_STEP_CHARACTER = ConsoleColor.format('skipped', '-');
+ProgressFormatter.UNDEFINED_STEP_CHARACTER = ConsoleColor.format('undefined', 'U');
+ProgressFormatter.PENDING_STEP_CHARACTER = ConsoleColor.format('pending', 'P');
+ProgressFormatter.FAILED_STEP_CHARACTER = ConsoleColor.format('failed', 'F');
module.exports = ProgressFormatter;
View
26 lib/cucumber/listener/summary_formatter.js
@@ -1,10 +1,12 @@
var SummaryFormatter = function (options) {
var Cucumber = require('../../cucumber');
+
var failedScenarioLogBuffer = "";
var undefinedStepLogBuffer = "";
var failedStepResults = Cucumber.Type.Collection();
var statsJournal = Cucumber.Listener.StatsJournal();
+ var color = Cucumber.Util.ConsoleColor;
var self = Cucumber.Listener.Formatter(options);
@@ -65,7 +67,7 @@ var SummaryFormatter = function (options) {
};
self.getStepDefinitionSyntax = function getStepDefinitionSyntax() {
- var syntax = options.coffee ? 'CoffeeScript' : 'JavaScript';
+ var syntax = options.coffeeScriptSnippets ? 'CoffeeScript' : 'JavaScript';
return new Cucumber.SupportCode.StepDefinitionSnippetBuilderSyntax[syntax]();
};
@@ -123,13 +125,13 @@ var SummaryFormatter = function (options) {
self.log(scenarioCount + " scenario" + (scenarioCount != 1 ? "s" : ""));
if (scenarioCount > 0 ) {
if (failedScenarioCount > 0)
- details.push(failedScenarioCount + " failed");
+ details.push(color.format('failed', failedScenarioCount + " failed"));
if (undefinedScenarioCount > 0)
- details.push(undefinedScenarioCount + " undefined");
+ details.push(color.format('undefined', undefinedScenarioCount + " undefined"));
if (pendingScenarioCount > 0)
- details.push(pendingScenarioCount + " pending");
+ details.push(color.format('pending', pendingScenarioCount + " pending"));
if (passedScenarioCount > 0)
- details.push(passedScenarioCount + " passed");
+ details.push(color.format('passed', passedScenarioCount + " passed"));
self.log(" (" + details.join(', ') + ")");
}
self.log("\n");
@@ -147,24 +149,24 @@ var SummaryFormatter = function (options) {
self.log(stepCount + " step" + (stepCount != 1 ? "s" : ""));
if (stepCount > 0) {
if (failedStepCount > 0)
- details.push(failedStepCount + " failed");
+ details.push(color.format('failed', failedStepCount + " failed"));
if (undefinedStepCount > 0)
- details.push(undefinedStepCount + " undefined");
+ details.push(color.format('undefined', undefinedStepCount + " undefined"));
if (pendingStepCount > 0)
- details.push(pendingStepCount + " pending");
+ details.push(color.format('pending', pendingStepCount + " pending"));
if (skippedStepCount > 0)
- details.push(skippedStepCount + " skipped");
+ details.push(color.format('skipped', skippedStepCount + " skipped"));
if (passedStepCount > 0)
- details.push(passedStepCount + " passed");
+ details.push(color.format('passed', passedStepCount + " passed"));
self.log(" (" + details.join(', ') + ")");
}
self.log("\n");
};
self.logUndefinedStepSnippets = function logUndefinedStepSnippets() {
var undefinedStepLogBuffer = self.getUndefinedStepLogBuffer();
- self.log("\nYou can implement step definitions for undefined steps with these snippets:\n\n");
- self.log(undefinedStepLogBuffer);
+ self.log(color.format('pending', "\nYou can implement step definitions for undefined steps with these snippets:\n\n"));
+ self.log(color.format('pending', undefinedStepLogBuffer));
};
return self;
View
2 lib/cucumber/support_code.js
@@ -5,4 +5,4 @@ SupportCode.StepDefinition = require('./support_code/step_de
SupportCode.StepDefinitionSnippetBuilder = require('./support_code/step_definition_snippet_builder');
SupportCode.StepDefinitionSnippetBuilderSyntax = require('./support_code/step_definition_snippet_builder_syntax');
SupportCode.WorldConstructor = require('./support_code/world_constructor');
-module.exports = SupportCode;
+module.exports = SupportCode;
View
2 lib/cucumber/support_code/step_definition_snippet_builder_syntax.js
@@ -93,5 +93,5 @@ CoffeeScriptSyntax.prototype = {
_.extend(CoffeeScriptSyntax.prototype, Syntax.prototype);
-exports.JavaScript = JavaScriptSyntax;
+exports.JavaScript = JavaScriptSyntax;
exports.CoffeeScript = CoffeeScriptSyntax;
View
1 lib/cucumber/util.js
@@ -3,4 +3,5 @@ Util.Arguments = require('./util/arguments');
Util.Exception = require('./util/exception');
Util.RegExp = require('./util/reg_exp');
Util.String = require('./util/string');
+Util.ConsoleColor = require('./util/colors');
module.exports = Util;
View
85 lib/cucumber/util/colors.js
@@ -0,0 +1,85 @@
+var ConsoleColor = {
+ ANSICodes: {
+ 'reset' : '\033[0m',
+ 'bold' : '\033[1m',
+ 'faint' : '\033[2m',
+ 'grey' : '\033[2m\033[37m',
+ 'italic' : '\033[3m',
+ 'underline' : '\033[4m',
+ 'blink' : '\033[5m',
+ 'black' : '\033[30m',
+ 'red' : '\033[31m',
+ 'green' : '\033[32m',
+ 'yellow' : '\033[33m',
+ 'blue' : '\033[34m',
+ 'magenta' : '\033[35m',
+ 'cyan' : '\033[36m',
+ 'white' : '\033[37m'
+ },
+
+ formatColors: {
+ 'undefined' : ['yellow'],
+ 'pending' : ['yellow'],
+ 'pending_param' : ['yellow','bold'],
+ 'failed' : ['red'],
+ 'failed_param' : ['red','bold'],
+ 'passed' : ['green'],
+ 'passed_param' : ['green','bold'],
+ 'skipped' : ['cyan'],
+ 'skipped_param' : ['cyan','bold'],
+ 'comment' : ['grey'],
+ 'tag' : ['cyan']
+ },
+
+ color: function (colors, text, noReset) {
+ code = '';
+ if (Object.prototype.toString.call(colors).slice(8,-1) !== 'Array')
+ colors = [colors];
+ for (var idx = 0; idx < colors.length; idx++) {
+ // Check if color is valid
+ if(this.ANSICodes[colors[idx]] !== undefined) {
+ code += this.ANSICodes[colors[idx]];
+ }
+ }
+ lines = text.split("\n");
+ for (var lineNumber = 0; lineNumber < lines.length; lineNumber++) {
+ if(lines[lineNumber].length > 0) {
+ lines[lineNumber] = code + lines[lineNumber] + this.ANSICodes['reset'];
+ }
+ }
+ return lines.join("\n");
+ },
+
+ format: function(format, text, noReset) {
+ // Check environment for color codes
+ var envColors = process.env.CUCUMBER_COLORS;
+ if(envColors !== undefined && envColors.length > 0) {
+ envColors = process.env.CUCUMBER_COLORS.split(':');
+ for (var idx = 0; idx < envColors.length; idx++) {
+ var envColor = envColors[idx].split('=');
+ // Break if bad value
+ if(envColor[1] === undefined) break;
+ var newColors = envColor[1].split(',');
+ // Assign environment colors only if they are valid
+ var isValidColor = true;
+ for (var idx2 = 0; idx2 < newColors.length; idx2++) {
+ if (this.ANSICodes[newColors[idx2]] === undefined) isValidColor = false;
+ }
+ if (isValidColor && this.formatColors[envColor[0]] !== undefined) {
+ this.formatColors[envColor[0]] = newColors;
+ }
+ }
+ }
+ format = this.formatColors[format];
+ return this.color(format, text, noReset);
+ },
+
+ setFormat: function(format) {
+ process.stdout.write(this.format(format,'',true));
+ },
+
+ resetFormat: function(format) {
+ process.stdout.write(this.color('reset','',true));
+ }
+};
+module.exports = ConsoleColor;
View
3 package.json
@@ -33,7 +33,8 @@
"David Godfrey <reactiveraven@reactiveraven.co.uk>",
"Paul Shannon (http://devpaul.com)",
"Simon Dean <simon@simondean.org> (http://www.simondean.org)",
- "John Wright <johngeorge.wright@gmail.com>"
+ "John Wright <johngeorge.wright@gmail.com>",
+ "Johny Jose <johny@playlyfe.com>"
],
"repository": {
"type": "git",
View
4 spec/cucumber/ast/assembler_spec.js
@@ -103,7 +103,7 @@ describe("Cucumber.Ast.Assembler", function() {
var feature, featureTags, element;
beforeEach(function() {
- element = createSpyWithStubs("AST element", {addTags: null});
+ element = createSpyWithStubs("AST element", {addInheritedtags: null});
featureTags = createSpy("feature tags");
feature = createSpyWithStubs("current feature", {getTags: featureTags});
spyOn(assembler, 'getCurrentFeature').andReturn(feature);
@@ -121,7 +121,7 @@ describe("Cucumber.Ast.Assembler", function() {
it("adds the feature tags to the element", function() {
assembler.applyCurrentFeatureTagsToElement(element);
- expect(element.addTags).toHaveBeenCalledWith(featureTags);
+ expect(element.addInheritedtags).toHaveBeenCalledWith(featureTags);
});
});
View
18 spec/cucumber/cli/argument_parser_spec.js
@@ -339,6 +339,24 @@ describe("Cucumber.Cli.ArgumentParser", function () {
});
});
+ describe("shouldSnippetsBeInCoffeeScript()", function () {
+ var shouldSnippetsBeInCoffeeScript;
+
+ beforeEach(function () {
+ shouldSnippetsBeInCoffeeScript = createSpy("should snippets be in coffee script?");
+ spyOn(argumentParser, 'getOptionOrDefault').andReturn(shouldSnippetsBeInCoffeeScript);
+ });
+
+ it("gets the 'coffee' flag with a falsy default value", function () {
+ argumentParser.shouldSnippetsBeInCoffeeScript();
+ expect(argumentParser.getOptionOrDefault).toHaveBeenCalledWith("coffee", false);
+ });
+
+ it("returns the flag value", function () {
+ expect(argumentParser.shouldSnippetsBeInCoffeeScript()).toBe(shouldSnippetsBeInCoffeeScript);
+ });
+ });
+
describe("getOptions() [storeOptions()]", function () {
var options;
View
38 spec/cucumber/cli/configuration_spec.js
@@ -29,9 +29,13 @@ describe("Cucumber.Cli.Configuration", function () {
});
describe("getFormatter()", function () {
+ var shouldSnippetsBeInCoffeeScript, formatterOptions;
+
beforeEach(function () {
+ shouldSnippetsBeInCoffeeScript = createSpy("should snippets be in CS?");
+ formatterOptions = {coffeeScriptSnippets: shouldSnippetsBeInCoffeeScript};
spyOnStub(argumentParser, 'getFormat').andReturn("progress");
- spyOnStub(argumentParser, 'shouldSnippetsBeInCoffee').andReturn(false);
+ spyOnStub(argumentParser, 'shouldSnippetsBeInCoffeeScript').andReturn(shouldSnippetsBeInCoffeeScript);
spyOn(Cucumber.Listener, 'JsonFormatter');
spyOn(Cucumber.Listener, 'ProgressFormatter');
spyOn(Cucumber.Listener, 'PrettyFormatter');
@@ -43,6 +47,11 @@ describe("Cucumber.Cli.Configuration", function () {
expect(argumentParser.getFormat).toHaveBeenCalled();
});
+ it("checks whether the step definition snippets should be in CoffeeScript", function () {
+ configuration.getFormatter();
+ expect(argumentParser.shouldSnippetsBeInCoffeeScript).toHaveBeenCalled();
+ });
+
describe("when the formatter name is \"json\"", function () {
var formatter;
@@ -54,7 +63,7 @@ describe("Cucumber.Cli.Configuration", function () {
it("creates a new progress formatter", function () {
configuration.getFormatter();
- expect(Cucumber.Listener.JsonFormatter).toHaveBeenCalled();
+ expect(Cucumber.Listener.JsonFormatter).toHaveBeenCalledWith(formatterOptions);
});
it("returns the progress formatter", function () {
@@ -73,7 +82,7 @@ describe("Cucumber.Cli.Configuration", function () {
it("creates a new progress formatter", function () {
configuration.getFormatter();
- expect(Cucumber.Listener.ProgressFormatter).toHaveBeenCalled();
+ expect(Cucumber.Listener.ProgressFormatter).toHaveBeenCalledWith(formatterOptions);
});
it("returns the progress formatter", function () {
@@ -92,7 +101,7 @@ describe("Cucumber.Cli.Configuration", function () {
it("creates a new pretty formatter", function () {
configuration.getFormatter();
- expect(Cucumber.Listener.PrettyFormatter).toHaveBeenCalled();
+ expect(Cucumber.Listener.PrettyFormatter).toHaveBeenCalledWith(formatterOptions);
});
it("returns the pretty formatter", function () {
@@ -111,7 +120,7 @@ describe("Cucumber.Cli.Configuration", function () {
it("creates a new summary formatter", function () {
configuration.getFormatter();
- expect(Cucumber.Listener.SummaryFormatter).toHaveBeenCalled();
+ expect(Cucumber.Listener.SummaryFormatter).toHaveBeenCalledWith(formatterOptions);
});
it("returns the summary formatter", function () {
@@ -266,7 +275,7 @@ describe("Cucumber.Cli.Configuration", function () {
});
});
- describe("isVersionRequired()", function () {
+ describe("isVersionRequested()", function () {
beforeEach(function () {
spyOnStub(argumentParser, 'isVersionRequested');
});
@@ -282,4 +291,21 @@ describe("Cucumber.Cli.Configuration", function () {
expect(configuration.isVersionRequested()).toBe(isVersionRequested);
});
});
+
+ describe("shouldSnippetsBeInCoffeeScript()", function () {
+ beforeEach(function () {
+ spyOnStub(argumentParser, 'shouldSnippetsBeInCoffeeScript');
+ });
+
+ it("asks the argument parser whether the version was requested or not", function () {
+ configuration.shouldSnippetsBeInCoffeeScript();
+ expect(argumentParser.shouldSnippetsBeInCoffeeScript).toHaveBeenCalled();
+ });
+
+ it("returns the answer from the argument parser", function () {
+ var shouldSnippetsBeInCoffeeScript = createSpy("is version requested?");
+ argumentParser.shouldSnippetsBeInCoffeeScript.andReturn(shouldSnippetsBeInCoffeeScript);
+ expect(configuration.shouldSnippetsBeInCoffeeScript()).toBe(shouldSnippetsBeInCoffeeScript);
+ });
+ });
});
View
47 spec/cucumber/listener/pretty_formatter_spec.js
@@ -12,6 +12,7 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
spyOn(Cucumber.Listener, 'Formatter').andReturn(formatter);
spyOn(Cucumber.Listener, 'SummaryFormatter').andReturn(summaryFormatter);
prettyFormatter = Cucumber.Listener.PrettyFormatter(options);
+ color = Cucumber.Util.ConsoleColor;
});
describe("constructor", function () {
@@ -65,9 +66,12 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
beforeEach(function () {
keyword = "feature-keyword";
name = "feature-name";
- feature = createSpyWithStubs("feature", { getKeyword: keyword, getName: name });
+ description = "feature-description";
+ tags = [createSpyWithStubs("tags", {getName: '@tag'})];
+ feature = createSpyWithStubs("feature", { getKeyword: keyword, getName: name, getDescription: description, getTags: tags });
event = createSpyWithStubs("event", { getPayloadItem: feature });
callback = createSpy("callback");
+ spyOn(prettyFormatter, 'logIndented');
});
it("gets the feature from the event payload", function () {
@@ -87,10 +91,16 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
it("logs the feature header", function () {
prettyFormatter.handleBeforeFeatureEvent(event, callback);
- var text = keyword + ": " + name + "\n\n";
+ var text = color.format('tag', '@tag') + "\n" +keyword + ": " + name + "\n";
expect(prettyFormatter.log).toHaveBeenCalledWith(text);
});
+ it("logs the feature description", function() {
+ prettyFormatter.handleBeforeFeatureEvent(event, callback);
+ var text = description + "\n\n";
+ expect(prettyFormatter.logIndented).toHaveBeenCalledWith(text,1);
+ });
+
it("calls back", function () {
prettyFormatter.handleBeforeFeatureEvent(event, callback);
expect(callback).toHaveBeenCalled();
@@ -103,7 +113,14 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
beforeEach(function () {
keyword = "scenario-keyword";
name = "scenario-name";
- scenario = createSpyWithStubs("scenario", { getKeyword: keyword, getName: name });
+ //Background step assumed to be the longest
+ backgroundStepLength = 50;
+ scenarioStepLength = 20;
+ tags = [createSpyWithStubs("tags", {getName: '@tag'})];
+ line = 10
+ uri = "scenario-uri";
+ background = createSpyWithStubs("background", { getMaxStepLength: backgroundStepLength})
+ scenario = createSpyWithStubs("scenario", { getKeyword: keyword, getName: name, getMaxStepLength: scenarioStepLength, getUri: uri, getLine: line, getBackground: background, getOwnTags: tags });
event = createSpyWithStubs("event", { getPayloadItem: scenario });
spyOn(prettyFormatter, 'logIndented');
callback = createSpy("callback");
@@ -126,7 +143,7 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
it("logs the scenario header, indented by one level", function () {
prettyFormatter.handleBeforeScenarioEvent(event, callback);
- var text = keyword + ": " + name + "\n";
+ var text = color.format('tag', "@tag") + "\n" + prettyFormatter._pad(keyword + ": " + name, backgroundStepLength + 3) + color.format('comment', "# " + scenario.getUri().slice(1) + ":" + scenario.getLine()) + "\n";
expect(prettyFormatter.logIndented).toHaveBeenCalledWith(text, 1);
});
@@ -161,8 +178,11 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
beforeEach(function () {
keyword = "step-keyword ";
name = "step-name";
- step = createSpyWithStubs("step", { getKeyword: keyword, hasDataTable: null, getDataTable: null, hasDocString: null, getDocString: null, getName: name });
- stepResult = createSpyWithStubs("step result", { getStep: step, isFailed: null });
+ uri = "/step-uri";
+ maxStepLength = 10;
+ line = 10;
+ step = createSpyWithStubs("step", { getKeyword: keyword, hasDataTable: null, getDataTable: null, hasDocString: null, getDocString: null, getName: name, getUri: uri, getLine: line });
+ stepResult = createSpyWithStubs("step result", { getStep: step, isFailed: null, isPending: null, isSuccessful: null, isUndefined: null, isSkipped: null });
event = createSpyWithStubs("event", { getPayloadItem: stepResult });
spyOn(prettyFormatter, 'logDataTable');
spyOn(prettyFormatter, 'logDocString');
@@ -193,6 +213,7 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
it("logs the step header, indented by two levels", function () {
prettyFormatter.handleStepResultEvent(event, callback);
var text = keyword + name + "\n";
+ var text = prettyFormatter._pad(keyword + name, maxStepLength + 10) + color.format('comment', "# " + uri.slice(1) + ":" + line) + "\n";
expect(prettyFormatter.logIndented).toHaveBeenCalledWith(text, 2);
});
@@ -217,7 +238,7 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
it("logs the data table", function () {
prettyFormatter.handleStepResultEvent(event, callback);
- expect(prettyFormatter.logDataTable).toHaveBeenCalledWith(dataTable);
+ expect(prettyFormatter.logDataTable).toHaveBeenCalledWith(stepResult, dataTable);
});
});
@@ -258,7 +279,7 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
it("logs the doc string", function () {
prettyFormatter.handleStepResultEvent(event, callback);
- expect(prettyFormatter.logDocString).toHaveBeenCalledWith(docString);
+ expect(prettyFormatter.logDocString).toHaveBeenCalledWith(stepResult, docString);
});
});
@@ -360,17 +381,18 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
["c", "cuke", "cuke.js"],
["cu", "cuke", "cucumber"]
];
+ stepResult = createSpyWithStubs("step result", { getStep: step, isFailed: null, isPending: null, isSuccessful: null, isUndefined: null, isSkipped: null });
dataTable = createSpyWithStubs("data table", {raw: rows});
spyOn(prettyFormatter, "logIndented");
});
it("gets the rows from the table", function () {
- prettyFormatter.logDataTable(dataTable);
+ prettyFormatter.logDataTable(stepResult, dataTable);
expect(dataTable.raw).toHaveBeenCalled();
});
it("logs the lines with padding, indented by 3 levels", function () {
- prettyFormatter.logDataTable(dataTable);
+ prettyFormatter.logDataTable(stepResult, dataTable);
expect(prettyFormatter.logIndented).toHaveBeenCalledWith("| cuk | cuke | cukejs |\n", 3);
expect(prettyFormatter.logIndented).toHaveBeenCalledWith("| c | cuke | cuke.js |\n", 3);
expect(prettyFormatter.logIndented).toHaveBeenCalledWith("| cu | cuke | cucumber |\n", 3);
@@ -382,17 +404,18 @@ describe("Cucumber.Listener.PrettyFormatter", function () {
beforeEach(function () {
contents = "this is a multiline\ndoc string\n\n:-)";
+ stepResult = createSpyWithStubs("step result", { getStep: step, isFailed: null, isPending: null, isSuccessful: null, isUndefined: null, isSkipped: null });
docString = createSpyWithStubs("doc string", {getContents: contents});
spyOn(prettyFormatter, "logIndented");
});
it("gets the contents of the doc string", function () {
- prettyFormatter.logDocString(docString);
+ prettyFormatter.logDocString(stepResult, docString);
expect(docString.getContents).toHaveBeenCalled();
});
it("logs the contents of the doc string, with a 3-level indentation", function () {
- prettyFormatter.logDocString(docString);
+ prettyFormatter.logDocString(stepResult, docString);
expect(prettyFormatter.logIndented).toHaveBeenCalledWith('"""\n' + contents + '\n"""\n', 3);
});
});
View
8 spec/cucumber/listener/summary_formatter_spec.js
@@ -14,6 +14,7 @@ describe("Cucumber.Listener.SummaryFormatter", function () {
spyOn(Cucumber.Listener, 'Formatter').andReturn(formatter);
spyOn(Cucumber.Listener, 'StatsJournal').andReturn(statsJournal);
summaryFormatter = Cucumber.Listener.SummaryFormatter(options);
+ color = Cucumber.Util.ConsoleColor;
});
describe("constructor", function () {
@@ -992,13 +993,14 @@ describe("Cucumber.Listener.SummaryFormatter", function () {
var undefinedStepLogBuffer;
beforeEach(function () {
- undefinedStepLogBuffer = createSpy("undefined step log buffer");
+ // Undefined Step Log buffer is string
+ undefinedStepLogBuffer = 'undefinedStepsLogBuffer';
spyOn(summaryFormatter, 'getUndefinedStepLogBuffer').andReturn(undefinedStepLogBuffer);
});
it("logs a little explanation about the snippets", function () {
summaryFormatter.logUndefinedStepSnippets();
- expect(summaryFormatter.log).toHaveBeenCalledWith("\nYou can implement step definitions for undefined steps with these snippets:\n\n");
+ expect(summaryFormatter.log).toHaveBeenCalledWith(color.format('pending', "\nYou can implement step definitions for undefined steps with these snippets:\n\n"));
});
it("gets the undefined steps log buffer", function () {
@@ -1008,7 +1010,7 @@ describe("Cucumber.Listener.SummaryFormatter", function () {
it("logs the undefined steps", function () {
summaryFormatter.logUndefinedStepSnippets();
- expect(summaryFormatter.log).toHaveBeenCalledWith(undefinedStepLogBuffer);
+ expect(summaryFormatter.log).toHaveBeenCalledWith(color.format('pending', undefinedStepLogBuffer));
});
});
});

0 comments on commit 7dc33d4

Please sign in to comment.
Something went wrong with that request. Please try again.