Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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
  • Loading branch information...
commit 44c67571c5c7f60e9ff76a1e60f8400580b241db 2 parents 0411c18 + 53c3501
@jbpros jbpros authored
Showing with 893 additions and 385 deletions.
  1. +15 −6 .travis.yml
  2. +1 −2  CONTRIBUTE.md
  3. +52 −1 History.md
  4. +1 −1  LICENSE
  5. +25 −20 README.md
  6. +24 −1 features/json_formatter.feature
  7. +10 −0 features/pogoscript_support.feature
  8. +24 −6 features/step_definitions/cli_steps.js
  9. +28 −13 features/step_definitions/cucumber_js_mappings.rb
  10. +16 −56 features/step_definitions/cucumber_steps.js
  11. +4 −0 features/step_definitions/cucumber_steps.rb
  12. +89 −0 features/step_definitions/cucumber_world.js
  13. +1 −1  lib/cucumber.js
  14. +1 −1  lib/cucumber/cli.js
  15. +5 −5 lib/cucumber/cli/argument_parser.js
  16. +3 −2 lib/cucumber/cli/argument_parser/support_code_path_expander.js
  17. +11 −5 lib/cucumber/listener.js
  18. +10 −0 lib/cucumber/listener/events.js
  19. +2 −0  lib/cucumber/listener/json_formatter.js
  20. +13 −5 lib/cucumber/runtime/ast_tree_walker.js
  21. +4 −0 lib/cucumber/runtime/step_result.js
  22. +7 −7 lib/cucumber/support_code.js
  23. +46 −8 lib/cucumber/support_code/library.js
  24. +25 −2 lib/cucumber/support_code/step_definition.js
  25. +7 −8 lib/cucumber/support_code/step_definition_snippet_builder_syntax.js
  26. +22 −13 package.json
  27. +5 −0 spec/cucumber/cli/argument_parser/support_code_path_expander_spec.js
  28. +20 −0 spec/cucumber/listener/events_spec.js
  29. +10 −2 spec/cucumber/listener/json_formatter_spec.js
  30. +35 −3 spec/cucumber/listener_spec.js
  31. +23 −7 spec/cucumber/runtime/ast_tree_walker_spec.js
  32. +1 −1  spec/cucumber/runtime/failed_step_result_spec.js
  33. +7 −1 spec/cucumber/runtime/step_result_spec.js
  34. +1 −1  spec/cucumber/runtime/successful_step_result_spec.js
  35. +308 −202 spec/cucumber/support_code/library_spec.js
  36. +1 −0  spec/cucumber/support_code/step_definition_snippet_builder_spec.js
  37. +3 −3 spec/cucumber/support_code/step_definition_snippet_builder_syntax_spec.js
  38. +33 −2 spec/cucumber/support_code/step_definition_spec.js
View
21 .travis.yml
@@ -1,14 +1,23 @@
rvm: "1.9.2"
-before_script: "git submodule update --init && npm install"
+before_install:
+ - ruby --version
+ - gem --version
+ - rvm --version
+ - bundle install
+
script: "rake"
+language: node_js
+
node_js:
- - 0.6
- - 0.8
+ - "0.11"
+ - "0.10"
+ - "0.8"
+ - "0.6"
-branches:
- only:
- - master
+matrix:
+ allow_failures:
+ - node_js: "0.11"
notifications:
email:
View
3  CONTRIBUTE.md
@@ -108,7 +108,6 @@ This a reminder of the steps maintainers have to follow to release a new version
* Add new contributors to `package.json`, if any
* Commit those changes as "*Release 0.1.2*" (where *0.1.2* is the actual version, of course)
* Tag commit as "v0.1.2" with short description of main changes
-* Push to main repo on Github
+* Push to main repo on GitHub
* Wait for build to go green
* Publish to NPM
-* Deploy to cucumber.no.de
View
53 History.md
@@ -2,11 +2,62 @@
## [v0.3.x](https://github.com/cucumber/cucumber-js/compare/v0.3.0...master)
-### [master (unreleased)](https://github.com/cucumber/cucumber-js/compare/v0.3.0...master)
+### [master (unreleased)](https://github.com/cucumber/cucumber-js/compare/v0.3.2...master)
**TBD**
+### [v0.3.2](https://github.com/cucumber/cucumber-js/compare/v0.3.1...v0.3.2)
+
+#### New features
+
+* Add PogoScript support (Josh Chisholm)
+* Add listener and event handler registration (close #130) (Paul Shannon)
+
+#### Documentation, internals and tests
+
+* Added some nice stats (Aslak Hellesøy)
+* Fix spelling of "GitHub" (Peter Suschlik)
+* Add Code Climate badge to README (Julien Biezemans)
+* Update README.md (Sebastian Schürmann)
+
+### [v0.3.1](https://github.com/cucumber/cucumber-js/compare/v0.3.0...v0.3.1)
+
+#### New features
+
+* Add DataTable.rows() (Niklas Närhinen)
+* Officially support Node 0.10 and 0.11 (Julien Biezemans)
+
+#### Changed features
+
+* Update cucumber-html (Aslak Hellesøy)
+* Bump Gherkin (Julien Biezemans)
+* Add options parameter to JSON formatter (Israël Hallé)
+* Updated CoffeeScript (Matteo Collina)
+* Specify strict coffee-script version number (Julien Biezemans)
+* Bump jasmine-node (Julien Biezemans)
+
+#### Fixes
+
+* Fix travis build Node versions (Julien Biezemans)
+* Fix Travis CI configuration (Julien Biezemans)
+
+#### Documentation, internals and tests
+
+* Remove words in History (Julien Biezemans)
+* Update dev status table in README (Julien Biezemans)
+* Update LICENSE (Julien Biezemans)
+* Add contributors (Julien Biezemans)
+* Move data table scenario to TCK (Julien Biezemans)
+* Be consistent in spec matchers (Julien Biezemans)
+* Remove cucumber.no.de links (Kim, Jang-hwan)
+* Fix broken link in README dev status table (#118) (Michael Zedeler)
+* Refactor hook-related Given steps in JS stepdefs (Julien Biezemans)
+* Refactor failing mapping JS step definitions (Julien Biezemans & Matt Wynne)
+* Update README.md to correct error in example for zombie initialization (Tom V)
+* Update minor typos in README.md (David Godfrey)
+
+
### [v0.3.0](https://github.com/cucumber/cucumber-js/compare/v0.2.22...v0.3.0)
View
2  LICENSE
@@ -1,6 +1,6 @@
The MIT License
-Copyright (c) 2011, 2012 Julien Biezemans and contributors
+Copyright (c) 2011-2013 Julien Biezemans and contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
View
45 README.md
@@ -1,11 +1,15 @@
-# Cucumber.js [![Build Status](https://secure.travis-ci.org/cucumber/cucumber-js.png?branch=master)](http://travis-ci.org/cucumber/cucumber-js)
+# Cucumber.js
+ [![Build Status](https://secure.travis-ci.org/cucumber/cucumber-js.png?branch=master)](http://travis-ci.org/cucumber/cucumber-js)
+ [![Dependencies](https://david-dm.org/cucumber/cucumber-js.png)](https://david-dm.org/cucumber/cucumber-js) [![Code Climate](https://codeclimate.com/github/cucumber/cucumber-js.png)](https://codeclimate.com/github/cucumber/cucumber-js)
+
+[![NPM](https://nodei.co/npm/cucumber.png?stars&downloads)](https://nodei.co/npm/cucumber/)
+[![NPM](https://nodei.co/npm-dl/cucumber.png)](https://nodei.co/npm/cucumber/)
+
*Cucumber*, the [popular Behaviour-Driven Development tool](http://cukes.info), brought to your JavaScript stack.
It runs on both Node.js and *modern* web browsers.
-**Try it now: [http://cucumber.no.de](http://cucumber.no.de)!**
-
## Development status
Cucumber.js is still a work in progress. Here is its current status.
@@ -121,7 +125,7 @@ Cucumber.js is still a work in progress. Here is its current status.
<td>Done</td>
</tr>
<tr>
- <td><a href="https://github.com/cucumber/cucumber-js/blob/master/features/cli.featur">Command-line interface</a></td>
+ <td><a href="https://github.com/cucumber/cucumber-js/blob/master/features/cli.feature">Command-line interface</a></td>
<td>Done</td>
</tr>
</tbody>
@@ -136,7 +140,7 @@ Cucumber.js is still a work in progress. Here is its current status.
Cucumber.js is tested on:
-* Node.js 0.6 and 0.8 (see [CI builds](http://travis-ci.org/#!/cucumber/cucumber-js))
+* Node.js 0.6, 0.8 and 0.10.0 (see [CI builds](http://travis-ci.org/#!/cucumber/cucumber-js))
* Google Chrome
* Firefox
* Safari
@@ -185,7 +189,7 @@ Feature: Example feature
So that I can concentrate on building awesome applications
Scenario: Reading documentation
- Given I am on the Cucumber.js Github repository
+ Given I am on the Cucumber.js GitHub repository
When I go to the README file
Then I should see "Usage" as the page title
```
@@ -203,7 +207,7 @@ Support files let you setup the environment in which steps will be run, and defi
var zombie = require('zombie');
var World = function World(callback) {
- this.browser = new zombie.Browser(); // this.browser will be available in step definitions
+ this.browser = new zombie(); // this.browser will be available in step definitions
this.visit = function(url, callback) {
this.browser.visit(url, callback);
@@ -221,7 +225,7 @@ It is possible to tell Cucumber to use another object instance than the construc
var zombie = require('zombie');
var WorldConstructor = function WorldConstructor(callback) {
- this.browser = new zombie.Browser(); // this.browser will be available in step definitions
+ this.browser = new zombie(); // this.browser will be available in step definitions
var world = {
visit: function(url, callback) {
@@ -252,7 +256,7 @@ Step definitions are run when steps match their name. `this` is an instance of `
var myStepDefinitionsWrapper = function () {
this.World = require("../support/world.js").World; // overwrite default World constructor
- this.Given(/^I am on the Cucumber.js Github repository$/, function(callback) {
+ this.Given(/^I am on the Cucumber.js GitHub repository$/, function(callback) {
// Express the regexp above with the code you wish you had.
// `this` is set to a new this.World instance.
// i.e. you may use this.browser to execute the step:
@@ -273,11 +277,12 @@ var myStepDefinitionsWrapper = function () {
this.Then(/^I should see "(.*)" as the page title$/, function(title, callback) {
// matching groups are passed as parameters to the step definition
- if (!this.isOnPageWithTitle(title))
- // You can make steps fail by calling the `fail()` function on the callback:
- callback.fail(new Error("Expected to be on page with title " + title));
- else
+ var pageTitle = this.browser.text('title');
+ if (title === pageTitle) {
callback();
+ } else {
+ callback.fail(new Error("Expected to be on page with title " + title));
+ }
});
};
@@ -291,15 +296,16 @@ this.Then('I should see "$title" as the page title', function(title, callback) {
// the above string is converted to the following Regexp by Cucumber:
// /^I should see "([^"]*)" as the page title$/
- if (!this.isOnPageWithTitle(title))
- // You can make steps fail by calling the `fail()` function on the callback:
- callback.fail(new Error("Expected to be on page with title " + title));
- else
+ var pageTitle = this.browser.text('title');
+ if (title === pageTitle) {
callback();
+ } else {
+ callback.fail(new Error("Expected to be on page with title " + title));
+ }
});
```
-`'I have $count "$string"'` would translate to `/^I have (.*) "([^"]*)")$/`.
+`'I have $count "$string"'` would translate to `/^I have (.*) "([^"]*)"$/`.
#### Hooks
@@ -360,7 +366,7 @@ module.exports = myAfterHooks;
##### Around hooks
-It's also possible to combine both before and around hooks in one single definition with the help of *around hooks*:
+It's also possible to combine both before and after hooks in one single definition with the help of *around hooks*:
```javascript
// features/support/advanced_hooks.js
@@ -449,7 +455,6 @@ A few example apps are available for you to browse:
* [Rails app serving features in the browser](https://github.com/jbpros/cucumber-js-example)
* [Express.js app running features in the cli](https://github.com/olivoil/NodeBDD)
-* [Try cucumber.js in the browser](http://cucumber.no.de/)
## Contribute
View
25 features/json_formatter.feature
@@ -257,6 +257,7 @@ Feature: JSON Formatter
"keyword": "Given ",
"result": {
"error_message": "<error-message>",
+ "duration": "<duration>",
"status": "failed"
},
"match": {
@@ -309,6 +310,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {
@@ -365,6 +367,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -513,6 +516,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {
@@ -534,6 +538,7 @@ Feature: JSON Formatter
"keyword": "Given ",
"result": {
"error_message": "<error-message>",
+ "duration": "<duration>",
"status": "failed"
},
"match": {
@@ -599,6 +604,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {
@@ -629,6 +635,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -658,6 +665,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -740,6 +748,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {
@@ -760,6 +769,7 @@ Feature: JSON Formatter
"line": 7,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -779,6 +789,7 @@ Feature: JSON Formatter
"line": 10,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -808,6 +819,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -827,6 +839,7 @@ Feature: JSON Formatter
"line": 7,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -846,6 +859,7 @@ Feature: JSON Formatter
"line": 10,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -875,6 +889,7 @@ Feature: JSON Formatter
"line": 4,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -894,6 +909,7 @@ Feature: JSON Formatter
"line": 7,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -913,6 +929,7 @@ Feature: JSON Formatter
"line": 10,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -1074,6 +1091,7 @@ Feature: JSON Formatter
"content_type": ""
},
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -1194,6 +1212,7 @@ Feature: JSON Formatter
"line": 5,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -1260,6 +1279,7 @@ Feature: JSON Formatter
"line": 5,
"keyword": "Given ",
"result": {
+ "duration": "<duration>",
"status": "passed"
},
"match": {}
@@ -1323,7 +1343,10 @@ Feature: JSON Formatter
{ "cells": ["1", "2", "3"] },
{ "cells": ["!", "~", "@"] }
],
- "result": { "status": "passed" },
+ "result": {
+ "duration": "<duration>",
+ "status": "passed"
+ },
"match": {}
}
]
View
10 features/pogoscript_support.feature
@@ -0,0 +1,10 @@
+Feature: PogoScript support
+ In order to use the JS dialect that totally rocks
+ As a step definition implementor
+ I want to use PogoScript for writing step definitions
+
+ Scenario: PogoScript step definition
+ Given a mapping written in PogoScript
+ When Cucumber executes a scenario using that mapping
+ Then the feature passes
+ And the mapping is run
View
30 features/step_definitions/cli_steps.js
@@ -79,19 +79,18 @@ var cliSteps = function cliSteps() {
var actualError = lastRun['error'];
var actualStderr = lastRun['stderr'];
+ expectedOutput = expectedOutput.replace(/<current-directory>/g, tmpDir);
+
try { var actualJson = JSON.parse(actualOutput); }
catch(err) { throw new Error("Error parsing actual JSON:\n" + actualOutput); }
- var errorMessageSubstitute = "Random error message #" + Math.floor(Math.random() * 100000);
- expectedOutput = expectedOutput.replace(/<current-directory>/g, tmpDir);
- expectedOutput = expectedOutput.replace(/<error-message>/g, errorMessageSubstitute);
-
try { var expectedJson = JSON.parse(expectedOutput); }
catch(err) { throw new Error("Error parsing expected JSON:\n" + expectedOutput); }
- var actualJsonString = JSON.stringify(actualJson, null, 2);
- actualJsonString = actualJsonString.replace(/("error_message": ")(.+)(",)/g, "$1"+errorMessageSubstitute+"$3");
+ neutraliseVariableValuesInJson(actualJson);
+ neutraliseVariableValuesInJson(expectedJson);
+ var actualJsonString = JSON.stringify(actualJson, null, 2);
var expectedJsonString = JSON.stringify(expectedJson, null, 2);
if (actualJsonString != expectedJsonString)
@@ -118,4 +117,23 @@ var cliSteps = function cliSteps() {
callback();
});
};
+
+var neutraliseVariableValuesInJson = function neutraliseVariableValuesInJson(report) {
+ report.forEach(function (item) {
+ (item.elements || []).forEach(function (element) {
+ (element['steps'] || []).forEach(function (step) {
+ if ('result' in step) {
+ if ('error_message' in step.result) {
+ step.result.error_message = "<error-message>";
+ }
+
+ if ('duration' in step.result) {
+ step.result.duration = "<duration>";
+ }
+ }
+ });
+ });
+ });
+};
+
module.exports = cliSteps;
View
41 features/step_definitions/cucumber_js_mappings.rb
@@ -1,6 +1,7 @@
module CucumberJsMappings
STEP_DEFINITIONS_FILE = "features/step_definitions/cucumber_steps.js"
COFFEE_SCRIPT_DEFINITIONS_FILE = "features/step_definitions/cucumber_steps.coffee"
+ POGO_SCRIPT_DEFINITIONS_FILE = "features/step_definitions/cucumber_steps.pogo"
FEATURE_FILE = "features/a_feature.feature"
WORLD_VARIABLE_LOG_FILE = "world_variable.log"
WORLD_FUNCTION_LOG_FILE = "world_function.log"
@@ -317,9 +318,13 @@ def assert_passed_with_arguments(pattern, arguments)
def assert_json_output(expected)
expected.gsub!(/<current-directory>/, File.join(Dir.pwd, current_dir))
- expected = JSON(expected).to_s
+ expected = JSON(expected)
actual = JSON(all_output)
- neutralise_error_messages_in_enumerable actual
+
+ neutralise_variable_values_in_json expected
+ neutralise_variable_values_in_json actual
+
+ expected = expected.to_s
actual = actual.to_s
actual.should == expected
end
@@ -365,6 +370,19 @@ def write_coffee_script_definition_file
module.exports = stepDefinitions
EOF
end
+
+ def write_pogo_script_definition_file
+ @mapping_name = "a PogoScript mapping"
+ append_to_file POGO_SCRIPT_DEFINITIONS_FILE, <<-EOF
+fs = require('fs')
+step definitions () =
+ this.define step r/^#{@mapping_name}$/ @(callback)
+ fs.write file sync ('#{step_file(@mapping_name)}', '')
+ callback()
+
+module.exports = step definitions
+EOF
+ end
def write_string_based_pattern_mapping
@mapping_name = "a mapping + fancy characters"
@@ -397,17 +415,14 @@ def nth_step_name n
"step #{n}"
end
- def neutralise_error_messages_in_enumerable enumerable
- if enumerable.is_a? Array
- enumerable.each do |item|
- neutralise_error_messages_in_enumerable item if item.respond_to? :each
- end
- else
- enumerable.each do |attr, value|
- if attr == "error_message"
- enumerable[attr] = "<error-message>"
- elsif value.respond_to? :each
- neutralise_error_messages_in_enumerable value
+ def neutralise_variable_values_in_json json
+ json.each do |item|
+ (item['elements'] || []).each do |element|
+ (element['steps'] || []).each do |step|
+ if step.include? 'result'
+ step['result']['error_message'] = "<error-message>" if step['result'].include? 'error_message'
+ step['result']['duration'] = "<duration>" if step['result'].include? 'duration'
+ end
end
end
end
View
72 features/step_definitions/cucumber_steps.js
@@ -4,81 +4,41 @@ var cucumberSteps = function() {
this.World = World;
Given(/^a scenario with:$/, function(steps, callback) {
- this.featureSource += "Feature: A feature\n";
- this.featureSource += " Scenario: A scenario\n";
- this.featureSource += steps.replace(/^/gm, ' ');
+ this.addScenario("A scenario", steps);
callback();
});
Given(/^the step "([^"]*)" has a passing mapping$/, function(stepName, callback) {
- this.stepDefinitions += "Given(/^" + stepName + "$/, function(callback) {\
- world.touchStep(\"" + stepName + "\");\
- callback();\
-});\n";
- callback();
+ this.addPassingStepDefinitionWithName(stepName, callback);
});
- Given(/^a passing (before|after) hook$/, function(hookType, callback) {
- var defineHook = (hookType == 'before' ? 'Before' : 'After');
- this.stepDefinitions += defineHook + "(function(callback) {\
- world.logCycleEvent('" + hookType + "');\
- callback();\
-});\n";
- callback();
- });
-
- Given(/^a passing around hook$/, function(callback) {
- this.stepDefinitions += "Around(function(runScenario) {\
- world.logCycleEvent('around-pre');\
- runScenario(function(callback) {\
- world.logCycleEvent('around-post');\
- callback();\
- });\
-});\n";
- callback();
+ Given(/^a passing (before|after|around) hook$/, function(hookType, callback) {
+ if (hookType == "before")
+ this.addBeforeHook(callback);
+ else if (hookType == "after")
+ this.addAfterHook(callback);
+ else
+ this.addAroundHook(callback);
});
Given(/^an untagged hook$/, function(callback) {
- this.stepDefinitions += "Before(function(callback) {\
- world.logCycleEvent('hook');\
- callback();\
-});\n";
- callback();
+ this.addUntaggedHook(callback);
});
- Given(/^a hook tagged with "([^"]*)"$/, function(tag, callback) {
- this.stepDefinitions += "Before('" + tag +"', function(callback) {\
- world.logCycleEvent('hook');\
- callback();\
-});\n";
- callback();
+ Given(/^a hook tagged with "([^"]*)"$/, function(tags, callback) {
+ this.addHookWithTags(tags, callback);
});
- Given(/^an around hook tagged with "([^"]*)"$/, function(tag, callback) {
- this.stepDefinitions += "Around('" + tag + "', function(runScenario) {\
- world.logCycleEvent('hook-pre');\
- runScenario(function(callback) {\
- world.logCycleEvent('hook-post');\
- callback();\
- });\
-});\n";
- callback();
+ Given(/^an around hook tagged with "([^"]*)"$/, function(tags, callback) {
+ this.addAroundHookWithTags(tags, callback);
});
Given(/^the step "([^"]*)" has a failing mapping$/, function(stepName, callback) {
- this.stepDefinitions += "Given(/^" + stepName + "$/, function(callback) {\
- world.touchStep(\"" + stepName + "\");\
- throw(new Error('I was supposed to fail.'));\
-});\n";
- callback();
+ this.addFailingMapping(stepName, {}, callback);
});
Given(/^the step "([^"]*)" has a mapping failing with the message "([^"]*)"$/, function(stepName, message, callback) {
- this.stepDefinitions += "Given(/^" + stepName + "$/, function(callback) {\
- world.touchStep(\"" + stepName + "\");\
- throw(new Error('" + message + "'));\
-});\n";
- callback();
+ this.addFailingMapping(stepName, { message: message }, callback);
});
Given(/^the step "([^"]*)" has a mapping asynchronously failing with the message "([^"]*)"$/, function(stepName, message, callback) {
View
4 features/step_definitions/cucumber_steps.rb
@@ -5,6 +5,10 @@
write_coffee_script_definition_file
end
+Given /^a mapping written in PogoScript$/ do
+ write_pogo_script_definition_file
+end
+
Given /^a mapping with a string-based pattern$/ do
write_string_based_pattern_mapping
end
View
89 features/step_definitions/cucumber_world.js
@@ -140,6 +140,87 @@ proto.addPassingScenarioWithoutTags = function addPassingScenarioWithoutTags() {
this.addPassingScenarioWithTags();
};
+proto.addBeforeHook = function (callback) {
+ this._addHook({ type: "before" }, callback);
+};
+
+proto.addAfterHook = function (callback) {
+ this._addHook({ type: "after" }, callback);
+};
+
+proto.addAroundHook = function (callback) {
+ this._addAroundHook(callback);
+};
+
+proto.addAroundHookWithTags = function (tags, callback) {
+ this._addAroundHook({ tags: tags, logEvent: "hook" }, callback);
+};
+
+proto.addUntaggedHook = function (callback) {
+ this._addHook({ type: "before", logEvent: "hook" }, callback);
+};
+
+proto.addHookWithTags = function (tags, callback) {
+ this._addHook({ type: "before", logEvent: "hook", tags: tags }, callback);
+};
+
+proto._addHook = function (options, callback) {
+ if (!callback) {
+ callback = options;
+ options = {};
+ }
+ var type = "before";
+ var tags = "";
+ if (options.type) type = options.type;
+ if (!options.logEvent) options.logEvent = type;
+ if (options.tags) tags = '"' + options.tags + '", ';
+ var defineHook = (type == 'before' ? 'Before' : 'After');
+ this.stepDefinitions += defineHook + "(" + tags + "function(callback) {\
+ world.logCycleEvent('" + options.logEvent + "');\
+ callback();\
+});\n";
+ callback();
+};
+
+proto._addAroundHook = function (options, callback) {
+ if (!callback) {
+ callback = options;
+ options = {};
+ }
+ var tags = "";
+ var logEvent = "around";
+ if (options.tags) tags = '"' + options.tags + '", ';
+ if (options.logEvent) logEvent = options.logEvent;
+ this.stepDefinitions += "Around(" + tags + "function(runScenario) {\
+ world.logCycleEvent('" + logEvent + "-pre');\
+ runScenario(function(callback) {\
+ world.logCycleEvent('" + logEvent + "-post');\
+ callback();\
+ });\
+});\n";
+ callback();
+};
+
+proto.addFailingMapping = function (stepName, options, callback) {
+ this.stepDefinitions += this._generateFailingMapping(stepName, options);
+ callback();
+};
+
+proto._generateMapping = function (stepName, body) {
+ return "\
+Given(/^" + stepName + "$/, function(callback) {\
+ world.touchStep(\"" + stepName + "\");\n" + body + "\
+});\
+";
+};
+
+proto._generateFailingMapping = function (stepName, options) {
+ var message = "I was supposed to fail.";
+ if (options.message) message = options.message;
+ var body = "throw(new Error('" + message + "'));";
+ return this._generateMapping(stepName, body);
+};
+
proto.createEmptyFeature = function createEmptyFeature(options) {
options = options || {};
tags = options['tags'] || [];
@@ -152,6 +233,14 @@ proto.createEmptyFeature = function createEmptyFeature(options) {
}
};
+proto.addPassingStepDefinitionWithName = function (name, callback) {
+ this.stepDefinitions += "Given(/^" + name + "$/, function(callback) {\
+ world.touchStep(\"" + name + "\");\
+ callback();\
+});\n";
+ callback();
+};
+
proto.makeNumberedStepName = function makeNumberedStepName(index) {
var index = index || (++this.stepCount);
var stepName = "step " + index;
View
2  lib/cucumber.js
@@ -16,6 +16,6 @@ Cucumber.Type = require('./cucumber/type');
Cucumber.Util = require('./cucumber/util');
Cucumber.VolatileConfiguration = require('./cucumber/volatile_configuration');
-Cucumber.VERSION = "0.3.0";
+Cucumber.VERSION = "0.3.2";
module.exports = Cucumber;
View
2  lib/cucumber/cli.js
@@ -65,7 +65,7 @@ var Cli = function(argv) {
summary : prints a summary only, after all\n\
scenarios were executed\n\
\n\
---coffee Display step definitions snippets in CoffeeScript.\n\
+--coffee Display step definition snippets in CoffeeScript.\n\
\n\
-v, --version Display Cucumber.js's version.\n\
\n\
View
10 lib/cucumber/cli/argument_parser.js
@@ -64,11 +64,11 @@ 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.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;
},
View
5 lib/cucumber/cli/argument_parser/support_code_path_expander.js
@@ -1,11 +1,12 @@
var SupportCodePathExpander = {
expandPaths: function expandPaths(paths) {
var Cucumber = require('../../../cucumber');
- var CoffeeScript = require('coffee-script');
+ var CoffeeScript = require('coffee-script');
+ var PogoScript = require('pogo');
var PathExpander = Cucumber.Cli.ArgumentParser.PathExpander;
var expandedPaths = PathExpander.expandPathsWithRegexp(paths, SupportCodePathExpander.SUPPORT_CODE_FILES_IN_DIR_REGEXP);
return expandedPaths;
}
};
-SupportCodePathExpander.SUPPORT_CODE_FILES_IN_DIR_REGEXP = /\.(js|coffee)$/;
+SupportCodePathExpander.SUPPORT_CODE_FILES_IN_DIR_REGEXP = /\.(js|coffee|pogo)$/;
module.exports = SupportCodePathExpander;
View
16 lib/cucumber/listener.js
@@ -15,16 +15,21 @@ var Listener = function () {
},
buildHandlerNameForEvent: function buildHandlerNameForEvent(event) {
- var handlerName =
- Listener.EVENT_HANDLER_NAME_PREFIX +
- event.getName() +
- Listener.EVENT_HANDLER_NAME_SUFFIX;
- return handlerName;
+ return self.buildHandlerName(event.getName());
},
getHandlerForEvent: function getHandlerForEvent(event) {
var eventHandlerName = self.buildHandlerNameForEvent(event);
return self[eventHandlerName];
+ },
+
+ buildHandlerName: function buildHandler(shortName) {
+ return Listener.EVENT_HANDLER_NAME_PREFIX + shortName + Listener.EVENT_HANDLER_NAME_SUFFIX;
+ },
+
+ setHandlerForEvent: function setHandlerForEvent(shortname, handler) {
+ var eventName = self.buildHandlerName(shortname);
+ self[eventName] = handler;
}
};
return self;
@@ -33,6 +38,7 @@ var Listener = function () {
Listener.EVENT_HANDLER_NAME_PREFIX = 'handle';
Listener.EVENT_HANDLER_NAME_SUFFIX = 'Event';
+Listener.Events = require('./listener/events');
Listener.Formatter = require('./listener/formatter');
Listener.PrettyFormatter = require('./listener/pretty_formatter');
Listener.ProgressFormatter = require('./listener/progress_formatter');
View
10 lib/cucumber/listener/events.js
@@ -0,0 +1,10 @@
+exports['BeforeFeatures'] = 'BeforeFeatures';
+exports['BeforeFeature'] = 'BeforeFeature';
+exports['Background'] = 'Background';
+exports['BeforeScenario'] = 'BeforeScenario';
+exports['BeforeStep'] = 'BeforeStep';
+exports['StepResult'] = 'StepResult';
+exports['AfterStep'] = 'AfterStep';
+exports['AfterScenario'] = 'AfterScenario';
+exports['AfterFeature'] = 'AfterFeature';
+exports['AfterFeatures'] = 'AfterFeatures';
View
2  lib/cucumber/listener/json_formatter.js
@@ -124,6 +124,7 @@ var JsonFormatter = function(options) {
if (stepResult.isSuccessful()) {
resultStatus = 'passed';
+ stepOutput['duration'] = stepResult.getDuration();
}
else if (stepResult.isPending()) {
resultStatus = 'pending';
@@ -140,6 +141,7 @@ var JsonFormatter = function(options) {
if (failureMessage) {
stepOutput['error_message'] = (failureMessage.stack || failureMessage);
}
+ stepOutput['duration'] = stepResult.getDuration();
}
stepOutput['status'] = resultStatus;
View
18 lib/cucumber/runtime/ast_tree_walker.js
@@ -1,7 +1,6 @@
var AstTreeWalker = function(features, supportCodeLibrary, listeners) {
var Cucumber = require('../../cucumber');
- var listeners;
var world;
var allFeaturesSucceded = true;
var skippingSteps = false;
@@ -107,10 +106,19 @@ var AstTreeWalker = function(features, supportCodeLibrary, listeners) {
},
broadcastEvent: function broadcastEvent(event, callback) {
- listeners.forEach(
- function(listener, callback) { listener.hear(event, callback); },
- callback
- );
+ broadcastToListeners(listeners, onRuntimeListenersComplete);
+
+ function onRuntimeListenersComplete() {
+ var listeners = supportCodeLibrary.getListeners();
+ broadcastToListeners(listeners, callback);
+ }
+
+ function broadcastToListeners(listeners, callback) {
+ listeners.forEach(
+ function(listener, callback) { listener.hear(event, callback); },
+ callback
+ );
+ }
},
lookupStepDefinitionByName: function lookupStepDefinitionByName(stepName) {
View
4 lib/cucumber/runtime/step_result.js
@@ -8,6 +8,10 @@ var StepResult = function (payload) {
getStep: function getStep() {
return payload.step;
+ },
+
+ getDuration: function getDuration() {
+ return payload.duration;
}
};
View
14 lib/cucumber/support_code.js
@@ -1,8 +1,8 @@
-var SupportCode = {};
-SupportCode.Hook = require('./support_code/hook');
-SupportCode.Library = require('./support_code/library');
-SupportCode.StepDefinition = require('./support_code/step_definition');
-SupportCode.StepDefinitionSnippetBuilder = require('./support_code/step_definition_snippet_builder');
+var SupportCode = {};
+SupportCode.Hook = require('./support_code/hook');
+SupportCode.Library = require('./support_code/library');
+SupportCode.StepDefinition = require('./support_code/step_definition');
+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;
+SupportCode.WorldConstructor = require('./support_code/world_constructor');
+module.exports = SupportCode;
View
54 lib/cucumber/support_code/library.js
@@ -1,6 +1,7 @@
var Library = function(supportCodeDefinition) {
var Cucumber = require('../../cucumber');
+ var listeners = Cucumber.Type.Collection();
var stepDefinitions = Cucumber.Type.Collection();
var hooker = Cucumber.SupportCode.Library.Hooker();
var worldConstructor = Cucumber.SupportCode.WorldConstructor();
@@ -50,6 +51,20 @@ var Library = function(supportCodeDefinition) {
stepDefinitions.add(stepDefinition);
},
+ registerListener: function registerListener(listener) {
+ listeners.add(listener);
+ },
+
+ registerHandler: function registerHandler(eventName, handler) {
+ var listener = Cucumber.Listener();
+ listener.setHandlerForEvent(eventName, handler);
+ self.registerListener(listener);
+ },
+
+ getListeners: function getListeners() {
+ return listeners;
+ },
+
instantiateNewWorld: function instantiateNewWorld(callback) {
var world = new worldConstructor(function(explicitWorld) {
process.nextTick(function() { // release the constructor
@@ -60,19 +75,42 @@ var Library = function(supportCodeDefinition) {
};
var supportCodeHelper = {
- Around : self.defineAroundHook,
- Before : self.defineBeforeHook,
- After : self.defineAfterHook,
- Given : self.defineStep,
- When : self.defineStep,
- Then : self.defineStep,
- defineStep : self.defineStep,
- World : worldConstructor
+ Around : self.defineAroundHook,
+ Before : self.defineBeforeHook,
+ After : self.defineAfterHook,
+ Given : self.defineStep,
+ When : self.defineStep,
+ Then : self.defineStep,
+ defineStep : self.defineStep,
+ registerListener : self.registerListener,
+ registerHandler : self.registerHandler,
+ World : worldConstructor
};
+
+ appendEventHandlers(supportCodeHelper, self);
supportCodeDefinition.call(supportCodeHelper);
worldConstructor = supportCodeHelper.World;
return self;
};
+
+function appendEventHandlers(supportCodeHelper, library) {
+ var Cucumber = require('../../cucumber');
+ var events = Cucumber.Listener.Events;
+ var eventName;
+
+ for (eventName in events) {
+ if (events.hasOwnProperty(eventName)) {
+ supportCodeHelper[eventName] = createEventListenerMethod(library, eventName);
+ }
+ }
+}
+
+function createEventListenerMethod(library, eventName) {
+ return function(handler) {
+ library.registerHandler(eventName, handler);
+ };
+}
+
Library.Hooker = require('./library/hooker');
module.exports = Library;
View
27 lib/cucumber/support_code/step_definition.js
@@ -26,6 +26,27 @@ var StepDefinition = function (pattern, code) {
},
invoke: function invoke(step, world, callback) {
+ var time = function time() {
+ if (typeof process !== 'undefined' && process.hrtime) {
+ return process.hrtime();
+ }
+ else {
+ return new Date().getTime();
+ }
+ };
+
+ var durationInNanoseconds = function durationInNanoseconds(start) {
+ if (typeof process !== 'undefined' && process.hrtime) {
+ var duration = process.hrtime(start);
+ return duration[0] * 1e9 + duration[1];
+ }
+ else {
+ return (new Date().getTime() - start) * 1e6;
+ }
+ };
+
+ var start = time();
+
var cleanUp = function cleanUp() {
Cucumber.Util.Exception.unregisterUncaughtExceptionHandler(handleException);
};
@@ -34,7 +55,8 @@ var StepDefinition = function (pattern, code) {
if (error) {
codeCallback.fail(error);
} else {
- var successfulStepResult = Cucumber.Runtime.SuccessfulStepResult({step: step});
+ var duration = durationInNanoseconds(start);
+ var successfulStepResult = Cucumber.Runtime.SuccessfulStepResult({step: step, duration:duration});
cleanUp();
callback(successfulStepResult);
}
@@ -48,7 +70,8 @@ var StepDefinition = function (pattern, code) {
codeCallback.fail = function fail(failureReason) {
var failureException = failureReason || new Error(StepDefinition.UNKNOWN_STEP_FAILURE_MESSAGE);
- var failedStepResult = Cucumber.Runtime.FailedStepResult({step: step, failureException: failureException});
+ var duration = durationInNanoseconds(start);
+ var failedStepResult = Cucumber.Runtime.FailedStepResult({step: step, failureException: failureException, duration: duration});
cleanUp();
callback(failedStepResult);
};
View
15 lib/cucumber/support_code/step_definition_snippet_builder_syntax.js
@@ -1,7 +1,7 @@
-var _ = require('underscore'),
- Syntax = function() {},
- JavaScriptSyntax = function() {},
- CoffeeScriptSyntax = function() {};
+var _ = require('underscore');
+var Syntax = function() {};
+var JavaScriptSyntax = function() {};
+var CoffeeScriptSyntax = function() {};
Syntax.prototype = {
getStepDefinitionDocString: function() {
@@ -15,7 +15,7 @@ Syntax.prototype = {
getStepDefinitionCallback: function() {
return 'callback';
},
-
+
getPatternStart: function() {
return '/^';
},
@@ -93,6 +93,5 @@ CoffeeScriptSyntax.prototype = {
_.extend(CoffeeScriptSyntax.prototype, Syntax.prototype);
-exports.JavaScript = JavaScriptSyntax;
-exports.CoffeeScript = CoffeeScriptSyntax;
-
+exports.JavaScript = JavaScriptSyntax;
+exports.CoffeeScript = CoffeeScriptSyntax;
View
35 package.json
@@ -8,7 +8,7 @@
"gherkin",
"tests"
],
- "version": "0.3.0",
+ "version": "0.3.2",
"homepage": "http://github.com/cucumber/cucumber-js",
"author": "Julien Biezemans <jb@jbpros.com> (http://jbpros.net)",
"contributors": [
@@ -27,6 +27,13 @@
"Israel Halle <isra017@gmail.com>",
"Matteo Collina <matteo.collina@gmail.com>",
"Niklas Närhinen <niklas@narhinen.net>",
+ "Kim, Jang-hwan <janghwan@gmail.com>",
+ "Michael Zedeler <michael@zedeler.dk>",
+ "Tom V <tom@toc.com>",
+ "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>",
"Johny Jose <johny@playlyfe.com>"
],
"repository": {
@@ -42,20 +49,23 @@
},
"main": "./lib/cucumber",
"engines": {
- "node": "0.6 || 0.7 || 0.8"
+ "node": "0.6 || 0.8 || 0.10 || 0.11"
},
"dependencies": {
- "gherkin": "2.11.5",
- "jasmine-node": "1.0.26",
- "connect": "2.3.2",
+ "gherkin": "2.12.2",
"browserify": "1.15.5",
- "nopt": "1.0.10",
- "underscore": "1.3.3",
- "rimraf": "2.0.2",
- "mkdirp": "0.3.3",
- "cucumber-html": "0.2.2",
- "walkdir": "0.0.4",
- "coffee-script": "1.4.0"
+ "nopt": "2.1.2",
+ "underscore": "1.5.2",
+ "cucumber-html": "0.2.3",
+ "walkdir": "0.0.7",
+ "coffee-script": "1.6.3",
+ "pogo": "0.5.1"
+ },
+ "devDependencies": {
+ "connect": "2.11.0",
+ "jasmine-node": "1.11.0",
+ "mkdirp": "0.3.5",
+ "rimraf": "2.2.2"
},
"scripts": {
"test": "./bin/cucumber.js && jasmine-node spec"
@@ -70,6 +80,5 @@
"url": "http://github.com/cucumber/cucumber.js/LICENSE"
}
],
- "devDependencies": {},
"optionalDependencies": {}
}
View
5 spec/cucumber/cli/argument_parser/support_code_path_expander_spec.js
@@ -34,5 +34,10 @@ describe("Cucumber.Cli.ArgumentParser.SupportCodePathExpander", function() {
var matchedCoffeeScriptFile = SupportCodePathExpander.SUPPORT_CODE_FILES_IN_DIR_REGEXP.test("example_steps.coffee");
expect(matchedCoffeeScriptFile).toBeTruthy();
});
+
+ it("matches PogoScript files", function() {
+ var matchedPogoScriptFile = SupportCodePathExpander.SUPPORT_CODE_FILES_IN_DIR_REGEXP.test("example_steps.pogo");
+ expect(matchedPogoScriptFile).toBeTruthy();
+ });
});
});
View
20 spec/cucumber/listener/events_spec.js
@@ -0,0 +1,20 @@
+require('../../support/spec_helper');
+
+describe('Cucumber.Listener.Events', function () {
+ var Cucumber = requireLib('cucumber');
+ var events = Cucumber.Listener.Events;
+
+ describe('construction', function () {
+ it("contains a list of event names", function () {
+ for(var name in events) {
+ if(events.hasOwnProperty(name)) {
+ expect(events[name]).toEqual(name);
+ }
+ }
+ });
+
+ it("is defined", function() {
+ expect(events).toBeDefined();
+ });
+ });
+});
View
12 spec/cucumber/listener/json_formatter_spec.js
@@ -264,6 +264,7 @@ describe("Cucumber.Listener.JsonFormatterWrapper", function () {
isSkipped: undefined,
isUndefined: undefined,
getFailureException: false,
+ getDuration: undefined,
getStep: step
});
fakeEvent = createSpyWithStubs("event", {getPayloadItem: stepResult});
@@ -291,15 +292,17 @@ describe("Cucumber.Listener.JsonFormatterWrapper", function () {
isSkipped: undefined,
isUndefined: undefined,
getFailureException: false,
+ getDuration: undefined,
getStep: step
});
stepResult.isSuccessful.andReturn(true);
+ stepResult.getDuration.andReturn(1);
fakeEvent = createSpyWithStubs("event", {getPayloadItem: stepResult});
listener.handleStepResultEvent(fakeEvent, callback);
expect(formatter.step).toHaveBeenCalledWith({name: 'Step', line: 3, keyword: 'Step'});
- expect(formatter.result).toHaveBeenCalledWith({status: 'passed'});
+ expect(formatter.result).toHaveBeenCalledWith({status: 'passed', duration: 1});
expect(formatter.match).toHaveBeenCalledWith({location: undefined});
});
@@ -319,6 +322,7 @@ describe("Cucumber.Listener.JsonFormatterWrapper", function () {
isSkipped: undefined,
isUndefined: undefined,
getFailureException: false,
+ getDuration: undefined,
getStep: step
});
@@ -348,16 +352,18 @@ describe("Cucumber.Listener.JsonFormatterWrapper", function () {
isSkipped: undefined,
isUndefined: undefined,
getFailureException: false,
+ getDuration: undefined,
getStep: step
});
stepResult.isFailed.andReturn(true);
+ stepResult.getDuration.andReturn(1);
fakeEvent = createSpyWithStubs("event", {getPayloadItem: stepResult});
listener.handleStepResultEvent(fakeEvent, callback);
expect(formatter.step).toHaveBeenCalledWith({name: 'Step', line: 3, keyword: 'Step'});
- expect(formatter.result).toHaveBeenCalledWith({status: 'failed'});
+ expect(formatter.result).toHaveBeenCalledWith({status: 'failed', duration: 1});
expect(formatter.match).toHaveBeenCalledWith({location: undefined});
});
@@ -377,6 +383,7 @@ describe("Cucumber.Listener.JsonFormatterWrapper", function () {
isSkipped: undefined,
isUndefined: undefined,
getFailureException: false,
+ getDuration: undefined,
getStep: step
});
@@ -406,6 +413,7 @@ describe("Cucumber.Listener.JsonFormatterWrapper", function () {
isSkipped: undefined,
isUndefined: undefined,
getFailureException: false,
+ getDuration: undefined,
getStep: step
});
View
38 spec/cucumber/listener_spec.js
@@ -2,6 +2,7 @@ require('../support/spec_helper');
describe("Cucumber.Listener", function() {
var Cucumber = requireLib('cucumber');
+ var listener;
beforeEach(function() {
listener = Cucumber.Listener();
@@ -96,11 +97,12 @@ describe("Cucumber.Listener", function() {
});
describe("buildHandlerNameForEvent", function () {
- var event, eventName;
+ var event, eventName, buildHandlerName;
beforeEach(function () {
eventName = "SomeEventName";
event = createSpyWithStubs("Event", {getName: eventName});
+ buildHandlerName = spyOn(listener, "buildHandlerName");
});
it("gets the name of the event", function () {
@@ -108,8 +110,9 @@ describe("Cucumber.Listener", function() {
expect(event.getName).toHaveBeenCalled();
});
- it("returns the name of the event with prefix 'handle' and suffix 'Event'", function () {
- expect(listener.buildHandlerNameForEvent(event)).toBe("handle" + eventName + "Event");
+ it("calls buildHandlerName", function() {
+ listener.buildHandlerNameForEvent(event);
+ expect(buildHandlerName).toHaveBeenCalled();
});
});
@@ -145,4 +148,33 @@ describe("Cucumber.Listener", function() {
});
});
});
+
+ describe("buildHandlerName", function() {
+ it("returns the name of the event with prefix 'handle' and suffix 'Event'", function () {
+ var eventName = "shortName";
+ var expected = "handle" + eventName + "Event";
+
+ expect(listener.buildHandlerName(eventName)).toBe(expected);
+ });
+ });
+
+ describe("setHandlerForEvent", function() {
+ var shortName = "anEventName";
+ var handler = function(){};
+ var buildHandlerName;
+
+ beforeEach(function() {
+ buildHandlerName = spyOn(listener, "buildHandlerName").andCallThrough();
+ listener.setHandlerForEvent(shortName, handler);
+ });
+
+ it("attaches the function as a property to itself", function() {
+ var expectedKey = Cucumber.Listener.EVENT_HANDLER_NAME_PREFIX + shortName + Cucumber.Listener.EVENT_HANDLER_NAME_SUFFIX;
+ expect(listener[expectedKey]).toBe(handler);
+ });
+
+ it("calls buildHandlerName", function() {
+ expect(buildHandlerName).toHaveBeenCalled();
+ });
+ });
});
View
30 spec/cucumber/runtime/ast_tree_walker_spec.js
@@ -2,13 +2,16 @@ require('../../support/spec_helper');
describe("Cucumber.Runtime.AstTreeWalker", function() {
var Cucumber = requireLib('cucumber');
- var treeWalker, features, supportCodeLibrary, listeners;
+ var treeWalker, features, supportCodeLibrary, listeners, supportListeners;
beforeEach(function() {
features = createSpyWithStubs("Features AST element", {acceptVisitor: null});
supportCodeLibrary = createSpy("Support code library");
listeners = [createSpy("First listener"), createSpy("Second listener")];
+ supportListeners = [createSpy("First support listener"), createSpy("Second support listener")];
spyOnStub(listeners, 'syncForEach').andCallFake(function(cb) { listeners.forEach(cb); });
+ spyOnStub(supportListeners, 'syncForEach').andCallFake(function(cb) { supportListeners.forEach(cb); });
+ spyOnStub(supportCodeLibrary, 'getListeners').andCallFake(function() { return supportListeners; });
treeWalker = Cucumber.Runtime.AstTreeWalker(features, supportCodeLibrary, listeners);
});
@@ -447,7 +450,7 @@ describe("Cucumber.Runtime.AstTreeWalker", function() {
beforeEach(function() {
wrapper = treeWalker.wrapAfterEventBroadcast(event, callback);
- spyOn(treeWalker, 'broadcastAfterEvent');;
+ spyOn(treeWalker, 'broadcastAfterEvent');
});
it("broadcasts an after event with the received callback as callback", function() {
@@ -501,21 +504,34 @@ describe("Cucumber.Runtime.AstTreeWalker", function() {
describe("broadcastEvent()", function() {
- var event, eventName, callback;
+ var event, callback;
beforeEach(function() {
event = createSpy("Event");
callback = createSpy("Callback");
- spyOn(listeners, 'forEach');
+ spyOnListeners(listeners);
+ spyOnListeners(supportListeners);
});
+ function spyOnListeners(listeners) {
+ spyOn(listeners, 'forEach').andCallFake(function() {
+ var callback = listeners.forEach.mostRecentCall.args[1];
+ callback();
+ });
+ }
+
it("iterates over the listeners", function() {
treeWalker.broadcastEvent(event, callback);
- expect(listeners.forEach).toHaveBeenCalled();
- expect(listeners.forEach).toHaveBeenCalledWithAFunctionAsNthParameter(1);
- expect(listeners.forEach).toHaveBeenCalledWithValueAsNthParameter(callback, 2);
+ assertListenerCollectionCalled(listeners.forEach);
+ assertListenerCollectionCalled(supportListeners.forEach);
+ expect(supportListeners.forEach).toHaveBeenCalledWithValueAsNthParameter(callback, 2);
});
+ function assertListenerCollectionCalled(forEachSpy) {
+ expect(forEachSpy).toHaveBeenCalled();
+ expect(forEachSpy).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ }
+
describe("for each listener", function() {
var userFunction, listener, forEachCallback;
View
2  spec/cucumber/runtime/failed_step_result_spec.js
@@ -9,7 +9,7 @@ describe("Cucumber.Runtime.FailedStepResult", function() {
spyOn(Cucumber.Runtime, 'StepResult').andReturn(stepResult);
step = createSpy("step");
failureException = createSpy("failure exception");
- payload = {step: step, failureException: failureException};
+ payload = { step: step, failureException: failureException };
failedStepResult = Cucumber.Runtime.FailedStepResult(payload);
});
View
8 spec/cucumber/runtime/step_result_spec.js
@@ -6,7 +6,7 @@ describe("Cucumber.Runtime.StepResult", function() {
beforeEach(function() {
step = createSpy("step");
- stepResult = Cucumber.Runtime.StepResult({step: step});
+ stepResult = Cucumber.Runtime.StepResult({ step: step, duration: 123 });
});
it("is not failed", function() {
@@ -34,4 +34,10 @@ describe("Cucumber.Runtime.StepResult", function() {
expect(stepResult.getStep()).toBe(step);
});
});
+
+ describe("getDuration()", function() {
+ it("returns the duration passed to the constructor", function() {
+ expect(stepResult.getDuration()).toBe(123);
+ });
+ });
});
View
2  spec/cucumber/runtime/successful_step_result_spec.js
@@ -8,7 +8,7 @@ describe("Cucumber.Runtime.SuccessfulStepResult", function() {
stepResult = createSpy("base step result");
spyOn(Cucumber.Runtime, 'StepResult').andReturn(stepResult);
step = createSpy("step");
- payload = {step: step};
+ payload = { step: step };
successfulStepResult = Cucumber.Runtime.SuccessfulStepResult(payload);
});
View
510 spec/cucumber/support_code/library_spec.js
@@ -3,26 +3,22 @@ require('../../support/spec_helper');
describe("Cucumber.SupportCode.Library", function() {
var Cucumber = requireLib('cucumber');
var library, rawSupportCode, hooker;
- var stepDefinitionCollection;
var worldConstructor;
beforeEach(function() {
rawSupportCode = createSpy("Raw support code");
- stepDefinitionCollection = [
- createSpyWithStubs("First step definition", {matchesStepName:false}),
- createSpyWithStubs("Second step definition", {matchesStepName:false}),
- createSpyWithStubs("Third step definition", {matchesStepName:false})
- ];
hooker = createSpyWithStubs("hooker");
worldConstructor = createSpy("world constructor");
- spyOnStub(stepDefinitionCollection, 'syncForEach').andCallFake(function(cb) { stepDefinitionCollection.forEach(cb); });
- spyOn(Cucumber.Type, 'Collection').andReturn(stepDefinitionCollection);
spyOn(Cucumber.SupportCode.Library, 'Hooker').andReturn(hooker);
spyOn(Cucumber.SupportCode, 'WorldConstructor').andReturn(worldConstructor);
- library = Cucumber.SupportCode.Library(rawSupportCode);
});
describe("constructor", function() {
+ beforeEach(function() {
+ spyOn(Cucumber.Type, 'Collection');
+ library = Cucumber.SupportCode.Library(rawSupportCode);
+ });
+
it("creates a collection of step definitions", function() {
expect(Cucumber.Type.Collection).toHaveBeenCalled();
});
@@ -88,281 +84,391 @@ describe("Cucumber.SupportCode.Library", function() {
it("exposes the World constructor", function() {
expect(supportCodeHelper.World).toBe(worldConstructor);
});
- });
- });
-
- describe("lookupStepDefinitionByName()", function() {
- var stepName;
- beforeEach(function() {
- stepName = createSpy("Step name");
- });
+ it("exposes a method to register a listener", function() {
+ expect(supportCodeHelper.registerListener).toBeAFunction();
+ });
- it("asks each step definition in the library if they match the step name", function() {
- library.lookupStepDefinitionByName(stepName);
- stepDefinitionCollection.forEach(function(stepDefinition) {
- expect(stepDefinition.matchesStepName).toHaveBeenCalledWith(stepName);
+ it("exposes a method to register a handler", function() {
+ expect(supportCodeHelper.registerHandler).toBeAFunction();
});
- });
- it("returns the step definition that matches the name", function() {
- var matchingStepDefinition = stepDefinitionCollection[1];
- matchingStepDefinition.matchesStepName.andReturn(true);
- expect(library.lookupStepDefinitionByName(stepName)).toBe(matchingStepDefinition);
+ // parameterized test
+ for(eventName in Cucumber.Listener.Events) {
+ if(!Cucumber.Listener.Events.hasOwnProperty(eventName))
+ continue;
+
+ describe(eventName + ' event register handler method', function() {
+ beforeEach(function() {
+ spyOn(library, 'registerHandler');
+ });
+
+ it("is defined as a function", function() {
+ expect(supportCodeHelper[eventName]).toBeAFunction();
+ });
+
+ it("calls registerHandler with the eventName", function() {
+ var handler = createSpy('handler');
+ supportCodeHelper[eventName](handler);
+ expect(library.registerHandler).toHaveBeenCalled();
+ expect(library.registerHandler).toHaveBeenCalledWithValueAsNthParameter(eventName, 1);
+ expect(library.registerHandler).toHaveBeenCalledWithValueAsNthParameter(handler, 2);
+ });
+ });
+ }
});
});
- describe("isStepDefinitionNameDefined()", function() {
- var name;
+ describe('Step Definitions', function() {
+ var stepDefinitionCollection;
beforeEach(function() {
- name = createSpy("step name");
- spyOn(library, 'lookupStepDefinitionByName');
+ stepDefinitionCollection = [
+ createSpyWithStubs("First step definition", {matchesStepName:false}),
+ createSpyWithStubs("Second step definition", {matchesStepName:false}),
+ createSpyWithStubs("Third step definition", {matchesStepName:false})
+ ];
+ spyOnStub(stepDefinitionCollection, 'syncForEach').andCallFake(function(cb) { stepDefinitionCollection.forEach(cb); });
+ spyOn(Cucumber.Type, 'Collection').andReturn(stepDefinitionCollection);
+ library = Cucumber.SupportCode.Library(rawSupportCode);
});
- it("looks up the step definition by the name", function() {
- library.isStepDefinitionNameDefined(name);
- expect(library.lookupStepDefinitionByName).toHaveBeenCalledWith(name);
- });
-
- describe("when a step definition is found", function() {
- var stepDefinition;
+ describe("lookupStepDefinitionByName()", function() {
+ var stepName;
beforeEach(function() {
- stepDefinition = createSpy("step definition");
- library.lookupStepDefinitionByName.andReturn(stepDefinition);
+ stepName = createSpy("Step name");
+ });
+
+ it("asks each step definition in the library if they match the step name", function() {
+ library.lookupStepDefinitionByName(stepName);
+ stepDefinitionCollection.forEach(function(stepDefinition) {
+ expect(stepDefinition.matchesStepName).toHaveBeenCalledWith(stepName);
+ });
});
- it("returns true", function() {
- expect(library.isStepDefinitionNameDefined(name)).toBeTruthy();
+ it("returns the step definition that matches the name", function() {
+ var matchingStepDefinition = stepDefinitionCollection[1];
+ matchingStepDefinition.matchesStepName.andReturn(true);
+ expect(library.lookupStepDefinitionByName(stepName)).toBe(matchingStepDefinition);
});
});
- describe("when no step definition is found", function() {
+ describe("isStepDefinitionNameDefined()", function() {
+ var name;
+
beforeEach(function() {
- library.lookupStepDefinitionByName.andReturn(undefined);
+ name = createSpy("step name");
+ spyOn(library, 'lookupStepDefinitionByName');
});
- it("returns false", function() {
- expect(library.isStepDefinitionNameDefined(name)).toBeFalsy();
+ it("looks up the step definition by the name", function() {
+ library.isStepDefinitionNameDefined(name);
+ expect(library.lookupStepDefinitionByName).toHaveBeenCalledWith(name);
});
- });
- });
- describe("hookUpFunction()", function() {
- var userFunction, scenario, world, hookedUpFunction;
+ describe("when a step definition is found", function() {
+ var stepDefinition;
- beforeEach(function() {
- userFunction = createSpy("user function");
- hookedUpFunction = createSpy("hooked up function");
- scenario = createSpy("scenario");
- world = createSpy("world instance");
- spyOnStub(hooker, 'hookUpFunction').andReturn(hookedUpFunction);
- });
+ beforeEach(function() {
+ stepDefinition = createSpy("step definition");
+ library.lookupStepDefinitionByName.andReturn(stepDefinition);
+ });
+
+ it("returns true", function() {
+ expect(library.isStepDefinitionNameDefined(name)).toBeTruthy();
+ });
+ });
- it("hooks up the function with the world instance", function() {
- library.hookUpFunction(userFunction, scenario, world);
- expect(hooker.hookUpFunction).toHaveBeenCalledWith(userFunction, scenario, world);
+ describe("when no step definition is found", function() {
+ beforeEach(function() {
+ library.lookupStepDefinitionByName.andReturn(undefined);
+ });
+
+ it("returns false", function() {
+ expect(library.isStepDefinitionNameDefined(name)).toBeFalsy();
+ });
+ });
});
- it("returns the hooked up function", function() {
- expect(library.hookUpFunction(userFunction, scenario, world)).toBe(hookedUpFunction);
+ describe("defineStep()", function() {
+ var name, code, stepDefinition;
+
+ beforeEach(function() {
+ name = createSpy("step definition name");
+ code = createSpy("step definition code");
+ stepDefinition = createSpy("step definition");
+ spyOn(Cucumber.SupportCode, 'StepDefinition').andReturn(stepDefinition);
+ spyOnStub(stepDefinitionCollection, 'add');
+ });
+
+ it("creates a step definition with the name and code", function() {
+ library.defineStep(name, code);
+ expect(Cucumber.SupportCode.StepDefinition).toHaveBeenCalledWith(name, code);
+ });
+
+ it("adds the step definition to the step collection", function() {
+ library.defineStep(name, code);
+ expect(stepDefinitionCollection.add).toHaveBeenCalledWith(stepDefinition);
+ });
});
});
- describe("defineAroundHook()", function() {
- var code;
+ describe('Listener Support', function() {
+ var listeners;
beforeEach(function() {
- code = createSpy("hook code");
- spyOnStub(hooker, 'addAroundHookCode');
+ listeners = [
+ createSpyWithStubs("First listener", {setHandlerForEvent: null}),
+ createSpyWithStubs("Second listener", {setHandlerForEvent: null}),
+ createSpyWithStubs("Third listener", {setHandlerForEvent: null})
+ ];
+ spyOn(Cucumber.Type, 'Collection').andReturn(listeners);
+ spyOnStub(listeners, 'add');
+ library = Cucumber.SupportCode.Library(rawSupportCode);
+ });
+
+ describe('getListeners()', function() {
+ it("returns a listener collection", function() {
+ var listeners = library.getListeners();
+ expect(listeners).toBeDefined();
+ });
});
- it("instructs the hooker to use the code as an around hook", function() {
- library.defineAroundHook(code);
- expect(hooker.addAroundHookCode).toHaveBeenCalledWith(code, {tags: []});
+ describe("registerListener()", function() {
+ it("adds the listener to the listener collection", function() {
+ var listener = createSpy('sample listener');
+ library.registerListener(listener);
+ expect(listeners.add).toHaveBeenCalledWith(listener);
+ })
});
- it("instructs the hooker to use the code as an around hook with a tag group", function() {
- var tagGroup = createSpy("tag group");
- library.defineAroundHook(tagGroup, code);
- expect(hooker.addAroundHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup]});
- });
+ describe('registerHandler()', function() {
+ var eventName, handler, listener;
+
+ beforeEach(function() {
+ eventName = 'eventName';
+ handler = createSpy('sampleHandler');
+ listener = createSpyWithStubs("listener", {setHandlerForEvent: null});
+ spyOn(Cucumber, 'Listener').andReturn(listener);
+ library.registerHandler(eventName, handler);
+ });
+
+ it('creates a listener to the listener collection', function() {
+ expect(listener.setHandlerForEvent).toHaveBeenCalledWithValueAsNthParameter(eventName, 1);
+ expect(listener.setHandlerForEvent).toHaveBeenCalledWithValueAsNthParameter(handler, 2);
+ });
- it("instructs the hooker to use the code as an around hook with tag groups", function() {
- var tagGroup1 = createSpy("tag group 1");
- var tagGroup2 = createSpy("tag group 2");
- library.defineAroundHook(tagGroup1, tagGroup2, code);
- expect(hooker.addAroundHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup1, tagGroup2]});
+ it("adds the listener to the listener collection", function() {
+ expect(listeners.add).toHaveBeenCalled();
+ });
});
});
- describe("defineBeforeHook()", function() {
- var code;
-
+ describe('Hook Methods', function() {
beforeEach(function() {
- code = createSpy("hook code");
- spyOnStub(hooker, 'addBeforeHookCode');
+ library = Cucumber.SupportCode.Library(rawSupportCode);
});
- it("instructs the hooker to use the code as an before hook", function() {
- library.defineBeforeHook(code);
- expect(hooker.addBeforeHookCode).toHaveBeenCalledWith(code, {tags: []});
- });
+ describe("hookUpFunction()", function() {
+ var userFunction, scenario, world, hookedUpFunction;
- it("instructs the hooker to use the code as an before hook with a tag group", function() {
- var tagGroup = createSpy("tag group");
- library.defineBeforeHook(tagGroup, code);
- expect(hooker.addBeforeHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup]});
- });
+ beforeEach(function() {
+ userFunction = createSpy("user function");
+ hookedUpFunction = createSpy("hooked up function");
+ scenario = createSpy("scenario");
+ world = createSpy("world instance");
+ spyOnStub(hooker, 'hookUpFunction').andReturn(hookedUpFunction);
+ });
+
+ it("hooks up the function with the world instance", function() {
+ library.hookUpFunction(userFunction, scenario, world);
+ expect(hooker.hookUpFunction).toHaveBeenCalledWith(userFunction, scenario, world);
+ });
- it("instructs the hooker to use the code as an before hook with tag groups", function() {
- var tagGroup1 = createSpy("tag group 1");
- var tagGroup2 = createSpy("tag group 2");
- library.defineBeforeHook(tagGroup1, tagGroup2, code);
- expect(hooker.addBeforeHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup1, tagGroup2]});
+ it("returns the hooked up function", function() {
+ expect(library.hookUpFunction(userFunction, scenario, world)).toBe(hookedUpFunction);
+ });
});
- });
- describe("defineAfterHook()", function() {
- var code;
+ describe("defineAroundHook()", function() {
+ var code;
- beforeEach(function() {
- code = createSpy("hook code");
- spyOnStub(hooker, 'addAfterHookCode');
- });
+ beforeEach(function() {
+ code = createSpy("hook code");
+ spyOnStub(hooker, 'addAroundHookCode');
+ });
- it("instructs the hooker to use the code as an after hook", function() {
- library.defineAfterHook(code);
- expect(hooker.addAfterHookCode).toHaveBeenCalledWith(code, {tags: []});
- });
+ it("instructs the hooker to use the code as an around hook", function() {
+ library.defineAroundHook(code);
+ expect(hooker.addAroundHookCode).toHaveBeenCalledWith(code, {tags: []});
+ });
- it("instructs the hooker to use the code as an after hook with a tag group", function() {
- var tagGroup = createSpy("tag group");
- library.defineAfterHook(tagGroup, code);
- expect(hooker.addAfterHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup]});
- });
+ it("instructs the hooker to use the code as an around hook with a tag group", function() {
+ var tagGroup = createSpy("tag group");
+ library.defineAroundHook(tagGroup, code);
+ expect(hooker.addAroundHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup]});
+ });
- it("instructs the hooker to use the code as an after hook with tag groups", function() {
- var tagGroup1 = createSpy("tag group 1");
- var tagGroup2 = createSpy("tag group 2");
- library.defineAfterHook(tagGroup1, tagGroup2, code);
- expect(hooker.addAfterHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup1, tagGroup2]});
+ it("instructs the hooker to use the code as an around hook with tag groups", function() {
+ var tagGroup1 = createSpy("tag group 1");
+ var tagGroup2 = createSpy("tag group 2");
+ library.defineAroundHook(tagGroup1, tagGroup2, code);
+ expect(hooker.addAroundHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup1, tagGroup2]});
+ });
});
- });
- describe("defineStep()", function() {
- var name, code, stepDefinition;
+ describe("defineBeforeHook()", function() {
+ var code;
- beforeEach(function() {
- name = createSpy("step definition name");
- code = createSpy("step definition code");
- stepDefinition = createSpy("step definition");
- spyOn(Cucumber.SupportCode, 'StepDefinition').andReturn(stepDefinition);
- spyOnStub(stepDefinitionCollection, 'add');
- });
+ beforeEach(function() {
+ code = createSpy("hook code");
+ spyOnStub(hooker, 'addBeforeHookCode');
+ });
- it("creates a step definition with the name and code", function() {
- library.defineStep(name, code);
- expect(Cucumber.SupportCode.StepDefinition).toHaveBeenCalledWith(name, code);
- });
+ it("instructs the hooker to use the code as an before hook", function() {
+ library.defineBeforeHook(code);
+ expect(hooker.addBeforeHookCode).toHaveBeenCalledWith(code, {tags: []});
+ });
- it("adds the step definition to the step collection", function() {
- library.defineStep(name, code);
- expect(stepDefinitionCollection.add).toHaveBeenCalledWith(stepDefinition);
+ it("instructs the hooker to use the code as an before hook with a tag group", function() {
+ var tagGroup = createSpy("tag group");
+ library.defineBeforeHook(tagGroup, code);
+ expect(hooker.addBeforeHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup]});
+ });
+
+ it("instructs the hooker to use the code as an before hook with tag groups", function() {
+ var tagGroup1 = createSpy("tag group 1");
+ var tagGroup2 = createSpy("tag group 2");
+ library.defineBeforeHook(tagGroup1, tagGroup2, code);
+ expect(hooker.addBeforeHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup1, tagGroup2]});
+ });
});
- });
- describe("instantiateNewWorld()", function() {
- var worldInstance, callback;
+ describe("defineAfterHook()", function() {
+ var code;
- beforeEach(function() {
- worldInstance = null;
- worldConstructor.andCallFake(function(callback) {
- worldInstance = this;
- if (callback)
- callback();
+ beforeEach(function() {
+ code = createSpy("hook code");
+ spyOnStub(hooker, 'addAfterHookCode');
+ });
+
+ it("instructs the hooker to use the code as an after hook", function() {
+ library.defineAfterHook(code);
+ expect(hooker.addAfterHookCode).toHaveBeenCalledWith(code, {tags: []});
+ });
+
+ it("instructs the hooker to use the code as an after hook with a tag group", function() {
+ var tagGroup = createSpy("tag group");
+ library.defineAfterHook(tagGroup, code);
+ expect(hooker.addAfterHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup]});
+ });
+
+ it("instructs the hooker to use the code as an after hook with tag groups", function() {
+ var tagGroup1 = createSpy("tag group 1");
+ var tagGroup2 = createSpy("tag group 2");
+ library.defineAfterHook(tagGroup1, tagGroup2, code);
+ expect(hooker.addAfterHookCode).toHaveBeenCalledWith(code, {tags: [tagGroup1, tagGroup2]});
});
- callback = createSpy("callback");
});
+ });
- it("creates a new instance of the World and give it a callback", function() {
- library.instantiateNewWorld(callback);
- expect(worldConstructor).toHaveBeenCalled();
- expect(worldConstructor).toHaveBeenCalledWithAFunctionAsNthParameter(1);
- expect(worldInstance.constructor).toBe(worldConstructor);
+ describe('World construction', function() {
+ beforeEach(function() {
+ library = Cucumber.SupportCode.Library(rawSupportCode);
});
- describe("world constructor callback", function() {
- var worldConstructorCompletionCallback;
+ describe("instantiateNewWorld()", function() {
+ var worldInstance, callback;
beforeEach(function() {
- library.instantiateNewWorld(callback);
- worldConstructorCompletionCallback = worldConstructor.mostRecentCall.args[0];
- spyOn(process, 'nextTick');
- })
+ worldInstance = null;
+ worldConstructor.andCallFake(function(callback) {
+ worldInstance = this;
+ if (callback)
+ callback();
+ });
+ callback = createSpy("callback");
+ });
- it("registers a function for the next tick (to get out of the constructor call)", function() {
- worldConstructorCompletionCallback();
- expect(process.nextTick).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ it("creates a new instance of the World and give it a callback", function() {
+ library.instantiateNewWorld(callback);
+ expect(worldConstructor).toHaveBeenCalled();
+ expect(worldConstructor).toHaveBeenCalledWithAFunctionAsNthParameter(1);
+ expect(worldInstance.constructor).toBe(worldConstructor);
});
- describe("next tick registered function", function() {
- var nextTickFunction;
+ describe("world constructor callback", function() {
+ var worldConstructorCompletionCallback;
- describe("when the world constructor called back without any argument", function() {
- beforeEach(function() {
- worldConstructorCompletionCallback();
- nextTickFunction = process.nextTick.mostRecentCall.args[0];
- });
+ beforeEach(function() {
+ library.instantiateNewWorld(callback);
+ worldConstructorCompletionCallback = worldConstructor.mostRecentCall.args[0];
+ spyOn(process, 'nextTick');
+ });
- it("calls back with the world instance", function() {
- nextTickFunction();
- expect(callback).toHaveBeenCalledWith(worldInstance);
-