Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cucumber4: Obtain Cucumber 3 scenario properties in hooks.rb #1432

Closed
orien opened this issue Jun 24, 2020 · 33 comments
Closed

Cucumber4: Obtain Cucumber 3 scenario properties in hooks.rb #1432

orien opened this issue Jun 24, 2020 · 33 comments
Labels
💔 breaking change This will require a major release
Milestone

Comments

@orien
Copy link
Contributor

orien commented Jun 24, 2020

Describe the bug

In version 3 it is possible to obtain the name of the current feature from Before and After hooks.

Before do |scenario|
  feature_name = scenario.feature.name
  #…
end

In version 4 this seems impossible as the feature method has been removed and I can see no replacement.

Before do |scenario|
  feature_name = scenario.feature.name
  # -> undefined method `feature' for #<Cucumber::RunningTestCase::TestCase:0x00007f9b307ae180> (NoMethodError)
end

To Reproduce
Steps to reproduce the behavior:

  1. Install version 4
  2. Add Before hook obtaining feature name
  3. Run cucumber
  4. See error

Expected behavior

Be able to obtain the running feature name from Before and After hooks.

Context & Motivation

Providing a replacement for this would ease the migration path to version 4.0.0 as integrations rely on this data.

For example, the VCR gem uses the scenario and feature names to determine which cassette to load.

@orien orien changed the title Obtain Feature name in before hook Obtain feature name in before hook Jun 24, 2020
@luke-hill
Copy link
Contributor

Do other methods on the scenario object work. As it seems to be much different.

Examples are scenario.source_tag_names scenario.name e.t.c.?

@orien
Copy link
Contributor Author

orien commented Jun 24, 2020

I see the following methods:

Cucumber 3

Before do |s|
  s.exception # => #<NilClass>
  s.feature # => #<Cucumber::Core::Ast::Feature>
  s.keyword # => #<String>
  s.language # => #<Gherkin::Dialect>
  s.location # => #<struct Cucumber::Core::Ast::Location::Precise
  s.name # => #<String>
  s.source # => [#<Cucumber::Core::Ast::Feature>, #<Cucumber::Core::Ast::Scenario>]
  s.source_tag_names # => [#<String>]
  s.status # => #<Symbol>
  s.step_count # => #<Integer>
  s.tags # => [#<Cucumber::Core::Ast::Tag>]
  s.test_steps # => [#<Cucumber::Core::Test::Step>, #<Cucumber::Core::Test::Step>]
end

Cucumber 4

Before do |s|
  s.exception # => #<NilClass>
  s.hash # => #<Integer>
  s.id # => #<String>
  s.language # => #<String>
  s.location # => #<struct Cucumber::Core::Test::Location::Precise
  s.name # => #<String>
  s.source_tag_names # => [#<String>]
  s.status # => #<Symbol>
  s.step_count # => #<Integer>
  s.tags # =>[#<Cucumber::Core::Test::Tag>]
  s.test_steps # => [#<Cucumber::Core::Test::Step>, #<Cucumber::Core::Test::HookStep>]
end

@luke-hill
Copy link
Contributor

Very comprehensive answer - thankyou. I'd definitely expect we could keep the old methods, but I've not been involved much with it recently.

@JoeSSS
Copy link
Contributor

JoeSSS commented Jul 4, 2020

Are there any workarounds to get feature name inside the scenario? We really want to update to new Cucumber version but feature name is essential for our tracking and flakiness monitoring on test results BE.

@luke-hill luke-hill changed the title Obtain feature name in before hook Cucumber4: Obtain Cucumber 3 scenario properties in hooks.rb Aug 14, 2020
@luke-hill luke-hill added the 💔 breaking change This will require a major release label Aug 14, 2020
@thedeeno
Copy link

thedeeno commented Aug 16, 2020

If anyone wants a work-around for VCR while this is being considered I hacked up the following monkey-patch:

# HACK: this method was available in cucumber 3.1 and VCR relies on it to
# generate cassette names.
module Cucumber
  module RunningTestCase
    class TestCase < SimpleDelegator

      def feature
        string = File.read(location.file)
        document = ::Gherkin::Parser.new.parse(string)
        document[:feature]
      end

    end
  end
end

There's probably a better way to do this.

@stale
Copy link

stale bot commented Dec 15, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in a week if no further activity occurs.

@stale stale bot added the ⌛ stale Will soon be closed by stalebot unless there is activity label Dec 15, 2020
@atyndall
Copy link

I believe this is still an issue?

@stale stale bot removed the ⌛ stale Will soon be closed by stalebot unless there is activity label Dec 15, 2020
@luke-hill
Copy link
Contributor

It is yes, but it is distinctly non-trivial and would require an agreement from the technical team on "what" we should do and whether we standardise across the flavours. I'll pop a slow-burner on it.

@luke-hill luke-hill added the 🧷 pinned Tells Stalebot not to close this issue label Dec 16, 2020
@Castone22
Copy link

I was doing some quick digging into the JSON formatter because SOMEHOW it still gets the feature name, seems like the expected way to handle it now is to use an AstLookup...

@ast_lookup = AstLookup.new(config)

which gets referenced here

builder = Builder.new(test_case, @ast_lookup)

The builder uses this to create a feature hash which can be cross referenced with the test location to get its feature name.

def initialize(test_case, ast_lookup)
@background_hash = nil
uri = test_case.location.file
feature = ast_lookup.gherkin_document(uri).feature
feature(feature, uri)
background(feature.children.first.background) unless feature.children.first.background.nil?
scenario(ast_lookup.scenario_source(test_case), test_case)
end

Should be able to intercept the config in an AfterConfig hook and save it for use i'd think.

@luke-hill
Copy link
Contributor

@Castone22 That is not using the new message protocol. So it's not a like for like comparison. The legacy JSON formatter is being removed (It was slated for v5 removal, I believe this is now pushed back to v6)

@Castone22
Copy link

I suppose that explains why the ast from the ast lookup consists of protofbufs, do you happen to know retrieving those is also slated to be removed?

@rickpastoor
Copy link

It appears that the patch by @thedeeno no longer works with cucumber 7.0.0. Investigating further, but if anyone already found the solution I'd love to hear it :)

@luke-hill
Copy link
Contributor

The internal structure of cucumber messages has basically been rewritten from scratch in cucumber 7. We now use a JSON schema instead of protobufs. Consequently, it's likely a lot of the internal structure has changed.

@rickpastoor
Copy link

This patch works for me:

module Cucumber
  module RunningTestCase
    class TestCase < SimpleDelegator

      def feature
        string = File.read(location.file)
        document = ::Gherkin::Parser.new.parse(string)
        document.feature
      end

    end
  end
end

@aurelien-reeves aurelien-reeves added ⚡ enhancement Request for new functionality 🐛 bug Defect / Bug labels Jul 22, 2021
@aurelien-reeves
Copy link
Contributor

aurelien-reeves commented Jul 22, 2021

I put both "Bug" and "Enhancement" labels because historically, it is a regression when cucumber v4 has been released, but regarding all the internal rework which led to the actual v7, internally it would actually be an enhancement 😅

@aurelien-reeves aurelien-reeves removed the 🐛 bug Defect / Bug label Jul 22, 2021
@luke-hill
Copy link
Contributor

You can still access the scenario name, the scenario location (Which includes a fully qualified filepath), and things like tags.

The switchover in mentality (I was against it at first too), is that the pickles execute the test cases, i.e. they should be thought of as the top level wrapper (or a scenario if thats easier). The feature isn't a realistic wrapper at this point.

I mentioned VCR were one of the larger consumers of this, I think maybe using a scenario name to qualify your VCR cassettes might help.

@Castone22
Copy link

Castone22 commented Jul 22, 2021

Another use case is having a custom formatter that logs metadata such as relative feature location, id, name and scenario gherkin plus the pass and fail state to with error output and such to an elk instance. (Something we're planning to open source in the near future.)

I'd expect other report tooling that hooks into things like zephyr scale or x-ray would benefit from a way to access this information. We're often more interested in the feature ast data in these situations though. I don't necessarily care about the form the data takes, Json is completely acceptable. We used to be able to resolve this through scenario.feature.source

@mattwynne
Copy link
Member

@Castone22 the formatter / events API is a better fit for that, though it's probably not very well documented at the moment. There are examples in Cucumber's own codebase were we match together the data from the test case result and Gherkin AST events to give the kind of info you're looking for, e.g. https://github.com/cucumber/cucumber-ruby/blob/97a03c0bd8199d5dcd3fc8de5993d01306dd4a1f/lib/cucumber/formatter/pretty.rb

It would be possible to build a richer domain model from these events to surface into a user API, but it's not something we have at the moment.

@Castone22
Copy link

Yes those is what I ultimately ended up using. A lack of a direct link from a test case to it's ast source was a little awkward at first though using an ast lookup was the pattern I was referring to, not the protobuf that resulted from using it back in 5. I was waiting for confirmation this was the intended route before I continued implementing against it though.

@mattwynne
Copy link
Member

@brasmusson really clarified it for me today at the Zoom community meeting, that the hooks are part of an execution model, and we should keep the info exposed in them lean because, for example, we might have test cases that were generated from sources other than Gherkin documents, or test cases running in parallel.

On the other hand, the events API used by the formatters is the higher-level place where you can observe everything going on in the Cucumber run, including AST nodes and execution results.

I think we're probably missing an abstraction layer that makes it easier to work with the events API for common use cases, so please keep talking to us and see if there are patterns in what you do with it that could be pushed upstream.

@aurelien-reeves
Copy link
Contributor

Thanks for all those explanations everyone!

What is that VCR project you are talking about?

@luke-hill
Copy link
Contributor

@aurelien-reeves https://github.com/vcr/vcr it's quite a large gem used in lots of projects (Like rails testing for example).

@aurelien-reeves aurelien-reeves added 🙅 wontfix This will not be worked on and removed 🧷 pinned Tells Stalebot not to close this issue labels Jul 29, 2021
@aurelien-reeves
Copy link
Contributor

Actually we still have to rename the paramter from "scenario" to "test_case" to reduce the confusion

@aurelien-reeves
Copy link
Contributor

I took a look in order to rename the parameter from "scenario" into "test_case" for hooks.
I was not able to find in the code any relevant place.

@luke-hill do you know if it is only matter of documentation? Or does the code need some update too?

Reminder: in order to be more clear than the hook parameter represent a pickle and not a scenario, we wanted to rename Before do |scenario| into Before do |test_case|

@luke-hill
Copy link
Contributor

in code it's kinda irrelevant as it's just a placeholder name.

Just in ruby these names invoke meaning. So if the param is called scenario it would be reasonable to assume you could get scenario based properties from them.

This is purely a doc issue now.

@aurelien-reeves
Copy link
Contributor

in code it's kinda irrelevant as it's just a placeholder name.

Just in ruby these names invoke meaning. So if the param is called scenario it would be reasonable to assume you could get scenario based properties from them.

That's the point: I did not find any code in the repo which had a param named 'scenario'. So I guess our own codebase is ok

This is purely a doc issue now.

👍

@stale
Copy link

stale bot commented Apr 14, 2023

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in two months if no further activity occurs.

@stale stale bot added the ⌛ stale Will soon be closed by stalebot unless there is activity label Apr 14, 2023
@stale stale bot removed the ⌛ stale Will soon be closed by stalebot unless there is activity label Jun 12, 2023
@RamadhanaRey

This comment was marked as resolved.

@luke-hill
Copy link
Contributor

I believe we fixed the docs part of this so this needs closing again.

Your code above is slightly faulty @RamadhanaRey - You want to run respond_to for both. But in essence, we're not going back to the old system. So just use the scenario name.

If you need the feature file name: You can obtain it here: https://github.com/site-prism/automation_helpers/blob/main/lib/automation_helpers/extensions/cucumber/core/test/case.rb#L13-L15

@abhiras29
Copy link

went through the whole thread and I know this is marked as completed
but could not find any solution for scenario.outline?
I know this method got deprecated in the new version of cucumber but any hack like we have for feature.name
help much appreciated

@Castone22
Copy link

I know you can figure it out using an ast lookup like the one I showed above, outlines use a different class then regular scenarios

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💔 breaking change This will require a major release
Projects
None yet
Development

No branches or pull requests