Darme
Darme

Reputation: 7083

RSpec custom matchers in Cucumber to DRY implementation-dependent tests, is it possible?

I'm reading the new version of "Rails Tutorial" by Michael Hartl and, since I'm pretty fond in BDD with Cucumber, I found myself concerned about what the author points out here: http://ruby.railstutorial.org/chapters/sign-in-sign-out?version=3.2#sec:rspec_custom_matchers

In few words the main hassle with Cucumber is that it's impossible to DRY implementation-dependent tests like this:

Then /^he should see an error message$/ do
  page.should have_selector('div.alert.alert-error', text: 'Invalid')
end

writing RSpec custom matchers like this:

RSpec::Matchers.define :have_error_message do |message|
  match do |page|
    page.should have_selector('div.alert.alert-error', text: message)
  end
end 

Because such a custom matcher must be put in spec/support/utilities.rb and can be called from RSpec integration tests but not from Cucumber step definitions.

Are you positive / what you think about it?

Thank you.

Upvotes: 4

Views: 1664

Answers (3)

Dan Kohn
Dan Kohn

Reputation: 34327

An example of Jon M's answer, of how you can use RSpec custom matchers in Cucumber:

# spec/support/matchers/http.rb
RSpec::Matchers.define :return_http_success do
  match do |actual|
    actual >= 200 && actual <= 299
  end
end

# features/support/matchers.rb
Dir[Rails.root.join('spec/support/matchers/*.rb')].each { |file| require file }

Upvotes: 0

Andrei Botalov
Andrei Botalov

Reputation: 21096

You can put implementation-dependent or reusable methods, locators to Cucumber World.

Example for your scenario:

# step_definitions/general_steps.rb
Then /^he should see an error message "(.+)"$/ do |text|
  within(error_message) do
    page.should have_content(text)
  end
end

# support/general_helpers.rb
module GeneralHelpers
  def error_message
    page.first('div.alert.alert-error')
  end
end

World(GeneralHelpers)

Here are some articles that refer to this approach:

Upvotes: 3

Jon M
Jon M

Reputation: 11705

You can certainly create RSpec matchers and use them in your Cucumber steps - I do this fairly frequently. I just place them in features/support/matchers and they are instantly available to use in my step definitions.

If you wanted to share them with your RSpec tests as well, you may want to extract them to a separate shared_test type location, and then you could require that folder in both your Cucumber env.rb file, and your RSpec spec_helper.rb file, then they would be available in both test frameworks.

Upvotes: 5

Related Questions