Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid Rspec shared examples 'previously defined' warning?

I am trying to learn how to use Rspec's shared examples feature and am getting a warning when I run my tests:

WARNING: Shared example group 'required attributes' has been previously defined at:
  /Users/me/app/spec/support/shared_examples/required_attributes_spec.rb:1
...and you are now defining it at:
  /Users/me/app/spec/support/shared_examples/required_attributes_spec.rb:1
The new definition will overwrite the original one.
....

I have read what I think is the documentation on this problem here but I'm having trouble understanding it/seeing the takeaways for my case.

Here is my shared example:

# spec/support/shared_examples/required_attributes_spec.rb

shared_examples_for 'required attributes' do |arr|
  arr.each do |meth|
    it "is invalid without #{meth}" do
      subject.send("#{meth}=", nil)
      subject.valid?
      expect(subject.errors[meth]).to eq(["can't be blank"])
    end
  end
end

I am trying to use this in a User model and a Company model. Here is what it looks like:

# spec/models/user_spec.rb

require 'rails_helper'

describe User do
  subject { build(:user) }
  include_examples 'required attributes', [:name]
end

# spec/models/company_spec.rb

require 'rails_helper'

describe Company do
  subject { build(:company) }
  include_examples 'required attributes', [:logo]
end

Per the recommendations in the Rspec docs I linked to above, I have tried changing include_examples to it_behaves_like, but that didn't help. I also commented out company_spec.rb entirely so there was just one spec using the shared example, and I am still getting the warning.

Can anyone help me see what's really going on here and what I should do in this case to avoid the warning?

like image 810
sixty4bit Avatar asked Jul 03 '15 14:07

sixty4bit


2 Answers

I found the answer in this issue at the Rspec Github:

Just in case someone googles and lands here. If putting your file with shared examples into support folder has not fixed the following error...Make sure your filename does not end with _spec.rb.

like image 50
sixty4bit Avatar answered Nov 14 '22 22:11

sixty4bit


As a followup to this, I had the issue in an included shared context with a filename that did not end in _spec.rb and was manually loaded via require_relative, not autoloaded. In my case, the issue was a copy-paste problem. The test looked like this:

RSpec.shared_examples 'foo' do
  RSpec.shared_examples 'bar' do
    it ... do... end
    it ... do... end
    # etc.
  end

  context 'first "foo" scenario' do
    let ...
    include_examples 'bar'
  end

  context 'second "foo" scenario' do
    let ...
    include_examples 'bar'
  end
end

The intent was to provide a single shared set of examples that exercised multiple contexts of operation for good coverage, all running through that internal shared examples list.

The bug was simple but subtle. Since I have RSpec monkey patching turned off (disable_monkey_patching!), I have to use RSpec.<foo> at the top level. But inside any other RSpec blocks, using RSpec.<foo> defines the entity inside RSpec's top-level :main context. So, that second set of shared, "internal" examples weren't being defined inside 'foo', they were being defined at the top level. This confused things enough to trigger the RSpec warning as soon more than one other file require_relative'd the above code.

The fix was to just do shared_examples 'bar' in the nested set, not RSpec.shared_examples 'bar', so that the inner examples were correctly described inside the inner context.

(Aside: This is an interesting example of how having monkey patching turned off is more important than might at first glance appear to be the case - it's not just for namespace purity. It allows for a much cleaner distinction in declarations between "this is top level" and "this is nested".)

like image 1
Andrew Hodgkinson Avatar answered Nov 14 '22 22:11

Andrew Hodgkinson