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