From b32f16bc7a6af0fb1fb883859842d0146030a108 Mon Sep 17 00:00:00 2001 From: Renier Morales Date: Thu, 21 Jun 2012 21:38:57 -0400 Subject: [PATCH] Add colors to pretty formatter (#71) --- lib/cucumber/listener/formatter.js | 22 +++++ lib/cucumber/listener/pretty_formatter.js | 9 +- lib/cucumber/listener/summarizer.js | 87 ++++++++++--------- package.json | 5 +- .../listener/pretty_formatter_spec.js | 21 +++-- spec/cucumber/listener/summarizer_spec.js | 2 + 6 files changed, 91 insertions(+), 55 deletions(-) diff --git a/lib/cucumber/listener/formatter.js b/lib/cucumber/listener/formatter.js index d8950922f..52be46f60 100644 --- a/lib/cucumber/listener/formatter.js +++ b/lib/cucumber/listener/formatter.js @@ -22,6 +22,28 @@ var Formatter = function (options) { return logs; }; + self.colorize = function colorize(text, stepResult) { + var ansi_color = require('ansi-color'); + if (stepResult.isFailed()) { + return ansi_color.set(text, Formatter.FAILED_COLOR); + } else if (stepResult.isSkipped()) { + return ansi_color.set(text, Formatter.SKIPPED_COLOR); + } else if (stepResult.isPending()) { + return ansi_color.set(text, Formatter.PENDING_COLOR); + } else if (stepResult.isUndefined()) { + return ansi_color.set(text, Formatter.UNDEFINED_COLOR); + } else if (stepResult.isSuccessful()) { + return ansi_color.set(text, Formatter.SUCCESSFUL_COLOR); + } + + return text; + }; + return self; }; +Formatter.FAILED_COLOR = "red"; +Formatter.SUCCESSFUL_COLOR = "green"; +Formatter.PENDING_COLOR = "yellow"; +Formatter.UNDEFINED_COLOR = "yellow"; +Formatter.SKIPPED_COLOR = "cyan"; module.exports = Formatter; diff --git a/lib/cucumber/listener/pretty_formatter.js b/lib/cucumber/listener/pretty_formatter.js index d1eb469de..d58fe9812 100644 --- a/lib/cucumber/listener/pretty_formatter.js +++ b/lib/cucumber/listener/pretty_formatter.js @@ -1,8 +1,8 @@ var PrettyFormatter = function(options) { - var Cucumber = require('../../cucumber'); + var Cucumber = require('../../cucumber'); var self = Cucumber.Listener.Formatter(options); - var summarizer = Cucumber.Listener.Summarizer(); + var summarizer = Cucumber.Listener.Summarizer({ colors: true }); var parentHear = self.hear; self.hear = function hear(event, callback) { @@ -33,13 +33,12 @@ var PrettyFormatter = function(options) { self.handleStepResultEvent = function handleStepResult(event, callback) { var stepResult = event.getPayloadItem('stepResult'); var step = stepResult.getStep(); - var source = step.getKeyword() + step.getName() + "\n"; + var source = self.colorize(step.getKeyword() + step.getName(), stepResult) + "\n"; self.logIndented(source, 2); - stepResult.isFailed(); if (stepResult.isFailed()) { var failure = stepResult.getFailureException(); - var failureDescription = failure.stack || failure; + var failureDescription = self.colorize(failure.stack || failure, stepResult); self.logIndented(failureDescription + "\n", 3); } callback(); diff --git a/lib/cucumber/listener/summarizer.js b/lib/cucumber/listener/summarizer.js index ac08144ae..0646d4087 100644 --- a/lib/cucumber/listener/summarizer.js +++ b/lib/cucumber/listener/summarizer.js @@ -1,4 +1,4 @@ -var Summarizer = function () { +var Summarizer = function (options) { var Cucumber = require('../../cucumber'); var logs = ""; @@ -6,10 +6,21 @@ var Summarizer = function () { var undefinedStepLogBuffer = ""; var failedStepResults = Cucumber.Type.Collection(); var statsJournal = Cucumber.Listener.StatsJournal(); + var Formatter = Cucumber.Listener.Formatter; var self = Cucumber.Listener(); var parentHear = self.hear; + + var addStyleToText = function addStyleToText(text, color) { + var ansi_color; + if (options && options.colors) { + ansi_color = require('ansi-color'); + return ansi_color.set(text, color); + } + return text; + }; + self.hear = function hear(event, callback) { statsJournal.hear(event, function () { parentHear(event, callback); @@ -101,7 +112,8 @@ var Summarizer = function () { }; self.logFailedStepResults = function logFailedStepResults() { - self.log("(::) failed steps (::)\n\n"); + var banner = "(::) failed steps (::)"; + self.log(banner + "\n\n"); failedStepResults.syncForEach(function(stepResult) { self.logFailedStepResult(stepResult); }); @@ -117,53 +129,42 @@ var Summarizer = function () { self.log("\n\n"); }; - self.logScenariosSummary = function logScenariosSummary() { - var scenarioCount = statsJournal.getScenarioCount(); - var passedScenarioCount = statsJournal.getPassedScenarioCount(); - var undefinedScenarioCount = statsJournal.getUndefinedScenarioCount(); - var pendingScenarioCount = statsJournal.getPendingScenarioCount(); - var failedScenarioCount = statsJournal.getFailedScenarioCount(); - var details = []; - - self.log(scenarioCount + " scenario" + (scenarioCount != 1 ? "s" : "")); - if (scenarioCount > 0 ) { - if (failedScenarioCount > 0) - details.push(failedScenarioCount + " failed"); - if (undefinedScenarioCount > 0) - details.push(undefinedScenarioCount + " undefined"); - if (pendingScenarioCount > 0) - details.push(pendingScenarioCount + " pending"); - if (passedScenarioCount > 0) - details.push(passedScenarioCount + " passed"); + function logSummaryHelper(noun) { + var suffix = " " + noun.toLowerCase(); + var count = statsJournal["get"+noun+"Count"](); + var passedCount = statsJournal["getPassed"+noun+"Count"](); + var undefinedCount = statsJournal["getUndefined"+noun+"Count"](); + var pendingCount = statsJournal["getPending"+noun+"Count"](); + var failedCount = statsJournal["getFailed"+noun+"Count"](); + var skippedCount = 0; + var details = []; + + if (statsJournal["getSkipped"+noun+"Count"]) + skippedCount = statsJournal["getSkipped"+noun+"Count"](); + + self.log(count + suffix + (count != 1 ? "s" : "")); + if (count > 0 ) { + if (failedCount > 0) + details.push(addStyleToText(failedCount + " failed", Formatter.FAILED_COLOR)); + if (undefinedCount > 0) + details.push(addStyleToText(undefinedCount + " undefined", Formatter.UNDEFINED_COLOR)); + if (pendingCount > 0) + details.push(addStyleToText(pendingCount + " pending", Formatter.PENDING_COLOR)); + if (skippedCount > 0) + details.push(addStyleToText(skippedCount + " skipped", Formatter.SKIPPED_COLOR)); + if (passedCount > 0) + details.push(addStyleToText(passedCount + " passed", Formatter.SUCCESSFUL_COLOR)); self.log(" (" + details.join(', ') + ")"); } self.log("\n"); + } + + self.logScenariosSummary = function logScenariosSummary() { + logSummaryHelper("Scenario"); }; self.logStepsSummary = function logStepsSummary() { - var stepCount = statsJournal.getStepCount(); - var passedStepCount = statsJournal.getPassedStepCount(); - var undefinedStepCount = statsJournal.getUndefinedStepCount(); - var skippedStepCount = statsJournal.getSkippedStepCount(); - var pendingStepCount = statsJournal.getPendingStepCount(); - var failedStepCount = statsJournal.getFailedStepCount(); - var details = []; - - self.log(stepCount + " step" + (stepCount != 1 ? "s" : "")); - if (stepCount > 0) { - if (failedStepCount > 0) - details.push(failedStepCount + " failed"); - if (undefinedStepCount > 0) - details.push(undefinedStepCount + " undefined"); - if (pendingStepCount > 0) - details.push(pendingStepCount + " pending"); - if (skippedStepCount > 0) - details.push(skippedStepCount + " skipped"); - if (passedStepCount > 0) - details.push(passedStepCount + " passed"); - self.log(" (" + details.join(', ') + ")"); - } - self.log("\n"); + logSummaryHelper("Step"); }; self.logUndefinedStepSnippets = function logUndefinedStepSnippets() { diff --git a/package.json b/package.json index c44374430..0009a4438 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "Olivier Melcher ", "Tristan Dunn ", "Ted de Koning", - "@renier", + "Renier Morales ", "Aslak Hellesøy ", "Aaron Garvey" ], @@ -49,7 +49,8 @@ "mkdirp": "0.3.3", "cucumber-html": "0.2.0", "walkdir": "0.0.4", - "coffee-script": "1.3.3" + "coffee-script": "1.3.3", + "ansi-color": "0.2.1" }, "scripts": { "test": "./bin/cucumber.js && jasmine-node spec" diff --git a/spec/cucumber/listener/pretty_formatter_spec.js b/spec/cucumber/listener/pretty_formatter_spec.js index bea828d1a..827fe3069 100644 --- a/spec/cucumber/listener/pretty_formatter_spec.js +++ b/spec/cucumber/listener/pretty_formatter_spec.js @@ -5,8 +5,10 @@ describe("Cucumber.Listener.PrettyFormatter", function () { var formatter, formatterHearMethod, summarizer, prettyFormatter, options; beforeEach(function () { + var Formatter = Cucumber.Listener.Formatter; options = createSpy(options); formatter = createSpyWithStubs("formatter", {log: null}); + formatter.colorize = Formatter().colorize; formatterHearMethod = spyOnStub(formatter, 'hear'); summarizer = createSpy("summarizer"); spyOn(Cucumber.Listener, 'Formatter').andReturn(formatter); @@ -162,7 +164,8 @@ describe("Cucumber.Listener.PrettyFormatter", function () { keyword = "step-keyword "; name = "step-name"; step = createSpyWithStubs("step", { getKeyword: keyword, getName: name }); - stepResult = createSpyWithStubs("step result", { getStep: step, isFailed: null }); + stepResult = createSpyWithStubs("step result", { + getStep: step, isFailed: null, isSkipped: null, isSuccessful: null, isPending: null, isUndefined: null }); event = createSpyWithStubs("event", { getPayloadItem: stepResult }); spyOn(prettyFormatter, 'logIndented'); callback = createSpy("callback"); @@ -215,18 +218,26 @@ describe("Cucumber.Listener.PrettyFormatter", function () { it("logs the failure stack when there is one, indented by three levels", function () { var stack = "failure stack"; - var text = stack + "\n"; + var text = formatter.colorize(stack, stepResult) + "\n"; exception.stack = stack; prettyFormatter.handleStepResultEvent(event, callback); - expect(prettyFormatter.logIndented).toHaveBeenCalledWith(text, 3); + //expect(prettyFormatter.logIndented).toHaveBeenCalledWith(text, 3); + // logIndented being called twice + expect(prettyFormatter.logIndented.mostRecentCall.args.length).toBe(2); + expect(prettyFormatter.logIndented.mostRecentCall.args[0]).toBe(text); + expect(prettyFormatter.logIndented.mostRecentCall.args[1]).toBe(3); }); it("logs the failure itself when there no stack, indented by three levels", function () { exception = "exception text"; - var text = exception + "\n"; + var text = formatter.colorize(exception, stepResult) + "\n"; stepResult.getFailureException.andReturn(exception); prettyFormatter.handleStepResultEvent(event, callback); - expect(prettyFormatter.logIndented).toHaveBeenCalledWith(text, 3); + //expect(prettyFormatter.logIndented).toHaveBeenCalledWith(text, 3); + // logIndented being called twice + expect(prettyFormatter.logIndented.mostRecentCall.args.length).toBe(2); + expect(prettyFormatter.logIndented.mostRecentCall.args[0]).toBe(text); + expect(prettyFormatter.logIndented.mostRecentCall.args[1]).toBe(3); }); }); diff --git a/spec/cucumber/listener/summarizer_spec.js b/spec/cucumber/listener/summarizer_spec.js index f35785abc..4b735fdab 100644 --- a/spec/cucumber/listener/summarizer_spec.js +++ b/spec/cucumber/listener/summarizer_spec.js @@ -6,6 +6,7 @@ describe("Cucumber.Listener.Summarizer", function () { beforeEach(function () { var Summarizer = Cucumber.Listener.Summarizer; + var Formatter = Cucumber.Listener.Formatter; listener = createSpyWithStubs("listener"); listenerHearMethod = spyOnStub(listener, 'hear'); statsJournal = createSpy("stats journal"); @@ -14,6 +15,7 @@ describe("Cucumber.Listener.Summarizer", function () { spyOn(Cucumber, 'Listener').andReturn(listener); spyOnStub(Cucumber.Listener, 'StatsJournal').andReturn(statsJournal); Cucumber.Listener.Summarizer = Summarizer; + Cucumber.Listener.Formatter = Formatter; summarizer = Cucumber.Listener.Summarizer(); });