cucumber
Version:
The official JavaScript implementation of Cucumber.
416 lines (274 loc) • 15 kB
Markdown
# Cucumber.js [](http://travis-ci.org/cucumber/cucumber-js)
*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.
### Cucumber Technology Compatibility Kit
| Feature | Status |
|:------------------------------------------------------------------------------------------------------------------------------|:--------------------|
| [Core](https://github.com/cucumber/cucumber-tck/blob/master/core.feature) (scenarios, steps, mappings) | Done |
| [Background](https://github.com/cucumber/cucumber-tck/blob/master/background.feature) | Done<sup>1</sup> |
| [Calling steps from step defs](https://github.com/cucumber/cucumber-tck/blob/master/calling_steps_from_stepdefs.feature) | To do |
| [Comments](https://github.com/cucumber/cucumber-tck/blob/master/comments.feature) | Done |
| [Command-line interface](https://github.com/cucumber/cucumber-tck/blob/master/command_line_interface.feature) | Done<sup>1, 2</sup> |
| [Command-line options](https://github.com/cucumber/cucumber-tck/blob/master/command_line_options.feature) | To do<sup>2</sup> |
| [Data tables](https://github.com/cucumber/cucumber-tck/blob/master/data_tables.feature) | Done |
| [Doc Strings](https://github.com/cucumber/cucumber-tck/blob/master/doc_strings.feature) | Done |
| [Failing steps](https://github.com/cucumber/cucumber-tck/blob/master/failing_steps.feature) | Done |
| [Hooks](https://github.com/cucumber/cucumber-tck/blob/master/hooks.feature) | Done |
| [I18n](https://github.com/cucumber/cucumber-tck/blob/master/i18n.feature) | To do |
| [JSON formatter](https://github.com/cucumber/cucumber-tck/blob/master/json_formatter.feature) | To do |
| [Pretty formatter](https://github.com/cucumber/cucumber-tck/blob/master/pretty_formatter.feature) | To do<sup>2</sup> |
| [Scenario outlines and examples](https://github.com/cucumber/cucumber-tck/blob/master/scenario_outlines_and_examples.feature) | To do |
| [Stats collector](https://github.com/cucumber/cucumber-tck/blob/master/stats_collector.feature) | To do |
| [Step argument transforms](https://github.com/cucumber/cucumber-tck/blob/master/step_argument_transforms.feature) | To do |
| [Tags](https://github.com/cucumber/cucumber-tck/blob/master/tags.feature) | Done |
| [Undefined steps](https://github.com/cucumber/cucumber-tck/blob/master/undefined_steps.feature) | Done |
| [Wire protocol](https://github.com/cucumber/cucumber-tck/blob/master/wire_protocol.feature) | To do |
| [World](https://github.com/cucumber/cucumber-tck/blob/master/world.feature) | Done |
1. Not certified by [Cucumber TCK](https://github.com/cucumber/cucumber-tck) yet.
2. Considered for removal from [Cucumber TCK](https://github.com/cucumber/cucumber-tck).
3. Simple *Around*, *Before* and *After* hooks are available.
### Cucumber.js-specific features
| Feature | Status |
|:------------------------------------------------------------------------------------------------------------------|:-----------------|
| [Background](https://github.com/cucumber/cucumber-js/blob/master/features/background.feature) | Done<sup>1</sup> |
| [CoffeeScript support](https://github.com/cucumber/cucumber-js/blob/master/features/coffeescript_support.feature) | Done |
| [Command-line interface](https://github.com/cucumber/cucumber-js/blob/master/features/cli.feature) | Done |
1. Will be certified by [Cucumber TCK](https://github.com/cucumber/cucumber-tck).
## Prerequesites
* [Node.js](http://nodejs.org)
* [NPM](http://npmjs.org)
Cucumber.js is tested on:
* Node.js 0.4, 0.6 (see [CI builds](http://travis-ci.org/#!/cucumber/cucumber-js)) and supposedly 0.5.
* Google Chrome
* Firefox
* Safari
* Opera
There are plans to have CI builds on browsers too.
## Usage
### Install
Cucumber.js is available as an npm module.
Install globally with:
``` shell
$ npm install -g cucumber
```
OR
You may also define cucumber.js as a development dependency of your application by including it in a package.json file.
``` json
// package.json
{ "devDependencies" : {
"cucumber": "latest"
}
}
```
Then install with `npm install --dev`
### Features
Features are written with the [Gherkin syntax](https://github.com/cucumber/cucumber/wiki/Gherkin)
``` gherkin
# features/myFeature.feature
Feature: Example feature
As a user of cucumber.js
I want to have documentation on cucumber
So that I can concentrate on building awesome applications
Scenario: Reading documentation
Given I am on the cucumber.js github page
When I go to the README file
Then I should see "Usage"
```
### Support Files
Support files let you setup the environment in which steps will be run, and define step definitions.
#### World
*World* is a constructor function with utility properties, destined to be used in step definitions:
``` javascript
// features/support/world.js
var zombie = require('zombie');
var World = function(callback) {
this.browser = new zombie.Browser(); // this.browser will be available in step definitions
this.visit = function(url, callback) {
this.browser.visit(url, callback);
};
callback(); // tell Cucumber we're finished
};
exports.World = World;
```
#### Step Definitions
Step definitions are the glue between features written in Gherkin and the actual *SUT* (*system under test*). They are written in JavaScript.
All step definitions will run with `this` set to what is known as the *[World](https://github.com/cucumber/cucumber/wiki/A-Whole-New-World)* in Cucumber. It's an object exposing useful methods, helpers and variables to your step definitions. A new instance of `World` is created before each scenario.
Step definitions are contained within one or more wrapper functions.
Those wrappers are run before executing the feature suite. `this` is an object holding important properties like the `Given()`, `When()` and `Then()` functions. Another notable property is `World`; it contains a default `World` constructor that can be either extended or replaced.
Step definitions are run when steps match their name. `this` is an instance of `World`.
``` javascript
// features/step_definitions/myStepDefinitions.js
var myStepDefinitionsWrapper = function () {
this.World = require("../support/world.js").World; // overwrite default World constructor
this.Given(/REGEXP/, 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:
this.visit('http://github.com/cucumber/cucumber-js', callback);
// The callback is passed to visit() so that when the job's finished, the next step can
// be executed by Cucumber.
});
this.When(/REGEXP/, function(callback) {
// Express the regexp above with the code you wish you had. Call callback() at the end
// of the step, or callback.pending() if the step is not yet implemented:
callback.pending();
});
this.Then(/REGEXP/, function(callback) {
// You can make steps fail by calling the `fail()` function on the callback:
if (!this.isOnPageWithTitle("Cucumber.js demo"))
callback.fail(new Error("Expected to be on 'Cucumber.js demo' page"));
else
callback();
});
};
module.exports = myStepDefinitionsWrapper;
```
#### Hooks
Hooks can be used to prepare and clean the environment before and after each scenario is executed.
##### Before hooks
To run something before every scenario, use before hooks:
``` javascript
// features/support/hooks.js (this path is just a suggestion)
var myHooks = function () {
this.Before(function(callback) {
// Just like inside step definitions, "this" is set to a World instance.
// It's actually the same instance the current scenario step definitions
// will receive.
// Let's say we have a bunch of "maintenance" methods available on our World
// instance, we can fire some to prepare the application for the next
// scenario:
this.bootFullTextSearchServer();
this.createSomeUsers();
// Don't forget to tell Cucumber when you're done:
callback();
});
};
module.exports = myHooks;
```
##### After hooks
The *before hook* counterpart is the *after hook*. It's similar in shape but is executed, well, *after* every scenario:
```javascript
// features/support/after_hooks.js
var myAfterHooks = function () {
this.After(function(callback) {
// Again, "this" is set to the World instance the scenario just finished
// playing with.
// We can then do some cleansing:
this.emptyDatabase();
this.shutdownFullTextSearchServer();
// Release control:
callback();
});
};
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*:
```javascript
// features/support/advanced_hooks.js
myAroundHooks = function() {
this.Around(function(runScenario) {
// "this" is - as always - an instance of World promised to the scenario.
// First do the "before scenario" tasks:
this.bootFullTextSearchServer();
this.createSomeUsers();
// When the "before" duty is finished, tell Cucumber to execute the scenario
// and pass a function to be called when the scenario is finished:
runScenario(function(callback) {
// Now, we can do our "after scenario" stuff:
this.emptyDatabase();
this.shutdownFullTextSearchServer();
// Tell Cucumber we're done:
callback();
});
});
};
module.exports = myAroundHooks;
```
##### Tagged hooks
Hooks can be conditionally elected for execution based on the tags of the scenario.
``` javascript
// features/support/hooks.js (this path is just a suggestion)
var myHooks = function () {
this.Before("@foo", "@bar,@baz", function(callback) {
// This hook will be executed before scenarios tagged with @foo and either
// @bar or @baz.
// ...
callback();
});
};
module.exports = myHooks;
```
### Run cucumber
Cucumber.js includes a binary file to execute the features.
If you installed cucumber.js with `npm install --dev`, you may run cucumber with:
``` shell
@NODE_ENV=test ./node_modules/.bin/cucumber.js
```
You may specify the features to run:
``` shell
@NODE_ENV=test ./node_modules/.bin/cucumber.js features/myFeature.feature
```
And require specific step definitions with the --require option:
``` shell
@NODE_ENV=test ./node_modules/.bin/cucumber.js features/myFeature.feature \
--require features/step_definitions/myStepDefinitions.js
```
### Examples
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/)
## Setup for using in Node.js and running tests
Install the required dependencies:
$ npm link
## Play
$ node example/server.js
Then go to [localhost:9797](http://localhost:9797/).
## Run tests
### Specs
$ node_modules/.bin/jasmine-node spec
### Features & documentation
There is a common set of features shared by all cucumber implementations. It's called the *Technology Compatibility Kit* or *TCK*. Find more on the [Cucumber TCK](http://github.com/cucumber/cucumber-tck) repository.
The official way of running them is through Cucumber-ruby and Aruba. Ruby and Bundler are required for this to work.
$ git submodule update --init
$ bundle
$ rm -rf doc; ARUBA_REPORT_DIR=doc cucumber features/cucumber-tck -r features
*Note*: you need the *bcat* and *rdiscount* gems in order to use the `ARUBA_REPORT_DIR` environment variable. Install it with `gem install bcat rdiscount`.
You can then open the generated documentation:
$ open doc/features/cucumber-tck/*.html # might open a lot of files ;)
In addition to that, Cucumber.js is able to run the features for itself too:
$ ./bin/cucumber.js features/cucumber-tck -r features
There are a few other Cucumber.js-dependent features. Execute everything:
$ ./bin/cucumber.js
### Rake
Alternatively, you can run everything with the help of Rake:
$ git submodule update --init
$ bundle
$ rake
### Debug messages
You can display debug messages by setting the DEBUG_LEVEL environment variable. It goes from `1` to `5`. `5` will display everything, `1` will only print out the critical things.
$ DEBUG_LEVEL=5 ./bin/cucumber.js
It even works with Aruba:
$ rm -rf doc; DEBUG_LEVEL=5 ARUBA_REPORT_DIR=doc cucumber features/cucumber-tck -r features
$ open doc/features/cucumber-tck/*.html # you'll see debug messages in Aruba-generated docs
## Help & support
* Twitter: [@cucumber_js](https://twitter.com/#!/cucumber_js/)
* IRC: [#cucumber](http://webchat.freenode.net?channels=cucumber&uio=d4) on Freenode
* Google Groups: [cukes](https://groups.google.com/group/cukes)
* [cukes.info](http://cukes.info)
## Release checklist
* Update development status in `README.md`, if relevant
* Update `History.md`
* Bump version in `lib/cucumber.js`
* Bump version in `package.json`
* 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
* Wait for build to go green
* Publish to NPM
* Deploy to cucumber.no.de