Skip to content

Commit 7d7ba96

Browse files
author
charlierudolph
committed
add full support to registerHandler
resolves #487 resolves #488 resolves #490
1 parent 1b94268 commit 7d7ba96

33 files changed

+637
-568
lines changed

README.md

+42-10
Original file line numberDiff line numberDiff line change
@@ -413,24 +413,56 @@ this.After(function (scenario, callback) {
413413
});
414414
```
415415

416-
##### After features event
417-
418-
The *after features event* is emitted once all features have been executed, just before the process exits. It can be used for tasks such as closing your browser after running automated browser tests with [selenium](https://code.google.com/p/selenium/wiki/WebDriverJs) or [phantomjs](http://phantomjs.org/).
419-
420-
note: There are "Before" and "After" events for each of the following: "Features", "Feature", "Scenario", "Step" as well as the standalone events "Background" and "StepResult". e.g. "BeforeScenario".
416+
##### Event Handlers
417+
418+
You can register event handlers for the following events within the cucumber lifecycle.
419+
420+
| Event | Object |
421+
|----------------|-----------------------------------------------------------|
422+
| BeforeFeatures | array of [Features](lib/cucumber/ast/feature.js) |
423+
| BeforeFeature | [Feature](lib/cucumber/ast/feature.js) |
424+
| BeforeScenario | [Scenario](lib/cucumber/ast/scenario.js) |
425+
| BeforeStep | [Step](lib/cucumber/ast/step.js) |
426+
| StepResult | [StepResult](lib/cucumber/runtime/step_result.js) |
427+
| AfterStep | [Step](lib/cucumber/ast/step.js) |
428+
| ScenarioResult | [ScenarioResult](lib/cucumber/runtime/scenario_result.js) |
429+
| AfterScenario | [Scenario](lib/cucumber/ast/scenario.js) |
430+
| AfterFeature | [Feature](lib/cucumber/ast/feature.js) |
431+
| FeaturesResult | [FeaturesResult](lib/cucumber/runtime/features_result.js) |
432+
| AfterFeatures | array of [Features](lib/cucumber/ast/feature.js) |
433+
434+
Hooks also trigger `BeforeStep`, `StepResult`, and `AfterStep` events with the object
435+
[HookStep](lib/cucumber/ast/hook_step.js)
436+
437+
Handlers will be passed the associated object as the first argument.
438+
Handlers can be synchronous, return a promise, accept an additional callback argument, or use generators.
421439

422440
```javascript
423-
// features/support/after_hooks.js
424-
var myAfterHooks = function () {
425-
this.registerHandler('AfterFeatures', function (event, callback) {
441+
// features/support/handlers.js
442+
var myHandlers = function () {
443+
this.registerHandler('AfterFeatures', function (features, callback) {
426444
// clean up!
427-
// Be careful, there is no World instance available on `this` here
445+
// There is no World instance available on `this`
428446
// because all scenarios are done and World instances are long gone.
429447
callback();
430448
});
431449
}
432450

433-
module.exports = myAfterHooks;
451+
module.exports = myHandlers;
452+
```
453+
454+
Handlers timeout the same as steps / hooks and can have their timeout changed
455+
by passing in an options object.
456+
457+
```javascript
458+
// features/support/handlers.js
459+
var myHandlers = function () {
460+
this.registerHandler('AfterFeatures', {timeout: 10000}, function (features, callback) {
461+
//...
462+
});
463+
}
464+
465+
module.exports = myHandlers;
434466
```
435467

436468
### CLI

cucumber.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
common = '--strict --format rerun:@rerun.txt'
1+
common = '--strict --format progress --format rerun:@rerun.txt'
22

33
module.exports = {
4-
build: common + ' --format progress',
54
'default': common,
6-
'es5': '--tags ~@es6'
5+
'es5': common + ' --tags ~@es6'
76
};

features/cli.feature

-42
Original file line numberDiff line numberDiff line change
@@ -191,45 +191,3 @@ Scenario: run a single failing feature
191191
<duration-stat>
192192
"""
193193
And the exit status should be 1
194-
195-
Scenario: run a single failing feature with an AfterFeatures hook
196-
Given a file named "features/a.feature" with:
197-
"""
198-
Feature: some feature
199-
Scenario: some scenario
200-
When a step is failing
201-
"""
202-
And a file named "features/step_definitions/cucumber_steps.js" with:
203-
"""
204-
var cucumberSteps = function() {
205-
this.When(/^a step is failing$/, function(callback) { callback("forced error"); });
206-
};
207-
module.exports = cucumberSteps;
208-
"""
209-
And a file named "features/support/hooks.js" with:
210-
"""
211-
var hooks = function() {
212-
this.registerHandler('AfterFeatures', function (event, callback) {
213-
callback();
214-
});
215-
};
216-
module.exports = hooks;
217-
"""
218-
When I run cucumber.js with `-f progress features/a.feature`
219-
Then it outputs this text:
220-
"""
221-
F
222-
223-
Failures:
224-
225-
1) Scenario: some scenario - features/a.feature:2
226-
Step: When a step is failing - features/a.feature:3
227-
Step Definition: features/step_definitions/cucumber_steps.js:2
228-
Message:
229-
forced error
230-
231-
1 scenario (1 failed)
232-
1 step (1 failed)
233-
<duration-stat>
234-
"""
235-
And the exit status should be 1

features/register_handler.feature

+203
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
Feature: Register Handler
2+
3+
Background:
4+
Given a file named "features/my_feature.feature" with:
5+
"""
6+
Feature: a feature
7+
Scenario: a scenario
8+
Given a step
9+
"""
10+
And a file named "features/step_definitions/my_steps.js" with:
11+
"""
12+
var stepDefinitions = function() {
13+
this.When(/^a step$/, function () {});
14+
};
15+
16+
module.exports = stepDefinitions;
17+
"""
18+
19+
Scenario: synchronous
20+
Given a file named "features/support/handlers.js" with:
21+
"""
22+
var handlers = function() {
23+
this.registerHandler('AfterFeatures', function () {});
24+
};
25+
26+
module.exports = handlers;
27+
"""
28+
When I run cucumber.js
29+
And the exit status should be 0
30+
31+
Scenario: synchronously throws
32+
Given a file named "features/support/handlers.js" with:
33+
"""
34+
var handlers = function() {
35+
this.registerHandler('AfterFeatures', function(){
36+
throw new Error('my error');
37+
});
38+
};
39+
40+
module.exports = handlers;
41+
"""
42+
When I run cucumber.js
43+
And the exit status should be non-zero
44+
And the error output contains the text:
45+
"""
46+
features/support/handlers.js:2 my error
47+
"""
48+
49+
Scenario: callback without error
50+
Given a file named "features/support/handlers.js" with:
51+
"""
52+
var handlers = function() {
53+
this.registerHandler('AfterFeatures', function(features, callback) {
54+
setTimeout(function () {
55+
callback();
56+
});
57+
});
58+
};
59+
60+
module.exports = handlers;
61+
"""
62+
When I run cucumber.js
63+
And the exit status should be 0
64+
65+
Scenario: callback with error
66+
Given a file named "features/support/handlers.js" with:
67+
"""
68+
var handlers = function() {
69+
this.registerHandler('AfterFeatures', function(features, callback) {
70+
setTimeout(function() {
71+
callback(new Error('my error'));
72+
});
73+
});
74+
};
75+
76+
module.exports = handlers
77+
"""
78+
When I run cucumber.js
79+
And the exit status should be non-zero
80+
And the error output contains the text:
81+
"""
82+
features/support/handlers.js:2 my error
83+
"""
84+
85+
Scenario: callback asynchronously throws
86+
Given a file named "features/support/handlers.js" with:
87+
"""
88+
var handlers = function() {
89+
this.registerHandler('AfterFeatures', function(features, callback) {
90+
setTimeout(function(){
91+
throw new Error('my error');
92+
});
93+
});
94+
};
95+
96+
module.exports = handlers;
97+
"""
98+
When I run cucumber.js
99+
And the exit status should be non-zero
100+
101+
Scenario: callback - returning a promise
102+
Given a file named "features/support/handlers.js" with:
103+
"""
104+
var handlers = function() {
105+
this.registerHandler('AfterFeatures', function(features, callback) {
106+
return {
107+
then: function() {}
108+
};
109+
});
110+
};
111+
112+
module.exports = handlers;
113+
"""
114+
When I run cucumber.js
115+
And the exit status should be non-zero
116+
And the error output contains the text:
117+
"""
118+
features/support/handlers.js:2 function accepts a callback and returns a promise
119+
"""
120+
121+
Scenario: promise resolves
122+
Given a file named "features/support/handlers.js" with:
123+
"""
124+
var handlers = function() {
125+
this.registerHandler('AfterFeatures', function() {
126+
return {
127+
then: function(resolve, reject) {
128+
setTimeout(resolve);
129+
}
130+
};
131+
});
132+
};
133+
134+
module.exports = handlers;
135+
"""
136+
When I run cucumber.js
137+
And the exit status should be 0
138+
139+
Scenario: promise rejects with error
140+
Given a file named "features/support/handlers.js" with:
141+
"""
142+
var handlers = function() {
143+
this.registerHandler('AfterFeatures', function() {
144+
return {
145+
then: function(resolve, reject) {
146+
setTimeout(function () {
147+
reject(new Error('my error'));
148+
});
149+
}
150+
};
151+
});
152+
};
153+
154+
module.exports = handlers;
155+
"""
156+
When I run cucumber.js
157+
And the exit status should be non-zero
158+
And the error output contains the text:
159+
"""
160+
features/support/handlers.js:2 my error
161+
"""
162+
163+
Scenario: promise rejects without error
164+
Given a file named "features/support/handlers.js" with:
165+
"""
166+
var handlers = function() {
167+
this.registerHandler('AfterFeatures', function() {
168+
return {
169+
then: function(resolve, reject) {
170+
setTimeout(reject);
171+
}
172+
};
173+
});
174+
};
175+
176+
module.exports = handlers
177+
"""
178+
When I run cucumber.js
179+
And the exit status should be non-zero
180+
And the error output contains the text:
181+
"""
182+
features/support/handlers.js:2 Promise rejected
183+
"""
184+
185+
Scenario: promise asynchronously throws
186+
Given a file named "features/support/handlers.js" with:
187+
"""
188+
var handlers = function(){
189+
this.registerHandler('AfterFeatures', function() {
190+
return {
191+
then: function(resolve, reject) {
192+
setTimeout(function(){
193+
throw new Error('my error');
194+
});
195+
}
196+
};
197+
});
198+
};
199+
200+
module.exports = handlers;
201+
"""
202+
When I run cucumber.js
203+
And the exit status should be non-zero
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
Feature: registerHandler timeouts
2+
3+
Background:
4+
Given a file named "features/a.feature" with:
5+
"""
6+
Feature:
7+
Scenario:
8+
Given a passing step
9+
"""
10+
And a file named "features/step_definitions/steps.js" with:
11+
"""
12+
module.exports = function() {
13+
this.Given(/^a passing step$/, function() {});
14+
};
15+
"""
16+
17+
Scenario: slow handler timeout
18+
Given a file named "features/supports/handlers.js" with:
19+
"""
20+
module.exports = function() {
21+
this.setDefaultTimeout(500);
22+
23+
this.registerHandler('AfterFeatures', function(features, callback) {
24+
setTimeout(callback, 1000);
25+
});
26+
};
27+
"""
28+
When I run cucumber.js with `--strict`
29+
Then the error output contains the text:
30+
"""
31+
features/supports/handlers.js:4 function timed out after 500 milliseconds
32+
"""
33+
And the exit status should be non-zero
34+
35+
36+
Scenario: slow handler can increase their timeout
37+
Given a file named "features/supports/handlers.js" with:
38+
"""
39+
module.exports = function() {
40+
this.setDefaultTimeout(500);
41+
42+
this.registerHandler('AfterFeatures', {timeout: 1500}, function(features, callback) {
43+
setTimeout(callback, 1000);
44+
});
45+
};
46+
"""
47+
When I run cucumber.js with `--strict`
48+
Then the exit status should be 0

0 commit comments

Comments
 (0)