Skip to content

Commit 1ecac46

Browse files
Add BeforeAll and AfterAll hooks (#1569)
* Add a feature for BeforeAll hook * Add BeforeAll hook * Add an AfterAll_hook feature * Add AfterAll hook * Move all hook related features into a dedicated sub-folder * Add a scenario for AfterAll to make sure it is invoked even after failed scenario * [skip ci] Update CHANGELOG.md * Draft a documentation for hooks * Add some sugar to hooks README * Adlinks to new hooks documentation in CHANGELOG.md * Do not execute BeforeAll and AfterAll hooks in dry-run mode
1 parent ce1ba5f commit 1ecac46

File tree

14 files changed

+333
-0
lines changed

14 files changed

+333
-0
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo
1414

1515
### Added
1616

17+
- New `BeforeAll` and `AfterAll` hooks
18+
19+
More information about hooks can be found in
20+
[features/docs/writing_support_code/hooks/README.md](./features/docs/writing_support_code/hooks/README.md).
21+
22+
([1569](https://github.com/cucumber/cucumber-ruby/pull/1569)
23+
[aurelien-reeves](https://github.com/aurelien-reeves))
24+
1725
- New hook: `InstallPlugin`
1826

1927
It is intended to be used to install an external plugin, like cucumber-ruby-wire.
@@ -26,6 +34,9 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo
2634
See [cucumber-ruby-wire](https://github.com/cucumber/cucumber-ruby-wire/) for a
2735
usage example.
2836

37+
More information about hooks can be found in
38+
[features/docs/writing_support_code/hooks/README.md](./features/docs/writing_support_code/hooks/README.md).
39+
2940
([1564](https://github.com/cucumber/cucumber-ruby/pull/1564)
3041
[aurelien-reeves](https://github.com/aurelien-reeves))
3142

features/docs/cli/dry_run.feature

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,34 @@ Feature: Dry Run
8484
1 step (1 undefined)
8585
8686
"""
87+
88+
Scenario: With BeforeAll and AfterAll hooks
89+
Given a file named "features/test.feature" with:
90+
"""
91+
Feature:
92+
Scenario:
93+
Given this step passes
94+
"""
95+
And the standard step definitions
96+
And a file named "features/step_definitions/support.rb" with:
97+
"""
98+
BeforeAll do
99+
raise "BeforeAll hook error has been raised"
100+
end
101+
102+
AfterAll do
103+
raise "AfterAll hook error has been raised"
104+
end
105+
"""
106+
When I run `cucumber features/test.feature --publish-quiet --dry-run`
107+
Then it should pass with exactly:
108+
"""
109+
Feature:
110+
111+
Scenario: # features/test.feature:2
112+
Given this step passes # features/step_definitions/steps.rb:1
113+
114+
1 scenario (1 skipped)
115+
1 step (1 skipped)
116+
117+
"""
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Cucumber Hooks
2+
3+
Cucumber proposes several hooks to let you specify some code to be executed at
4+
different stages of test execution, like before or after the execution of a
5+
scenario.
6+
7+
Hooks are part of your support code.
8+
9+
They are executed in the following order:
10+
11+
- [AfterConfiguration](#afterconfiguration-and-installplugin)
12+
- [InstallPlugin](#afterconfiguration-and-installplugin)
13+
- [BeforeAll](#beforeall-and-afterall)
14+
- Per scenario:
15+
- [Around](#around)
16+
- [Before](#before-and-after)
17+
- Per step:
18+
- [AfterStep](#afterstep)
19+
- [After](#before-and-after)
20+
- [AfterAll](#beforeall-and-afterall)
21+
22+
You can define as many hooks as you want. If you have several hooks of the same
23+
types - for example, several `BeforeAll` hooks - they will be all executed once.
24+
25+
Multiple hooks of the same type are executed in the order that they were defined.
26+
If you wish to control this order, use manual requires in `env.rb` - This file is
27+
loaded first - or migrate them all to one `hooks.rb` file.
28+
29+
## AfterConfiguration and InstallPlugin
30+
31+
[`AfterConfiguration`](#afterconfiguration) and [`InstallPlugin`](#installplugin)
32+
hooks are dedicated to plugins and are meant to extend Cucumber. For example,
33+
[`AfterConfiguration`](#afterconfiguration) allows you to dynamically change the
34+
configuration before the execution of the tests, and [`InstallPlugin`](#installplugin)
35+
allows to have some code that would have deeper impact on the execution.
36+
37+
### AfterConfiguration
38+
39+
**Note:** this is a legacy hook. You may consider using [`InstallPlugin`](#installplugin) instead.
40+
41+
```ruby
42+
AfterConfiguration do |configuration|
43+
# configuration is an instance of Cucumber::Configuration defined in
44+
# lib/cucumber/configuration.rb.
45+
end
46+
```
47+
48+
### InstallPlugin
49+
50+
In addition to the configuration, `InstallPlugin` also has access to some of Cucumber
51+
internals through a `RegistryWrapper`, defined in
52+
[lib/cucumber/glue/registry_wrapper.rb](../../../../lib/cucumber/glue/registry_wrapper.rb).
53+
54+
```ruby
55+
InstallPlugin do |configuration, registry|
56+
# configuration is an instance of Cucumber::Configuration defined in
57+
# lib/cucumber/configuration.rb
58+
#
59+
# registry is an instance of Cucumber::Glue::RegistryWrapper defined in
60+
# lib/cucumber/glue/registry_wrapper.rb
61+
end
62+
```
63+
64+
You can see an example in the [Cucumber Wire plugin](https://github.com/cucumber/cucumber-ruby-wire).
65+
66+
## BeforeAll and AfterAll
67+
68+
`BeforeAll` is executed once before the execution of the first scenario. `AfterAll`
69+
is executed once after the execution of the last scenario.
70+
71+
These two types of hooks have no parameters. Their purpose is to set-up and/or clean-up
72+
your environment not related to Cucumber, like a database or a browser.
73+
74+
```ruby
75+
BeforeAll do
76+
# snip
77+
end
78+
79+
AfterAll do
80+
# snip
81+
end
82+
```
83+
84+
## Around
85+
86+
**Note:** `Around` is a legacy hook and its usage is discouraged in favor of
87+
[`Before` and `After`](#before-and-after) hooks.
88+
89+
`Around` is a special hook which allows you to have a block syntax. Its original
90+
purpose was to support some databases with only block syntax for transactions.
91+
92+
```ruby
93+
Around do |scenario, block|
94+
SomeDatabase::begin_transaction do # this is just for illustration
95+
block.call
96+
end
97+
end
98+
```
99+
100+
## Before and After
101+
102+
`Before` is executed before each test case. `After` is executed after each test case.
103+
They both have the test case being executed as a parameter. Within the `After` hook,
104+
the status of the test case is also available.
105+
106+
```ruby
107+
Before do |test_case|
108+
log test_case.name
109+
end
110+
111+
After do |test_case|
112+
log test_case.failed?
113+
log test_case.status
114+
end
115+
```
116+
117+
## AfterStep
118+
119+
`AfterStep` is executed after each step of a test. If steps are not executed due
120+
to a previous failure, `AfterStep` won't be executed either.
121+
122+
```ruby
123+
AfterStep do |result, test_step|
124+
log test_step.inspect # test_step is a Cucumber::Core::Test::Step
125+
log result.inspect # result is a Cucumber::Core::Test::Result
126+
end
127+
```
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
Feature: AfterAll Hooks
2+
3+
AfterAll hooks can be used if you have some clean-up to be done after all
4+
scenarios have been executed.
5+
6+
Scenario: A single AfterAll hook
7+
8+
An AfterAll hook will be invoked a single time after all the scenarios have
9+
been executed.
10+
11+
Given a file named "features/f.feature" with:
12+
"""
13+
Feature: AfterAll hook
14+
Scenario: #1
15+
Then the AfterAll hook has not been called yet
16+
17+
Scenario: #2
18+
Then the AfterAll hook has not been called yet
19+
"""
20+
And a file named "features/step_definitions/steps.rb" with:
21+
"""
22+
hookCalled = 0
23+
24+
AfterAll do
25+
hookCalled += 1
26+
27+
raise "AfterAll hook error has been raised"
28+
end
29+
30+
Then /^the AfterAll hook has not been called yet$/ do
31+
expect(hookCalled).to eq 0
32+
end
33+
"""
34+
When I run `cucumber features/f.feature --publish-quiet`
35+
Then it should fail with:
36+
"""
37+
Feature: AfterAll hook
38+
39+
Scenario: #1 # features/f.feature:2
40+
Then the AfterAll hook has not been called yet # features/step_definitions/steps.rb:9
41+
42+
Scenario: #2 # features/f.feature:5
43+
Then the AfterAll hook has not been called yet # features/step_definitions/steps.rb:9
44+
45+
2 scenarios (2 passed)
46+
2 steps (2 passed)
47+
"""
48+
And the output should contain:
49+
"""
50+
AfterAll hook error has been raised (RuntimeError)
51+
"""
52+
53+
Scenario: It is invoked also when scenario has failed
54+
55+
Given a file named "features/f.feature" with:
56+
"""
57+
Feature: AfterAll hook
58+
Scenario: failed
59+
Given a failed step
60+
"""
61+
And a file named "features/step_definitions/steps.rb" with:
62+
"""
63+
AfterAll do
64+
raise "AfterAll hook error has been raised"
65+
end
66+
67+
Given /^a failed step$/ do
68+
expect(0).to eq 1
69+
end
70+
"""
71+
When I run `cucumber features/f.feature --publish-quiet`
72+
Then it should fail with:
73+
"""
74+
1 scenario (1 failed)
75+
1 step (1 failed)
76+
"""
77+
And the output should contain:
78+
"""
79+
AfterAll hook error has been raised (RuntimeError)
80+
"""
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Feature: BeforeAll Hooks
2+
3+
BeforeAll hooks can be used if you have some set-up to be done before all
4+
scenarios are executed.
5+
6+
BeforeAll hooks are not aware of your configuration. Use AfterConfiguration if
7+
you need it.
8+
9+
Scenario: A single BeforeAll hook
10+
11+
A BeforeAll hook will be invoked a single time before all the scenarios are
12+
executed.
13+
14+
Given a file named "features/f.feature" with:
15+
"""
16+
Feature: BeforeAll hook
17+
Scenario: #1
18+
Then the BeforeAll hook has been called
19+
20+
Scenario: #2
21+
Then the BeforeAll hook has been called
22+
"""
23+
And a file named "features/step_definitions/steps.rb" with:
24+
"""
25+
hookCalled = 0
26+
27+
BeforeAll do
28+
hookCalled += 1
29+
end
30+
31+
Then /^the BeforeAll hook has been called$/ do
32+
expect(hookCalled).to eq 1
33+
end
34+
"""
35+
When I run `cucumber features/f.feature`
36+
Then it should pass with:
37+
"""
38+
Feature: BeforeAll hook
39+
40+
Scenario: #1 # features/f.feature:2
41+
Then the BeforeAll hook has been called # features/step_definitions/steps.rb:7
42+
43+
Scenario: #2 # features/f.feature:5
44+
Then the BeforeAll hook has been called # features/step_definitions/steps.rb:7
45+
46+
2 scenarios (2 passed)
47+
2 steps (2 passed)
48+
49+
"""

0 commit comments

Comments
 (0)