Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Limit cucumber steps or steps file to specified feature or tag

I've written a modal slideshow for our web app that presents a navigation for sets of documents and exposes various metadata for those documents.

This is a large component of the application with esoteric requirements, so I think it's fair enough that its core scenarios (given to me as acceptance criteria) should be both numerous yet internally consistent.

To avoid having a new step for each of our many scenarios, I've adapted a helper which translates human-readable terms such as document caption into selectors:

module SelectorsHelper
  def selector_for(term)
    case term
    # Lightbox / modal / fancybox
    when 'lightbox'
        '#fancybox-inner'
    when 'close button'
        '.document-viewer__tools__close'

…alongside a few generic step definitions such as the following:

# Generic click action
When(/^I click (?:on )?(?:the |a )'(.*?)'?$/) do |element|
  find(selector_for(element)).click
end

The problem, whether I'm acting on very generic notions as with the above or more specific abstractions involving patterns that recur within a set of features, is that these may wreak havoc with other esoteric features, which may have much more specific steps to parse them. Every Cucumber example I've seen has step definition files whose filename bears a procedural relationship to a specific feature file, and my assumption was that in these cases, that step definition file would only be called to parse the scenarios in it's related feature:

+ features
| + step_definitions
| | + global_steps.rb
| | + modal_steps.rb
| | + login_steps.rb
| + modal.feature
| + login.feature

But that isn't the case — and I'm struggling to resign myself to the notion that Cucumber attempts to apply every step definition patterns to every scenario. If these tests are going to have any merit, they'll grow more numerous, introduce new concepts, and stay relevant without continuous re-writing. I want to be able to limit the scope of my steps to stop them interfering with features they weren't written for, but don't know how. The following conceptual solutions come to mind:

  • Use background or scenario @tags and invoke steps only for scenarios with those tags
  • Nest step definitions in some kind of wrapping helper or meta-step-definition that's invoked by a fallacious background given

I'm unfamiliar with Ruby and Cucumber seems extremely thin, so I'm daunted by unlimited potential on the one hand and no pre-determined implementation on the other. Any ideas?

like image 431
Barney Avatar asked Jul 31 '13 14:07

Barney


People also ask

How do you ignore steps in Cucumber?

Program the steps like you usually would, but in the first line of the step, make an 'if' statement like the one above to not run the code below if you don't want to. I haven't used cucumber in a few years. If next has a new syntax let me know.


1 Answers

In my experience overly generic steps lead to an extremely difficult to maintain automation code base. Try to go for a balance here if possible, only you can judge where this balance lies. You don't want overly repetitive step defintions but you don't want a super generic nightmare to debug.

It's possible to use a workaround to get to the list of tags but please please do not do this. It's gross, weird and not how cucumber is intended to be used.

As a workaround in your step_definitions you can use an around step to get a list of tag names from the scenario -

Around do |scenario, block|
  begin
    @tag_names = scenario.tags.collect { |tag| tag.name }
    block.call
  ensure
    $tags = nil
  end
end

Then in the step_definition body check if the tag you want to detect is included in the list -

Given(/^I am testing a step with a "([^"]*)"$/) do |arg|
  if @tag_names.include?('@a_tag')
    puts 'Executing a step definition with tag - @a_tag'
  else
    puts 'Executing a step definition without tag - @a_tag'
  end
end

This feature -

Feature: Example feature

  @a_tag
  Scenario: Example scenario #1
    Given I am testing a step with a "value"

  Scenario: Example scenario #1
    Given I am testing a step with a "value"

Results in this output -

Feature: Example feature

  @a_tag
  Scenario: Example scenario #1              # features/example.feature:4
    Given I am testing a step with a "value" # features/step_definitions/step_definitions.rb:10
      Executing a step definition with tag - @a_tag

  Scenario: Example scenario #1              # features/example.feature:7
    Given I am testing a step with a "value" # features/step_definitions/step_definitions.rb:10
      Executing a step definition without tag - @a_tag

2 scenarios (2 passed)
2 steps (2 passed)
0m0.004s

Again I think using this is an incredibly bad idea. It is better to have slightly repetive step definitions that are easy to follow and debug then to have a single super generic step definition to rule them all!

Edit - After re-reading your question and blog post I don't think this really answers your question. However, I am fairly certain you are trying to do something non-cucumberish

like image 118
Chris Wilding Avatar answered Sep 23 '22 02:09

Chris Wilding