Skip to content

Commit

Permalink
update support code interface
Browse files Browse the repository at this point in the history
closes #694
resolves #679
  • Loading branch information
charlierudolph committed Dec 19, 2016
1 parent 96a61d7 commit fa39a28
Show file tree
Hide file tree
Showing 57 changed files with 1,141 additions and 1,073 deletions.
27 changes: 16 additions & 11 deletions docs/nodejs_example.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Setup

* Install [Chrome](https://www.google.com/chrome/)
* Install [Node.js](https://nodejs.org) (6 or higher)
* Run `npm install --save-dev cucumber selenium-webdriver@3.0.1 chromedriver@2.25.1`
* Add the following files

Expand All @@ -21,48 +22,52 @@
// features/support/world.js
require('chromedriver')
var seleniumWebdriver = require('selenium-webdriver');
var {defineSupportCode} = require('cucumber');

This comment has been minimized.

Copy link
@boyney123

boyney123 Apr 20, 2017

Can we do named imports in node?

This comment has been minimized.

Copy link
@aslakhellesoy

aslakhellesoy Apr 20, 2017

Contributor

You mean import {defineSupportCode} from 'cucumber'? Sure - it's equivalent

function CustomWorld() {
this.driver = new seleniumWebdriver.Builder()
.forBrowser('chrome')
.build();
}
module.exports = function() {
this.World = CustomWorld;
};
defineSupportCode(function({setWorldConstructor}) {
setWorldConstructor(CustomWorld)
})
```
```javascript
// features/step_definitions/hooks.js
module.exports = function () {
this.After(function() {
var {defineSupportCode} = require('cucumber');
defineSupportCode(function({After}) {
After(function() {
return this.driver.quit();
});
};
});
```
```javascript
// features/step_definitions/browser_steps.js
var seleniumWebdriver = require('selenium-webdriver');
var {defineSupportCode} = require('cucumber');
module.exports = function () {
this.Given('I am on the Cucumber.js GitHub repository', function() {
defineSupportCode(function({Given, When, Then}) {
Given('I am on the Cucumber.js GitHub repository', function() {
return this.driver.get('https://github.com/cucumber/cucumber-js/tree/master');
});
this.When('I click on {stringInDoubleQuotes}', function (text) {
When('I click on {stringInDoubleQuotes}', function (text) {
return this.driver.findElement({linkText: text}).then(function(element) {
return element.click();
});
});
this.Then('I should see {stringInDoubleQuotes}', function (text) {
Then('I should see {stringInDoubleQuotes}', function (text) {
var xpath = "//*[contains(text(),'" + text + "')]";
var condition = seleniumWebdriver.until.elementLocated({xpath: xpath});
return this.driver.wait(condition, 5000);
});
};
});
```
* Run `./node_modules/.bin/cucumber-js`
56 changes: 28 additions & 28 deletions docs/support_files/api_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

## API Reference

All support files that export a function will be called with a context that exposes the following methods:
The function passed to `defineSupportCode` is called with an object as the first argument that exposes the following methods:

---

#### `this.addTransform({captureGroupRegexps, name, transformer})`
#### `addTransform({captureGroupRegexps, name, transformer})`

Add a new transform to convert a capture group into something else.

Expand Down Expand Up @@ -40,7 +40,7 @@ The built in transforms are:

---

#### `this.After([options,] fn)`
#### `After([options,] fn)`

Defines a hook which is run after each scenario.

Expand All @@ -58,19 +58,19 @@ Multiple `After` hooks are executed in the **reverse** order that they are defin

---

#### `this.Before([options,] fn)`
#### `Before([options,] fn)`

Defines a hook which is run before each scenario. Same interface as `this.After`.
Defines a hook which is run before each scenario. Same interface as `After`.

Multiple `Before` hooks are executed in the order that they are defined.

---

#### `this.defineStep([options,] pattern, fn)`
#### `defineStep([options,] pattern, fn)`

Defines a step.

Aliases: `this.Given`, `this.When`, `this.Then`.
Aliases: `Given`, `When`, `Then`.

* `pattern`: A regex or string pattern to match against a gherkin step.
* `options`: An object with the following keys:
Expand All @@ -82,13 +82,13 @@ Aliases: `this.Given`, `this.When`, `this.Then`.

---

#### `this.Given(pattern[, options], fn)`
#### `Given(pattern[, options], fn)`

Alias of `this.defineStep`.
Alias of `defineStep`.

---

#### `this.registerHandler(event[, options], fn)`
#### `registerHandler(event[, options], fn)`

* `event`: One of the supported event names [listed here](./event_handlers.md).
* `options`: An object with the following keys:
Expand All @@ -99,41 +99,41 @@ Alias of `this.defineStep`.

---

#### `this.setDefaultTimeout(milliseconds)`
#### `setDefaultTimeout(milliseconds)`

Set the default timeout for asynchronous steps. Defaults to `5000` milliseconds.

---

#### `this.setDefinitionFunctionWrapper(fn)`
#### `setDefinitionFunctionWrapper(fn)`

Set a function used to wrap step / hook definitions. When used, the result is wrapped again to ensure it has the same length of the original step / hook definition.

---

#### `this.Then(pattern[, options], fn)`

Alias of `this.defineStep`.

---

#### `this.When(pattern[, options], fn)`

Alias of `this.defineStep`.

---

#### `this.World`
#### `setWorldConstructor(constructor)`

Set a custom world constructor, to override the default world constructor:
```
```js
function World({attach, parameters}) {
this.attach = attach
this.parameters = parameters
attach = attach
parameters = parameters
}
```

* `attach` - a function hooks / steps can use to add [attachments](./attachments.md)
* `parameters` - world parameters passed in through the [cli](../cli.md#world-parameters)

**Note:** The World constructor was made strictly synchronous in *[v0.8.0](https://github.com/cucumber/cucumber-js/releases/tag/v0.8.0)*.

---

#### `Then(pattern[, options], fn)`

Alias of `defineStep`.

---

#### `When(pattern[, options], fn)`

Alias of `defineStep`.
86 changes: 53 additions & 33 deletions docs/support_files/attachments.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ The world constructor is passed an `attach` function,
which the default world constructor assigns to `this.attach`.

``` javascript
this.After(function () {
this.attach('Some text');
var {defineSupportCode} = require('cucumber');

defineSupportCode(function({After}) {
After(function () {
this.attach('Some text');
});
});
```

By default, text is saved with a MIME type of `text/plain`. You can also specify
a different MIME type:

``` javascript
this.After(function () {
this.attach('{"name": "some JSON"}', 'application/json');
var {defineSupportCode} = require('cucumber');

defineSupportCode(function({After}) {
After(function () {
this.attach('{"name": "some JSON"}', 'application/json');
});
});
```

Expand All @@ -24,49 +32,61 @@ The data will be `base64` encoded in the output.
You should wait for the stream to be read before continuing by providing a callback or waiting for the returned promise to resolve.

``` javascript
// Passing a callback
this.After(function (scenarioResult, callback) {
if (scenarioResult.isFailed()) {
var stream = getScreenshotOfError();
this.attach(stream, 'image/png', callback);
}
else {
callback();
}
});
var {defineSupportCode} = require('cucumber');

// Returning the promise
this.After(function (scenarioResult) {
if (scenarioResult.isFailed()) {
var stream = getScreenshotOfError();
return this.attach(stream, 'image/png');
}
defineSupportCode(function({After}) {
// Passing a callback
After(function (scenarioResult, callback) {
if (scenarioResult.isFailed()) {
var stream = getScreenshotOfError();
this.attach(stream, 'image/png', callback);
}
else {
callback();
}
});

// Returning the promise
After(function (scenarioResult) {
if (scenarioResult.isFailed()) {
var stream = getScreenshotOfError();
return this.attach(stream, 'image/png');
}
});
});
```

Images and binary data can also be attached using a [Buffer](https://nodejs.org/api/buffer.html).
The data will be `base64` encoded in the output.

``` javascript
this.After(function (scenarioResult) {
if (scenarioResult.isFailed()) {
var buffer = getScreenshotOfError();
this.attach(buffer, 'image/png');
}
var {defineSupportCode} = require('cucumber');

defineSupportCode(function({After}) {
After(function (scenarioResult) {
if (scenarioResult.isFailed()) {
var buffer = getScreenshotOfError();
this.attach(buffer, 'image/png');
}
});
});
```

Here is an example of saving a screenshot using [Selenium WebDriver](https://www.npmjs.com/package/selenium-webdriver)
when a scenario fails:

``` javascript
this.After(function (scenarioResult) {
var world = this;
if (scenarioResult.isFailed()) {
return webDriver.takeScreenshot().then(function(screenShot) {
// screenShot is a base-64 encoded PNG
world.attach(screenShot, 'image/png');
});
}
var {defineSupportCode} = require('cucumber');

defineSupportCode(function({After}) {
After(function (scenarioResult) {
var world = this;
if (scenarioResult.isFailed()) {
return webDriver.takeScreenshot().then(function(screenShot) {
// screenShot is a base-64 encoded PNG
world.attach(screenShot, 'image/png');
});
}
});
});
```
20 changes: 10 additions & 10 deletions docs/support_files/event_handlers.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,28 @@ Handlers can be synchronous, return a promise, accept an additional callback arg

```javascript
// features/support/handlers.js
var myHandlers = function () {
this.registerHandler('AfterFeatures', function (features, callback) {
var {defineSupportCode} = require('cucumber');

defineSupportCode(function({registerHandler}) {
registerHandler('AfterFeatures', function (features, callback) {
// clean up!
// There is no World instance available on `this`
// because all scenarios are done and World instances are long gone.
callback();
});
}

module.exports = myHandlers;
});
```

Handlers timeout the same as steps / hooks and can have their timeout changed
by passing in an options object.

```javascript
// features/support/handlers.js
var myHandlers = function () {
this.registerHandler('AfterFeatures', {timeout: 10000}, function (features, callback) {
var {defineSupportCode} = require('cucumber');

defineSupportCode(function({registerHandler}) {
registerHandler('AfterFeatures', {timeout: 10000}, function (features, callback) {
//...
});
}

module.exports = myHandlers;
});
```
Loading

0 comments on commit fa39a28

Please sign in to comment.