0

I've looked through the Ruby Gherkin source a bit and it doesn't look like there is a straightforward way to know which keyword was used once you are in a step definition. Am I missing something? Is there a way to do this? Even if it is bit of a hack?

Gherkin:

Then I say 'Hello World'
 

Step Definition:

When /I say 'Hello World'/ do
  keyword_used =  # FIXME how do I know what keyword was used in the Gherkin statement?
end

Edit: I'm adding the X for the Y...

The reason I am asking about this is that I am working with a group of people who want to do requirements capture in a fairly natural language sort of way (so, Gherkin) but then want to pump those requirements into something like ReqIF. For the use case at hand, it is important to retain a distinction between preconditions, trigger, and expected result. It is easy enough to adopt conventions for writing Gherkin that make this clear, e.g. all steps from the first step using keyword 'Given' to the last step before the first step using 'When' are preconditions. My step definitions do the work of shepherding the steps into the conversion to ReqIF. So, we're not actually using Cucumber to run tests, it is just a convenient apparatus for collecting and processing use cases / requirements expressed in Gherkin.

Huliax
  • 1,489
  • 3
  • 15
  • 27
  • If you don't get an answer that helps with the Y in what I think is an X/Y problem, you may want to open a linked question about the X, explaining more about *why* you're trying to do what you're doing. There may be a more idiomatic (or at least pragmatic) way to differentiate your step definitions rather than trying to branch off of Gherkin keywords. – Todd A. Jacobs Jan 26 '21 at 22:44

3 Answers3

1

Step Definitions Aren't Passed Step-Line Tokens

From Cucumber's point of view, all Gherkin keywords that trigger steps are identical. From the step definition's point of view, there's no out-of-the-box visibility of the keyword that triggered the step.

This is a design choice. In general, trying to branch the same step off of different keywords is largely a Cucumber anti-pattern, and prevents you from reusing step definitions in the way that most Cucumberists would expect. In general, I'd say that if you care deeply about which step-token was used to enter your step definition, there's probably a better way to do whatever it is you're really trying to accomplish (e.g. this is likely an X/Y problem).

On the other hand, if you're asking "Can I hack it?", then answer is "possibly." At least in the Ruby version, Cucumber uses a tokenizer and parser to read Gherkin, so you could conceivably introspect the AST or one of the other objects to see if you can access the token value of the #set_token_matched Ruby method, or somehow expose the value from the token matcher C source. Access to these values may or may not be possible without changes to the underlying source code, but these are likely the right seams to explore if you're trying to pry open the innards of Cucumber.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
0

No, this information is not available to the step definition.

Aslak Hellesøy
  • 1,191
  • 6
  • 9
  • While I agree that it's probably an X/Y problem, won't the Ruby version (I have zero opinion about other dialects) have some object in World or ObjectSpace that can be interrogated for the arguments passed to #set_token_matched or similar? – Todd A. Jacobs Jan 26 '21 at 22:38
0

With a push of encouragement from Todd A. Jacobs' answer, I was able to hack my way through to it. It isn't pretty but it demonstrates that it is possible.

In short, I captured the configuration during Cucumber::Runtime#run!. Then, in Cucumber::Core::Test::Runner#test_step I inserted the following lines:

          ast_lookup = Cucumber::Formatter::AstLookup.new(Hack.get_config)
          step_keyword = ast_lookup.step_source(test_step).step.keyword
          Hack.set_keyword(step_keyword)

Then it is just a matter of calling Hack#get_keyword in your step definition.

By no means am I suggesting that this is the best way to get this done, it is just a way to get it done. It's possible that this doesn't work in all cases but I just need rudimentary proof-of-concept at this point.

Huliax
  • 1,489
  • 3
  • 15
  • 27