Search code examples
rubycucumberexpressiondefinition

ruby cucumber how to have different steps call same definition using cucumber expressions


Say I wanted

Given something
When the sky is blue
And grass is green
Then I'm happy

but I wanted

When('the sky is blue') do
puts 'good'
end

and

When('grass is green') do
puts 'good'
end

to be the exact same step definition, something like

When(('the sky is blue')('grass is green')) do
puts 'good'
end

what would the syntax have to be to make it work - using ruby-cucumber and cucumber expressions as opposed to regex expressions? Please help


Solution

  • You might be able to do this with Cucumber expressions, but when people provide weird inputs it's hard to assume that there won't be edge cases that either over- or under-match. For example, you might expect the following to work:

    ( the )sky/grass is blue/green
    

    It will match your examples, but it will also match unexpectedly with text like When grass is blue or And the sky is green. This is probably not what you want. If you can't generalize, then you might need to use regular expressions with more explicit anchoring, or consider splitting up your Gherkin to avoid conjunction steps.

    Gherkin allows you to use a number of ways to extract tokens for processing. Assuming you don't have other, similar steps that would cause confusion, the following should work even without having to create custom parameter types in your Cucumber configuration. Other approaches could work, too, depending on your needs.

    # Gherkin
    When the "sky" is "blue"
    And "grass" is "green"
    Then I am "happy"
    
    # flexible object/color step with cucumber
    # expressions and a case statement
    When("(the ){word} is {word}") do |obj, color|
      case
      when (obj == "sky" and color == "blue") && 
           (obj == "grass" and color == "green")
        @emotional_state = "happy"
      else
        @emotional_state = "unhappy"
      end
    end 
    
    # use state from the previous step to measure
    # your happiness quotient
    Then("I am {word}") do |emotional_state|
      @emotional_state == emotional_state
    end
    

    You might also consider doing a scenario outline or passing a data table instead, so that you can more easily map your truth tables regarding what makes you happy. Depending on your goals and the chances of oversimplifying your steps to the point where steps aren't distinct enough, this should at least get you headed in the right direction.