Skip to content

Commit 47ff1b8

Browse files
Add support for named hooks (#1636)
* Add support for named hooks * Bump the CCK to 9.2.1 * Pin capybara to < 3.37 to support ruby 2.6 * Add a dedicated feature for named hooks * Update hooks documentation * Update CHANGELOG
1 parent 9ed77b3 commit 47ff1b8

File tree

7 files changed

+128
-32
lines changed

7 files changed

+128
-32
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo
2222
([PR#1612](https://github.com/cucumber/cucumber-ruby/pull/1612)
2323
[gogainda](https://github.com/gogainda))
2424

25+
- Add support for named hooks
26+
([PR#1636](https://github.com/cucumber/cucumber-ruby/pull/1636))
27+
2528
### Fixed
2629

2730
- Use `required_rubygems_version` instead of `rubygems_version`([PR#1629](https://github.com/cucumber/cucumber-ruby/pull/1629))

cucumber.gemspec

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,22 @@ Gem::Specification.new do |s|
2020
# Keep in sync with .circleci/config.yml & .rubocop.yml
2121
s.required_ruby_version = '>= 2.6'
2222
s.add_dependency 'builder', '~> 3.2', '>= 3.2.4'
23-
s.add_dependency 'cucumber-ci-environment', '~> 8.1', '>= 8.1.0'
24-
s.add_dependency 'cucumber-core', '~> 10.1', '>= 10.1.1'
25-
s.add_dependency 'cucumber-cucumber-expressions', '~> 15.0', '>= 15.0.1'
26-
s.add_dependency 'cucumber-gherkin', '~> 22.0', '>= 22.0.0'
27-
s.add_dependency 'cucumber-html-formatter', '~> 17.0', '>= 17.0.0'
28-
s.add_dependency 'cucumber-messages', '~> 17.1', '>= 17.1.1'
23+
s.add_dependency 'cucumber-ci-environment', '~> 9.0', '>= 9.0.4'
24+
s.add_dependency 'cucumber-core', '~> 11.0', '>= 11.0.0'
25+
s.add_dependency 'cucumber-cucumber-expressions', '~> 15.1', '>= 15.1.1'
26+
s.add_dependency 'cucumber-gherkin', '~> 23.0', '>= 23.0.1'
27+
s.add_dependency 'cucumber-html-formatter', '~> 19.1', '>= 19.1.0'
28+
s.add_dependency 'cucumber-messages', '~> 18.0', '>= 18.0.0'
2929
s.add_dependency 'diff-lcs', '~> 1.5', '>= 1.5.0'
3030
s.add_dependency 'mime-types', '~> 3.4', '>= 3.4.1'
31-
s.add_dependency 'multi_test', '~> 0.1', '>= 0.1.2'
31+
s.add_dependency 'multi_test', '~> 1.1', '>= 1.1.0'
3232
s.add_dependency 'sys-uname', '~> 1.2', '>= 1.2.2'
3333

34-
s.add_development_dependency 'cucumber-compatibility-kit', '~> 9.1', '>= 9.1.2'
35-
s.add_development_dependency 'nokogiri', '~> 1.13', '>= 1.13.1'
34+
s.add_development_dependency 'cucumber-compatibility-kit', '~> 9.2', '>= 9.2.1'
35+
s.add_development_dependency 'nokogiri', '~> 1.13', '>= 1.13.6'
3636
s.add_development_dependency 'pry', '~> 0.14', '>= 0.14.1'
3737
s.add_development_dependency 'rake', '~> 13.0', '>= 13.0.6'
38-
s.add_development_dependency 'rspec', '~> 3.10', '>= 3.10.0'
38+
s.add_development_dependency 'rspec', '~> 3.11', '>= 3.11.0'
3939
s.add_development_dependency 'simplecov', '~> 0.21', '>= 0.21.2'
4040
s.add_development_dependency 'syntax', '~> 1.2', '>= 1.2.2'
4141
s.add_development_dependency 'test-unit', '~> 3.5', '>= 3.5.3'
@@ -45,9 +45,9 @@ Gem::Specification.new do |s|
4545
s.add_development_dependency 'octokit', '~> 4.22', '>= 4.22.0'
4646

4747
# Needed for examples (rake examples)
48-
s.add_development_dependency 'capybara', '~> 3.36', '>= 3.36.0'
48+
s.add_development_dependency 'capybara', '~> 3.36', '>= 3.36.0', '< 3.37'
4949
s.add_development_dependency 'rack-test', '~> 1.1', '>= 1.1.0'
50-
s.add_development_dependency 'sinatra', '~> 2.1', '>= 2.1.0'
50+
s.add_development_dependency 'sinatra', '~> 2.2', '>= 2.2.0'
5151

5252
s.required_rubygems_version = '>= 1.6.1'
5353
s.files = Dir[

features/docs/writing_support_code/hooks/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ Multiple hooks of the same type are executed in the order that they were defined
2525
If you wish to control this order, use manual requires in `env.rb` - This file is
2626
loaded first - or migrate them all to one `hooks.rb` file.
2727

28+
Finaly, all hooks can be given a name to improve reporting and help debugging.
29+
30+
Note: Hooks names are only reported when using the message and the html formatters.
31+
2832
## InstallPlugin
2933

3034
[`InstallPlugin`](#installplugin) hook is dedicated to using plugins and is meant to
@@ -43,6 +47,12 @@ InstallPlugin do |configuration, registry|
4347
# registry is an instance of Cucumber::Glue::RegistryWrapper defined in
4448
# lib/cucumber/glue/registry_wrapper.rb
4549
end
50+
51+
# named hook:
52+
53+
InstallPlugin(name: 'Installation of a plugin') do |configuration, registry|
54+
# The name is optional
55+
end
4656
```
4757

4858
You can see an example in the [Cucumber Wire plugin](https://github.com/cucumber/cucumber-ruby-wire).
@@ -63,6 +73,16 @@ end
6373
AfterAll do
6474
# snip
6575
end
76+
77+
# Named hooks:
78+
79+
BeforeAll(name: 'Name of the hook') do
80+
# snip
81+
end
82+
83+
AfterAll(name: 'Name of the hook') do
84+
# snip
85+
end
6686
```
6787

6888
## Around
@@ -79,6 +99,12 @@ Around do |scenario, block|
7999
block.call
80100
end
81101
end
102+
103+
# with a name:
104+
105+
Around(name: 'Name of the hook') do |scenario, block|
106+
# snip
107+
end
82108
```
83109

84110
## Before and After
@@ -96,6 +122,16 @@ After do |test_case|
96122
log test_case.failed?
97123
log test_case.status
98124
end
125+
126+
# With names:
127+
128+
Before(name: 'Name of the hook') do |test_case|
129+
# snip
130+
end
131+
132+
After(name: 'Name of the hook') do |test_case|
133+
# snip
134+
end
99135
```
100136

101137
## AfterStep
@@ -108,4 +144,10 @@ AfterStep do |result, test_step|
108144
log test_step.inspect # test_step is a Cucumber::Core::Test::Step
109145
log result.inspect # result is a Cucumber::Core::Test::Result
110146
end
147+
148+
# with a name:
149+
150+
AfterStep(name: 'Named hook') do |result, test_step|
151+
# snip
152+
end
111153
```
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Feature: Named hooks
2+
3+
In order to spot errors easily in hooks
4+
As a developer
5+
I can give names to hooks
6+
7+
Scenario: Hooks can be named
8+
Given a file named "features/support/env.rb" with:
9+
"""
10+
Before(name: 'Named before hook') do
11+
# no-op
12+
end
13+
"""
14+
And a file named "features/simple_scenario.feature" with:
15+
"""
16+
Feature:
17+
Scenario:
18+
Given a step
19+
"""
20+
When I run `cucumber features --publish-quiet --format message`
21+
Then the stderr should not contain anything
22+
And the output should contain NDJSON with key "name" and value "Named before hook"
23+
24+
Scenario: All kind of hooks can be named
25+
Given a file named "features/support/env.rb" with:
26+
"""
27+
Before(name: 'Named before hook') {}
28+
After(name: 'Named after hook') {}
29+
BeforeAll(name: 'Named before_all hook') {}
30+
AfterAll(name: 'Named after_all hook') {}
31+
AfterStep(name: 'Named after_step hook') {}
32+
Around(name: 'Named around hook') {}
33+
InstallPlugin(name: 'Named install_plugin hook') {}
34+
"""
35+
And a file named "features/simple_scenario.feature" with:
36+
"""
37+
Feature:
38+
Scenario:
39+
Given a step
40+
"""
41+
When I run `cucumber features --publish-quiet --format message`
42+
Then the stderr should not contain anything
43+
And the output should contain NDJSON with key "name" and value "Named before hook"
44+
And the output should contain NDJSON with key "name" and value "Named after hook"
45+
And the output should contain NDJSON with key "name" and value "Named before_all hook"
46+
And the output should contain NDJSON with key "name" and value "Named after_all hook"
47+
And the output should contain NDJSON with key "name" and value "Named after_step hook"
48+
And the output should contain NDJSON with key "name" and value "Named around hook"
49+
And the output should contain NDJSON with key "name" and value "Named install_plugin hook"

lib/cucumber/glue/dsl.rb

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ def build_rb_world_factory(world_modules, namespaced_world_modules, proc)
1919
@rb_language.build_rb_world_factory(world_modules, namespaced_world_modules, proc)
2020
end
2121

22-
def register_rb_hook(phase, tag_names, proc)
23-
@rb_language.register_rb_hook(phase, tag_names, proc)
22+
def register_rb_hook(phase, tag_names, proc, name: nil)
23+
@rb_language.register_rb_hook(phase, tag_names, proc, name: name)
2424
end
2525

2626
def define_parameter_type(parameter_type)
@@ -62,29 +62,29 @@ def World(*world_modules, **namespaced_world_modules, &proc)
6262

6363
# Registers a proc that will run before each Scenario. You can register as many
6464
# as you want (typically from ruby scripts under <tt>support/hooks.rb</tt>).
65-
def Before(*tag_expressions, &proc)
66-
Dsl.register_rb_hook('before', tag_expressions, proc)
65+
def Before(*tag_expressions, name: nil, &proc)
66+
Dsl.register_rb_hook('before', tag_expressions, proc, name: name)
6767
end
6868

6969
# Registers a proc that will run after each Scenario. You can register as many
7070
# as you want (typically from ruby scripts under <tt>support/hooks.rb</tt>).
71-
def After(*tag_expressions, &proc)
72-
Dsl.register_rb_hook('after', tag_expressions, proc)
71+
def After(*tag_expressions, name: nil, &proc)
72+
Dsl.register_rb_hook('after', tag_expressions, proc, name: name)
7373
end
7474

7575
# Registers a proc that will be wrapped around each scenario. The proc
7676
# should accept two arguments: two arguments: the scenario and a "block"
7777
# argument (but passed as a regular argument, since blocks cannot accept
7878
# blocks in 1.8), on which it should call the .call method. You can register
7979
# as many as you want (typically from ruby scripts under <tt>support/hooks.rb</tt>).
80-
def Around(*tag_expressions, &proc)
81-
Dsl.register_rb_hook('around', tag_expressions, proc)
80+
def Around(*tag_expressions, name: nil, &proc)
81+
Dsl.register_rb_hook('around', tag_expressions, proc, name: name)
8282
end
8383

8484
# Registers a proc that will run after each Step. You can register as
8585
# as you want (typically from ruby scripts under <tt>support/hooks.rb</tt>).
86-
def AfterStep(*tag_expressions, &proc)
87-
Dsl.register_rb_hook('after_step', tag_expressions, proc)
86+
def AfterStep(*tag_expressions, name: nil, &proc)
87+
Dsl.register_rb_hook('after_step', tag_expressions, proc, name: name)
8888
end
8989

9090
def ParameterType(options)
@@ -108,20 +108,20 @@ def if_nil(value, default)
108108
end
109109

110110
# Registers a proc that will run after Cucumber is configured in order to install an external plugin.
111-
def InstallPlugin(&proc)
112-
Dsl.register_rb_hook('install_plugin', [], proc)
111+
def InstallPlugin(name: nil, &proc)
112+
Dsl.register_rb_hook('install_plugin', [], proc, name: name)
113113
end
114114

115115
# Registers a proc that will run before the execution of the scenarios.
116116
# Use it for your final set-ups
117-
def BeforeAll(&proc)
118-
Dsl.register_rb_hook('before_all', [], proc)
117+
def BeforeAll(name: nil, &proc)
118+
Dsl.register_rb_hook('before_all', [], proc, name: name)
119119
end
120120

121121
# Registers a proc that will run after the execution of the scenarios.
122122
# Use it for your final clean-ups
123-
def AfterAll(&proc)
124-
Dsl.register_rb_hook('after_all', [], proc)
123+
def AfterAll(name: nil, &proc)
124+
Dsl.register_rb_hook('after_all', [], proc, name: name)
125125
end
126126

127127
# Registers a new Ruby StepDefinition. This method is aliased

lib/cucumber/glue/hook.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ module Cucumber
66
module Glue
77
# TODO: Kill pointless wrapper for Before, After and AfterStep hooks with fire
88
class Hook
9-
attr_reader :id, :tag_expressions, :location
9+
attr_reader :id, :tag_expressions, :location, :name
1010

11-
def initialize(id, registry, tag_expressions, proc)
11+
def initialize(id, registry, tag_expressions, proc, name: nil)
1212
@id = id
1313
@registry = registry
14+
@name = name
1415
@tag_expressions = sanitize_tag_expressions(tag_expressions)
1516
@proc = proc
1617
@location = Cucumber::Core::Test::Location.from_source_location(*@proc.source_location)
@@ -32,6 +33,7 @@ def to_envelope
3233
Cucumber::Messages::Envelope.new(
3334
hook: Cucumber::Messages::Hook.new(
3435
id: id,
36+
name: name,
3537
tag_expression: tag_expressions.empty? ? nil : tag_expressions.join(' '),
3638
source_reference: Cucumber::Messages::SourceReference.new(
3739
uri: location.file,

lib/cucumber/glue/registry_and_more.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ def step_matches(name_to_match)
7272
end
7373
end
7474

75-
def register_rb_hook(phase, tag_expressions, proc)
76-
hook = add_hook(phase, Hook.new(@configuration.id_generator.new_id, self, tag_expressions, proc))
75+
def register_rb_hook(phase, tag_expressions, proc, name: nil)
76+
hook = add_hook(phase, Hook.new(@configuration.id_generator.new_id, self, tag_expressions, proc, name: name))
7777
@configuration.notify :envelope, hook.to_envelope
7878
hook
7979
end

0 commit comments

Comments
 (0)