Skip to content

rails_example_group: don't include RSpec::Rails::FixtureSupport if it's not defined #1407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

rails_example_group: don't include RSpec::Rails::FixtureSupport if it's not defined #1407

wants to merge 1 commit into from

Conversation

weedySeaDragon
Copy link

If ActiveRecord::Fixtures isn't defined, then the line include RSpec::Rails::FixtureSupport in
rspec/rails/example/rails_example_group throws an error.

I found this when I started to use the ammeter gem to help me write a spec for a generator.
The ammeter gem requires 'rspec/rails/example/rails_example_group' which has the line include RSpec::Rails::FixtureSupport.
#1372 introduced a conditional around the definition for RSpec::Rails::FixtureSupport (in rspec/rails/fixture_support.rb) so that the class is not defined if ActiveRecord::TestFixtures isn't defined. So when the include RSpec::Rails::FixtureSupport line in rspec/rails/example/rails_example_group is evaluated, an error is thrown since RSpec::Rails::FixtureSupport was never defined. This include line needs a conditional to check for this situation. I tested this correction: include RSpec::Rails::FixtureSupport if RSpec::Rails::FixtureSupport rescue false and it works.

Here's the environment and generator spec test file that shows the error:
Ruby 2.1.5p273
Rails 4.2.1
rspec (3.3.0)
rspec-rails (3.3.2) [I also tested master; same error occurs, same fix works]
ammeter (1.1.2)

spec_helper.rb and rails_helper.rb have defaults. No modifications were made to the originally installed files.

Generator spec test file:

   #  runs successfully with this line changed in rspec/rails/example/rails_example_group:
   #    original line: include RSpec::Rails::FixtureSupport if RSpec::Rails::FixtureSupport
   #    revised line:  include RSpec::Rails::FixtureSupport if RSpec::Rails::FixtureSupport rescue false # AE 2015-06-24
   require 'rails_helper'

   class RspecRailsFixturesBugGenEx < Rails::Generators::NamedBase
     def generate_stuff
     end
     def generate_nonsense
     end
   end

   describe RspecRailsFixturesBugGenEx do
     # Tell the generator where to put its output (
     destination File.expand_path("../../../../../tmp", __FILE__)
     before { prepare_destination }
     it 'runs all tasks in the generator' do
       gen = generator %w(posts)
       gen.should_receive :generate_stuff
       gen.should_receive :generate_nonsense
       gen.invoke_all
     end
   end

Stack trace with the error:
(I'm using RubyMine so a bit of that cruft is in the trace output.)

C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-rails-1fb6f9f642e8/lib/rspec/rails/example/rails_example_group.rb:14:in `<module:RailsExampleGroup>': uninitialized constant RSpec::Rails::FixtureSupport (NameError)
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-rails-1fb6f9f642e8/lib/rspec/rails/example/rails_example_group.rb:8:in `<module:Rails>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-rails-1fb6f9f642e8/lib/rspec/rails/example/rails_example_group.rb:6:in `<module:RSpec>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-rails-1fb6f9f642e8/lib/rspec/rails/example/rails_example_group.rb:5:in `<top (required)>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/ammeter-1.1.2/lib/ammeter/rspec/generator/example/generator_example_group.rb:4:in `<top (required)>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/ammeter-1.1.2/lib/ammeter/rspec/generator/example.rb:2:in `<top (required)>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/ammeter-1.1.2/lib/ammeter/init.rb:7:in `<top (required)>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/ammeter-1.1.2/lib/ammeter/railtie.rb:4:in `block in <class:Railtie>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/railties-4.2.1/lib/rails/initializable.rb:30:in `instance_exec'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/railties-4.2.1/lib/rails/initializable.rb:30:in `run'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/railties-4.2.1/lib/rails/initializable.rb:55:in `block in run_initializers'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:226:in `block in tsort_each'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:427:in `each_strongly_connected_component_from'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:347:in `block in each_strongly_connected_component'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:345:in `each'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:345:in `call'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:345:in `each_strongly_connected_component'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:224:in `tsort_each'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/2.1.0/tsort.rb:205:in `tsort_each'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/railties-4.2.1/lib/rails/initializable.rb:54:in `run_initializers'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/gems/railties-4.2.1/lib/rails/application.rb:353:in `initialize!'
    from C:/Users/ashley/RubymineProjects/RJInvestments/config/environment.rb:5:in `<top (required)>'
    from C:/Users/ashley/RubymineProjects/RJInvestments/spec/rails_helper.rb:5:in `require'
    from C:/Users/ashley/RubymineProjects/RJInvestments/spec/rails_helper.rb:5:in `<top (required)>'
    from C:/Users/ashley/RubymineProjects/RJInvestments/spec/generators/rr_fixtures_bug_spec.rb:18:in `require'
    from C:/Users/ashley/RubymineProjects/RJInvestments/spec/generators/rr_fixtures_bug_spec.rb:18:in `<top (required)>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/lib/rspec/core/configuration.rb:1332:in `load'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/lib/rspec/core/configuration.rb:1332:in `block in load_spec_files'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/lib/rspec/core/configuration.rb:1330:in `each'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/lib/rspec/core/configuration.rb:1330:in `load_spec_files'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/lib/rspec/core/runner.rb:102:in `setup'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/lib/rspec/core/runner.rb:88:in `run'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/lib/rspec/core/runner.rb:73:in `run'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/lib/rspec/core/runner.rb:41:in `invoke'
    from C:/rubys/ruby-2.1.5-x64-mingw32/lib/ruby/gems/2.1.0/bundler/gems/rspec-core-0697d3a9894f/exe/rspec:4:in `<top (required)>'
    from C:/rubys/ruby-2.1.5-x64-mingw32/bin/rspec:23:in `load'
    from C:/rubys/ruby-2.1.5-x64-mingw32/bin/rspec:23:in `<top (required)>'
    from -e:1:in `load'
    from -e:1:in `<main>'

FixtureSupport may not be defined if  defined?(ActiveRecord::TestFixtures) == false. This is done in  lib/rspec/rails/fixture_support.rb  .  If FixtureSupport isn't defined, the line that tries to include it will throw an error.  Only include it if the class is defined.
@@ -11,7 +11,7 @@ module RailsExampleGroup
include RSpec::Rails::MinitestLifecycleAdapter if ::Rails::VERSION::STRING >= '4'
include RSpec::Rails::MinitestAssertionAdapter
include RSpec::Rails::Matchers
include RSpec::Rails::FixtureSupport
include RSpec::Rails::FixtureSupport if RSpec::Rails::FixtureSupport rescue false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to check if RSpec::Rails::FixtureSupport is defined then if defined?(RSpec::Rails::FixtureSupport) is a lot nicer than rescue false, but I'm unsure why this is necessary

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually specifically check for if defined?(ActiveRecord::TestFixtures) and make this module a no op if so.

@JonRowe JonRowe closed this Jun 25, 2015
@JonRowe
Copy link
Member

JonRowe commented Jun 25, 2015

I think this out dated vs master, in master we define the module regardless, but only have the contents of the module applied when fixture support is available.

@cupakromer
Copy link
Member

❤️ Sorry you ran into this. The fixture support file defines the constant, regardless of if ActiveRecord::TestFixtures is available:

module RSpec
  module Rails
    # @private
    module FixtureSupport
      if defined?(ActiveRecord::TestFixtures)
        # Content here
      end
    end
  end
end

This issue sounds like something is not calling require 'rspec/rails' prior to using one of the components. rspec-rails is not currently designed to load individual pieces ad-hoc. The library needs to be required as a whole.

Looking at the stack it seems ammeter is what is only attempting to load part of rspec-rails 😦. The fix should come from there. There are a multiple dependencies that need to be loaded and setup. Currently this is handled by rspec-rails when you require 'rspec/rails'.

We may well move in the direction of allowing components to be required stand alone; however, we will still have the base requirement that require 'rspec/rails' is called first. The other rspec repos have this same requirement, as does ActiveSupport before you load parts ad-hoc.

@weedySeaDragon
Copy link
Author

Thanks for the really complete and very helpful responses @JonRowe and @cupakromer . You're exactly right: ammeter is only requiring selected parts of rspec/rails. I'll submit a PR over there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants