diff --git a/README.md b/README.md index da43e090d..0d6abcc2b 100644 --- a/README.md +++ b/README.md @@ -375,6 +375,26 @@ $ ./node_modules/.bin/cucumber.js **Note to Windows users:** invoke Cucumber.js with `cucumber-js` instead of `cucumber.js`. The latter is causing the operating system to invoke JScript instead of Node.js, because of the so-called file extension. +#### Formatters + +Use --format to specify the formatter. + +``` shell +$ cucumber.js --format=json +``` + +Cucumber.js provides progress (the default), summary, JSON and pretty +formatters. + +You can also specify a custom formatter by providing the path to a file +implementing the formatter: + +``` shell +$ cucumber.js --format=/path/to/my_formatter.js +``` + +Paths should be absolute or relative to the current working directory. + ### Examples A few example apps are available for you to browse: diff --git a/lib/cucumber/cli.js b/lib/cucumber/cli.js index cfeea46aa..7c1d7cff5 100644 --- a/lib/cucumber/cli.js +++ b/lib/cucumber/cli.js @@ -65,6 +65,7 @@ function Cli(argv) { json : prints the feature as JSON\n\ summary : prints a summary only, after all\n\ scenarios were executed\n\ + filename: load custom formatter from filename\n\ \n\ -i, --no-snippets Don't print snippets for pending steps.\n\ \n\ diff --git a/lib/cucumber/cli/configuration.js b/lib/cucumber/cli/configuration.js index 40d4f189a..a29b929fb 100644 --- a/lib/cucumber/cli/configuration.js +++ b/lib/cucumber/cli/configuration.js @@ -1,6 +1,7 @@ function Configuration(argv) { var Cucumber = require('../../cucumber'); - + var path = require('path'); + var fs = require('fs'); var argumentParser = Cucumber.Cli.ArgumentParser(argv); argumentParser.parse(); @@ -23,7 +24,13 @@ function Configuration(argv) { formatter = Cucumber.Listener.SummaryFormatter(options); break; default: - throw new Error('Unknown formatter name "' + format + '".'); + var formatterPath = path.resolve(process.cwd(), format); + if (fs.existsSync(formatterPath)) { + var formatterFactory = require(formatterPath); + formatter = formatterFactory(options, Cucumber); + } else { + throw new Error('Unknown formatter name ' + format + '.'); + } } return formatter; }, diff --git a/spec/cucumber/cli/configuration_spec.js b/spec/cucumber/cli/configuration_spec.js index d9af6f1d9..f105b2fda 100644 --- a/spec/cucumber/cli/configuration_spec.js +++ b/spec/cucumber/cli/configuration_spec.js @@ -1,3 +1,6 @@ +var fs = require('fs'); +var path = require('path'); + require('../../support/spec_helper'); require('../../support/configurations_shared_examples.js'); @@ -145,6 +148,37 @@ describe("Cucumber.Cli.Configuration", function () { expect(configuration.getFormatter).toThrow(); }); }); + + describe("when the formatter name is foo_formatter.js", function () { + var formatter; + + beforeEach(function () { + fs.writeFileSync(path.join(process.cwd(), 'foo_formatter.js'), + 'module.exports = function FooFormatter(options, Cucumber) { return {isFooFormatter: true}; };'); + argumentParser.getFormat.andReturn("foo_formatter.js"); + spyOnStub(fs, 'existsSync').andReturn(true); + formatter = configuration.getFormatter(); + }); + + afterEach(function () { + fs.unlinkSync(path.join(process.cwd(), 'foo_formatter.js')); + }); + + it("should find file", function () { + expect(fs.existsSync.callCount).toBe(1); + }); + + it("should require foo_formatter.js and return a FooFormatter", function () { + expect(formatter.isFooFormatter).toBe(true); + }); + }); + + describe("when a custom formatter can not be found", function () { + it("should throw an exception", function () { + argumentParser.getFormat.andReturn("unknown_formatter.js"); + expect(configuration.getFormatter).toThrow(); + }); + }); }); diff --git a/spec/cucumber/cli_spec.js b/spec/cucumber/cli_spec.js index 088e6ec0d..d201f4dec 100644 --- a/spec/cucumber/cli_spec.js +++ b/spec/cucumber/cli_spec.js @@ -35,30 +35,25 @@ describe("Cucumber.Cli", function () { describe("when the help is requested", function () { beforeEach(function () { configuration.isHelpRequested.andReturn(true); + cli.run(callback); }); it("displays the help", function () { - cli.run(callback); expect(cli.displayHelp).toHaveBeenCalledWith(callback); }); it("does not run the suite", function () { - cli.run(callback); expect(cli.runSuiteWithConfiguration).not.toHaveBeenCalledWith(callback); }); it("does not display the version", function () { - cli.run(callback); expect(cli.displayVersion).not.toHaveBeenCalledWith(callback); }); }); describe("when the help is not requested", function () { - beforeEach(function () { - configuration.isHelpRequested.andReturn(false); - }); - it("checks whether the version is requested or not", function () { + configuration.isHelpRequested.andReturn(false); cli.run(callback); expect(configuration.isVersionRequested).toHaveBeenCalled(); }); @@ -66,20 +61,18 @@ describe("Cucumber.Cli", function () { describe("when the version is requested", function () { beforeEach(function () { configuration.isVersionRequested.andReturn(true); + cli.run(callback); }); it("displays the version", function () { - cli.run(callback); expect(cli.displayVersion).toHaveBeenCalledWith(callback); }); it("does not display the help", function () { - cli.run(callback); expect(cli.displayHelp).not.toHaveBeenCalled(); }); - it("does not run the suite", function () { - cli.run(callback); + it("does not run the suite", function() { expect(cli.runSuiteWithConfiguration).not.toHaveBeenCalled(); }); }); @@ -87,10 +80,10 @@ describe("Cucumber.Cli", function () { describe("when the version is not requested", function () { beforeEach(function () { configuration.isVersionRequested.andReturn(false); + cli.run(callback); }); it("runs the suite", function () { - cli.run(callback); expect(cli.runSuiteWithConfiguration).toHaveBeenCalledWith(configuration, callback); }); @@ -99,8 +92,15 @@ describe("Cucumber.Cli", function () { expect(cli.displayHelp).not.toHaveBeenCalled(); }); - it("does not display the version", function () { - cli.run(callback); + it("runs the suite", function() { + expect(cli.runSuiteWithConfiguration).toHaveBeenCalledWith(configuration, callback); + }); + + it("does not display the help", function() { + expect(cli.displayHelp).not.toHaveBeenCalled(); + }); + + it("does not display the version", function() { expect(cli.displayVersion).not.toHaveBeenCalledWith(callback); }); }); @@ -117,25 +117,22 @@ describe("Cucumber.Cli", function () { runtime = createSpyWithStubs("runtime", {start: null, attachListener: null}); callback = createSpy("callback"); spyOn(Cucumber, 'Runtime').andReturn(runtime); + cli.runSuiteWithConfiguration(configuration, callback); }); - it("creates a Cucumber runtime with the CLI configuration", function () { - cli.runSuiteWithConfiguration(configuration, callback); + it("creates a Cucumber runtime with the CLI configuration", function() { expect(Cucumber.Runtime).toHaveBeenCalledWith(configuration); }); - it("gets the formatter from the configuration", function () { - cli.runSuiteWithConfiguration(configuration, callback); + it("gets the formatter from the configuration", function() { expect(configuration.getFormatter).toHaveBeenCalled(); }); - it("attaches the formatter to the runtime", function () { - cli.runSuiteWithConfiguration(configuration, callback); + it("attaches the formatter to the runtime", function() { expect(runtime.attachListener).toHaveBeenCalledWith(formatter); }); - it("runs the runtime with the callback", function () { - cli.runSuiteWithConfiguration(configuration, callback); + it("runs the runtime with the callback", function() { expect(runtime.start).toHaveBeenCalledWith(callback); }); }); @@ -146,15 +143,14 @@ describe("Cucumber.Cli", function () { beforeEach(function () { callback = createSpy("callback"); spyOn(process.stdout, 'write'); + cli.displayVersion(callback); }); - it("outputs the version of Cucumber to STDOUT", function () { - cli.displayVersion(callback); + it("outputs the version of Cucumber to STDOUT", function() { expect(process.stdout.write).toHaveBeenCalledWith(Cucumber.VERSION + "\n"); }); - it("calls back and tells it succeeded", function () { - cli.displayVersion(callback); + it("calls back and tells it succeeded", function() { expect(callback).toHaveBeenCalledWith(true); }); }); @@ -165,15 +161,14 @@ describe("Cucumber.Cli", function () { beforeEach(function () { callback = createSpy("callback"); spyOn(process.stdout, 'write'); + cli.displayHelp(callback); }); - it("outputs the usage of Cucumber to STDOUT", function () { - cli.displayHelp(callback); + it("outputs the usage of Cucumber to STDOUT", function() { expect(process.stdout.write).toHaveBeenCalledWithStringMatching("Usage: cucumber.js "); }); - it("calls back and tells it succeeded", function () { - cli.displayHelp(callback); + it("calls back and tells it succeeded", function() { expect(callback).toHaveBeenCalledWith(true); }); });