From 7f975f80f58ebb3fa0c2784842c4a83e8abbcd1c Mon Sep 17 00:00:00 2001 From: aurelien-reeves Date: Wed, 18 May 2022 14:51:28 +0200 Subject: [PATCH 1/6] Add support for named hooks --- cucumber.gemspec | 24 +++++++++---------- lib/cucumber/glue/dsl.rb | 32 +++++++++++++------------- lib/cucumber/glue/hook.rb | 6 +++-- lib/cucumber/glue/registry_and_more.rb | 4 ++-- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/cucumber.gemspec b/cucumber.gemspec index b2d9f68949..e2c70a4801 100644 --- a/cucumber.gemspec +++ b/cucumber.gemspec @@ -20,22 +20,22 @@ Gem::Specification.new do |s| # Keep in sync with .circleci/config.yml & .rubocop.yml s.required_ruby_version = '>= 2.6' s.add_dependency 'builder', '~> 3.2', '>= 3.2.4' - s.add_dependency 'cucumber-ci-environment', '~> 8.1', '>= 8.1.0' - s.add_dependency 'cucumber-core', '~> 10.1', '>= 10.1.1' - s.add_dependency 'cucumber-cucumber-expressions', '~> 15.0', '>= 15.0.1' - s.add_dependency 'cucumber-gherkin', '~> 22.0', '>= 22.0.0' - s.add_dependency 'cucumber-html-formatter', '~> 17.0', '>= 17.0.0' - s.add_dependency 'cucumber-messages', '~> 17.1', '>= 17.1.1' + s.add_dependency 'cucumber-ci-environment', '~> 9.0', '>= 9.0.4' + s.add_dependency 'cucumber-core', '~> 11.0', '>= 11.0.0' + s.add_dependency 'cucumber-cucumber-expressions', '~> 15.1', '>= 15.1.1' + s.add_dependency 'cucumber-gherkin', '~> 23.0', '>= 23.0.1' + s.add_dependency 'cucumber-html-formatter', '~> 19.1', '>= 19.1.0' + s.add_dependency 'cucumber-messages', '~> 18.0', '>= 18.0.0' s.add_dependency 'diff-lcs', '~> 1.5', '>= 1.5.0' s.add_dependency 'mime-types', '~> 3.4', '>= 3.4.1' - s.add_dependency 'multi_test', '~> 0.1', '>= 0.1.2' + s.add_dependency 'multi_test', '~> 1.1', '>= 1.1.0' s.add_dependency 'sys-uname', '~> 1.2', '>= 1.2.2' - s.add_development_dependency 'cucumber-compatibility-kit', '~> 9.1', '>= 9.1.2' - s.add_development_dependency 'nokogiri', '~> 1.13', '>= 1.13.1' + s.add_development_dependency 'cucumber-compatibility-kit', '~> 9.2', '>= 9.2.0' + s.add_development_dependency 'nokogiri', '~> 1.13', '>= 1.13.6' s.add_development_dependency 'pry', '~> 0.14', '>= 0.14.1' s.add_development_dependency 'rake', '~> 13.0', '>= 13.0.6' - s.add_development_dependency 'rspec', '~> 3.10', '>= 3.10.0' + s.add_development_dependency 'rspec', '~> 3.11', '>= 3.11.0' s.add_development_dependency 'simplecov', '~> 0.21', '>= 0.21.2' s.add_development_dependency 'syntax', '~> 1.2', '>= 1.2.2' s.add_development_dependency 'test-unit', '~> 3.5', '>= 3.5.3' @@ -45,9 +45,9 @@ Gem::Specification.new do |s| s.add_development_dependency 'octokit', '~> 4.22', '>= 4.22.0' # Needed for examples (rake examples) - s.add_development_dependency 'capybara', '~> 3.36', '>= 3.36.0' + s.add_development_dependency 'capybara', '~> 3.37', '>= 3.37.1' s.add_development_dependency 'rack-test', '~> 1.1', '>= 1.1.0' - s.add_development_dependency 'sinatra', '~> 2.1', '>= 2.1.0' + s.add_development_dependency 'sinatra', '~> 2.2', '>= 2.2.0' s.required_rubygems_version = '>= 1.6.1' s.files = Dir[ diff --git a/lib/cucumber/glue/dsl.rb b/lib/cucumber/glue/dsl.rb index af313304b2..728d010756 100644 --- a/lib/cucumber/glue/dsl.rb +++ b/lib/cucumber/glue/dsl.rb @@ -19,8 +19,8 @@ def build_rb_world_factory(world_modules, namespaced_world_modules, proc) @rb_language.build_rb_world_factory(world_modules, namespaced_world_modules, proc) end - def register_rb_hook(phase, tag_names, proc) - @rb_language.register_rb_hook(phase, tag_names, proc) + def register_rb_hook(phase, tag_names, proc, name: nil) + @rb_language.register_rb_hook(phase, tag_names, proc, name: name) end def define_parameter_type(parameter_type) @@ -62,14 +62,14 @@ def World(*world_modules, **namespaced_world_modules, &proc) # Registers a proc that will run before each Scenario. You can register as many # as you want (typically from ruby scripts under support/hooks.rb). - def Before(*tag_expressions, &proc) - Dsl.register_rb_hook('before', tag_expressions, proc) + def Before(*tag_expressions, name: nil, &proc) + Dsl.register_rb_hook('before', tag_expressions, proc, name: name) end # Registers a proc that will run after each Scenario. You can register as many # as you want (typically from ruby scripts under support/hooks.rb). - def After(*tag_expressions, &proc) - Dsl.register_rb_hook('after', tag_expressions, proc) + def After(*tag_expressions, name: nil, &proc) + Dsl.register_rb_hook('after', tag_expressions, proc, name: name) end # Registers a proc that will be wrapped around each scenario. The proc @@ -77,14 +77,14 @@ def After(*tag_expressions, &proc) # argument (but passed as a regular argument, since blocks cannot accept # blocks in 1.8), on which it should call the .call method. You can register # as many as you want (typically from ruby scripts under support/hooks.rb). - def Around(*tag_expressions, &proc) - Dsl.register_rb_hook('around', tag_expressions, proc) + def Around(*tag_expressions, name: nil, &proc) + Dsl.register_rb_hook('around', tag_expressions, proc, name: name) end # Registers a proc that will run after each Step. You can register as # as you want (typically from ruby scripts under support/hooks.rb). - def AfterStep(*tag_expressions, &proc) - Dsl.register_rb_hook('after_step', tag_expressions, proc) + def AfterStep(*tag_expressions, name: nil, &proc) + Dsl.register_rb_hook('after_step', tag_expressions, proc, name: name) end def ParameterType(options) @@ -108,20 +108,20 @@ def if_nil(value, default) end # Registers a proc that will run after Cucumber is configured in order to install an external plugin. - def InstallPlugin(&proc) - Dsl.register_rb_hook('install_plugin', [], proc) + def InstallPlugin(name: nil, &proc) + Dsl.register_rb_hook('install_plugin', [], proc, name: name) end # Registers a proc that will run before the execution of the scenarios. # Use it for your final set-ups - def BeforeAll(&proc) - Dsl.register_rb_hook('before_all', [], proc) + def BeforeAll(name: nil, &proc) + Dsl.register_rb_hook('before_all', [], proc, name: name) end # Registers a proc that will run after the execution of the scenarios. # Use it for your final clean-ups - def AfterAll(&proc) - Dsl.register_rb_hook('after_all', [], proc) + def AfterAll(name: nil, &proc) + Dsl.register_rb_hook('after_all', [], proc, name: name) end # Registers a new Ruby StepDefinition. This method is aliased diff --git a/lib/cucumber/glue/hook.rb b/lib/cucumber/glue/hook.rb index 6f8ed94750..9444d29d2d 100644 --- a/lib/cucumber/glue/hook.rb +++ b/lib/cucumber/glue/hook.rb @@ -6,11 +6,12 @@ module Cucumber module Glue # TODO: Kill pointless wrapper for Before, After and AfterStep hooks with fire class Hook - attr_reader :id, :tag_expressions, :location + attr_reader :id, :tag_expressions, :location, :name - def initialize(id, registry, tag_expressions, proc) + def initialize(id, registry, tag_expressions, proc, name: nil) @id = id @registry = registry + @name = name @tag_expressions = sanitize_tag_expressions(tag_expressions) @proc = proc @location = Cucumber::Core::Test::Location.from_source_location(*@proc.source_location) @@ -32,6 +33,7 @@ def to_envelope Cucumber::Messages::Envelope.new( hook: Cucumber::Messages::Hook.new( id: id, + name: name, tag_expression: tag_expressions.empty? ? nil : tag_expressions.join(' '), source_reference: Cucumber::Messages::SourceReference.new( uri: location.file, diff --git a/lib/cucumber/glue/registry_and_more.rb b/lib/cucumber/glue/registry_and_more.rb index 1aec188e2a..73c2cf8fd1 100644 --- a/lib/cucumber/glue/registry_and_more.rb +++ b/lib/cucumber/glue/registry_and_more.rb @@ -72,8 +72,8 @@ def step_matches(name_to_match) end end - def register_rb_hook(phase, tag_expressions, proc) - hook = add_hook(phase, Hook.new(@configuration.id_generator.new_id, self, tag_expressions, proc)) + def register_rb_hook(phase, tag_expressions, proc, name: nil) + hook = add_hook(phase, Hook.new(@configuration.id_generator.new_id, self, tag_expressions, proc, name: name)) @configuration.notify :envelope, hook.to_envelope hook end From 1580e739ae40a25ee1ddaad03e8562cb0c88e93e Mon Sep 17 00:00:00 2001 From: aurelien-reeves Date: Thu, 19 May 2022 11:02:58 +0200 Subject: [PATCH 2/6] Bump the CCK to 9.2.1 --- cucumber.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cucumber.gemspec b/cucumber.gemspec index e2c70a4801..860897ef67 100644 --- a/cucumber.gemspec +++ b/cucumber.gemspec @@ -31,7 +31,7 @@ Gem::Specification.new do |s| s.add_dependency 'multi_test', '~> 1.1', '>= 1.1.0' s.add_dependency 'sys-uname', '~> 1.2', '>= 1.2.2' - s.add_development_dependency 'cucumber-compatibility-kit', '~> 9.2', '>= 9.2.0' + s.add_development_dependency 'cucumber-compatibility-kit', '~> 9.2', '>= 9.2.1' s.add_development_dependency 'nokogiri', '~> 1.13', '>= 1.13.6' s.add_development_dependency 'pry', '~> 0.14', '>= 0.14.1' s.add_development_dependency 'rake', '~> 13.0', '>= 13.0.6' From 5934cdce77cf23ebb69bcb0e044303cce0da6fd5 Mon Sep 17 00:00:00 2001 From: aurelien-reeves Date: Thu, 19 May 2022 11:08:14 +0200 Subject: [PATCH 3/6] Pin capybara to < 3.37 to support ruby 2.6 --- cucumber.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cucumber.gemspec b/cucumber.gemspec index 860897ef67..b76f5d917e 100644 --- a/cucumber.gemspec +++ b/cucumber.gemspec @@ -45,7 +45,7 @@ Gem::Specification.new do |s| s.add_development_dependency 'octokit', '~> 4.22', '>= 4.22.0' # Needed for examples (rake examples) - s.add_development_dependency 'capybara', '~> 3.37', '>= 3.37.1' + s.add_development_dependency 'capybara', '~> 3.36', '>= 3.36.0', '< 3.37' s.add_development_dependency 'rack-test', '~> 1.1', '>= 1.1.0' s.add_development_dependency 'sinatra', '~> 2.2', '>= 2.2.0' From d03ec49e0ae135806f2f05d4430eacffa058b22c Mon Sep 17 00:00:00 2001 From: aurelien-reeves Date: Thu, 19 May 2022 11:40:31 +0200 Subject: [PATCH 4/6] Add a dedicated feature for named hooks --- .../hooks/named_hooks.feature | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 features/docs/writing_support_code/hooks/named_hooks.feature diff --git a/features/docs/writing_support_code/hooks/named_hooks.feature b/features/docs/writing_support_code/hooks/named_hooks.feature new file mode 100644 index 0000000000..146892077d --- /dev/null +++ b/features/docs/writing_support_code/hooks/named_hooks.feature @@ -0,0 +1,49 @@ +Feature: Named hooks + + In order to spot errors easily in hooks + As a developer + I can give names to hooks + + Scenario: Hooks can be named + Given a file named "features/support/env.rb" with: + """ + Before(name: 'Named before hook') do + # no-op + end + """ + And a file named "features/simple_scenario.feature" with: + """ + Feature: + Scenario: + Given a step + """ + When I run `cucumber features --publish-quiet --format message` + Then the stderr should not contain anything + And the output should contain NDJSON with key "name" and value "Named before hook" + + Scenario: All kind of hooks can be named + Given a file named "features/support/env.rb" with: + """ + Before(name: 'Named before hook') {} + After(name: 'Named after hook') {} + BeforeAll(name: 'Named before_all hook') {} + AfterAll(name: 'Named after_all hook') {} + AfterStep(name: 'Named after_step hook') {} + Around(name: 'Named around hook') {} + InstallPlugin(name: 'Named install_plugin hook') {} + """ + And a file named "features/simple_scenario.feature" with: + """ + Feature: + Scenario: + Given a step + """ + When I run `cucumber features --publish-quiet --format message` + Then the stderr should not contain anything + And the output should contain NDJSON with key "name" and value "Named before hook" + And the output should contain NDJSON with key "name" and value "Named after hook" + And the output should contain NDJSON with key "name" and value "Named before_all hook" + And the output should contain NDJSON with key "name" and value "Named after_all hook" + And the output should contain NDJSON with key "name" and value "Named after_step hook" + And the output should contain NDJSON with key "name" and value "Named around hook" + And the output should contain NDJSON with key "name" and value "Named install_plugin hook" From 305c713e6862b3814785d602866f8e794c96f7a2 Mon Sep 17 00:00:00 2001 From: aurelien-reeves Date: Thu, 19 May 2022 11:47:27 +0200 Subject: [PATCH 5/6] Update hooks documentation --- .../docs/writing_support_code/hooks/README.md | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/features/docs/writing_support_code/hooks/README.md b/features/docs/writing_support_code/hooks/README.md index a26fd79619..605f30106e 100644 --- a/features/docs/writing_support_code/hooks/README.md +++ b/features/docs/writing_support_code/hooks/README.md @@ -25,6 +25,8 @@ Multiple hooks of the same type are executed in the order that they were defined If you wish to control this order, use manual requires in `env.rb` - This file is loaded first - or migrate them all to one `hooks.rb` file. +Finaly, all hooks can be given a name to improve reporting and help debugging. + ## InstallPlugin [`InstallPlugin`](#installplugin) hook is dedicated to using plugins and is meant to @@ -43,6 +45,12 @@ InstallPlugin do |configuration, registry| # registry is an instance of Cucumber::Glue::RegistryWrapper defined in # lib/cucumber/glue/registry_wrapper.rb end + +# named hook: + +InstallPlugin(name: 'Installation of a plugin') do |configuration, registry| + # The name is optional +end ``` You can see an example in the [Cucumber Wire plugin](https://github.com/cucumber/cucumber-ruby-wire). @@ -63,6 +71,16 @@ end AfterAll do # snip end + +# Named hooks: + +BeforeAll(name: 'Name of the hook') do + # snip +end + +AfterAll(name: 'Name of the hook') do + # snip +end ``` ## Around @@ -79,6 +97,12 @@ Around do |scenario, block| block.call end end + +# with a name: + +Around(name: 'Name of the hook') do |scenario, block| + # snip +end ``` ## Before and After @@ -96,6 +120,16 @@ After do |test_case| log test_case.failed? log test_case.status end + +# With names: + +Before(name: 'Name of the hook') do |test_case| + # snip +end + +After(name: 'Name of the hook') do |test_case| + # snip +end ``` ## AfterStep @@ -108,4 +142,10 @@ AfterStep do |result, test_step| log test_step.inspect # test_step is a Cucumber::Core::Test::Step log result.inspect # result is a Cucumber::Core::Test::Result end + +# with a name: + +AfterStep(name: 'Named hook') do |result, test_step| + # snip +end ``` From ab2bc516dc58daa4deb42d012161312007e1fba0 Mon Sep 17 00:00:00 2001 From: aurelien-reeves Date: Thu, 19 May 2022 12:26:13 +0200 Subject: [PATCH 6/6] Update CHANGELOG --- CHANGELOG.md | 3 +++ features/docs/writing_support_code/hooks/README.md | 2 ++ 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6acaf0685f..24df863e24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,9 @@ Please visit [cucumber/CONTRIBUTING.md](https://github.com/cucumber/cucumber/blo ([PR#1612](https://github.com/cucumber/cucumber-ruby/pull/1612) [gogainda](https://github.com/gogainda)) +- Add support for named hooks + ([PR#1636](https://github.com/cucumber/cucumber-ruby/pull/1636)) + ### Fixed - Use `required_rubygems_version` instead of `rubygems_version`([PR#1629](https://github.com/cucumber/cucumber-ruby/pull/1629)) diff --git a/features/docs/writing_support_code/hooks/README.md b/features/docs/writing_support_code/hooks/README.md index 605f30106e..ef7799718d 100644 --- a/features/docs/writing_support_code/hooks/README.md +++ b/features/docs/writing_support_code/hooks/README.md @@ -27,6 +27,8 @@ loaded first - or migrate them all to one `hooks.rb` file. Finaly, all hooks can be given a name to improve reporting and help debugging. +Note: Hooks names are only reported when using the message and the html formatters. + ## InstallPlugin [`InstallPlugin`](#installplugin) hook is dedicated to using plugins and is meant to