Rspec-rails: Route helpers are not defined in helper and view specs

Created on 23 Jun 2016  路  13Comments  路  Source: rspec/rspec-rails

I've just upgraded my Rails version from 4.2.6 to 5.0.0.rc1 and using RSpec version 3.5.0.beta4(was 3.3.3).

Problem is; I have a method which calls root_path in my helper and paths are not defined in helper specs. Issue started after version upgrade.

I'm getting the following error when I run my helper spec;

NoMethodError: undefined method `root_path' for #<#<Class:0x00000002749080>:0x00000011f3e650>

I've tried to add following line to my helper;

include Rails.application.routes.url_helpers

But now error is the following;

NameError: undefined local variable or method `default_url_options' for #<#<Class:0x00000001efa550>:0x0000001784ccd8>

How can I define path helpers for helper specs or default_url_options?

Has reproduction case

Most helpful comment

@mrageh

After adding the rails-controller-testing the url helpers still work on both view/helper specs.

I can push a repo up and maybe someone else can try to reproduce the issue?

I created vanilla rails 5.0 app and investigated root cause by adding each gem from my Rails app's Gemfile.
At this time I suspect that there is something conflict between rails-controller-testing and twitter/secureheaders.

How to reproduce

Create vanilla Rails 5.0 app:

$ rails -v
Rails 5.0.0
$ rails new experiment --skip-bundle --skip-test
$ cd experiment

Add rspec-rails and rails-controller-testing to Gemfile:

group :development, :test do
  gem 'rspec-rails', '3.5.0'
end

group :test do
  gem 'rails-controller-testing', '0.1.1'
end

Install rspec-rails:

$ bundle --path vendor/bundle
$ rails generate rspec:install

Define route:

# config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
end

Add helper spec:

# spec/helpers/application_helper_spec.rb
require 'rails_helper'

RSpec.describe ApplicationHelper, type: :helper do
  it 'has url helper' do
    p root_path
  end
end

Test finished without failures:

$ rake
/Users/juno/.rbenv/versions/2.3.1/bin/ruby -I/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/lib:/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-support-3.5.0/lib /Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb
/Users/juno/src/experiment/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /Users/juno/src/experiment/config/application.rb to limit the frameworks that will be loaded.
"/"
.

Finished in 0.00954 seconds (files took 4.17 seconds to load)
1 example, 0 failures

Add secure_headers to Gemfile and bundle it.

gem 'secure_headers', '3.3.2'

Test has failed:

$ rake
/Users/juno/.rbenv/versions/2.3.1/bin/ruby -I/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/lib:/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-support-3.5.0/lib /Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb
/Users/juno/src/experiment/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /Users/juno/src/experiment/config/application.rb to limit the frameworks that will be loaded.
F

Failures:

  1) ApplicationHelper has url helper
     Failure/Error: p root_path

     NameError:
       undefined local variable or method `root_path' for #<RSpec::ExampleGroups::ApplicationHelper:0x007fd95f9608a8>
     # ./spec/helpers/application_helper_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.01303 seconds (files took 4.2 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/helpers/application_helper_spec.rb:4 # ApplicationHelper has url helper

/Users/juno/.rbenv/versions/2.3.1/bin/ruby -I/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/lib:/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-support-3.5.0/lib /Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb failed

I confirmed this with secure_headers 2.5.2 (previous major release) and 3.3.2 (current release).
Unfortunately I have no time to find out the cause of this confliction...

@samphippen
I hope this will be of some help.

All 13 comments

Same issue with Rails 5.0.0 and Rspec 3.5.0.

Thanks for the issue. We need a little more detail to be able to reproduce this.

Could you please provide us with a rails app that we can clone that demonstrates the issue. Specifically it'd be great if

1) you could rails new an application and commit
2) make all the changes necessary to reproduce the issue and commit

then, provide us with a description of how to clone your application and reproduce the issue.

Thanks :)

Same here.
My problem has solved by removing rails-controller-testing gem from Gemfile.

@samphippen I've created a new rails app with an initial commit without rails-controller-testing gem and the url helpers work fine in both view/helper specs.

After adding the rails-controller-testing the url helpers still work on both view/helper specs.

I can push a repo up and maybe someone else can try to reproduce the issue?

Version info Rails 5.0.0, Rspec 3.5.0 and gem rails-controller-testing 0.1.1

@mrageh thanks for giving it a go. We test against a new vanilla rails app as part of RSpec Rails's test suite. If we can get a clean reproduction case, then I'll gladly take a look at the issue. For the moment we've not seen a rails app that can produce this issue, so we can't debug. I'm happy to take a look at this as soon as there's a reproduction case. I suspect we'll upstream this to rails also.

@mrageh

After adding the rails-controller-testing the url helpers still work on both view/helper specs.

I can push a repo up and maybe someone else can try to reproduce the issue?

I created vanilla rails 5.0 app and investigated root cause by adding each gem from my Rails app's Gemfile.
At this time I suspect that there is something conflict between rails-controller-testing and twitter/secureheaders.

How to reproduce

Create vanilla Rails 5.0 app:

$ rails -v
Rails 5.0.0
$ rails new experiment --skip-bundle --skip-test
$ cd experiment

Add rspec-rails and rails-controller-testing to Gemfile:

group :development, :test do
  gem 'rspec-rails', '3.5.0'
end

group :test do
  gem 'rails-controller-testing', '0.1.1'
end

Install rspec-rails:

$ bundle --path vendor/bundle
$ rails generate rspec:install

Define route:

# config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
end

Add helper spec:

# spec/helpers/application_helper_spec.rb
require 'rails_helper'

RSpec.describe ApplicationHelper, type: :helper do
  it 'has url helper' do
    p root_path
  end
end

Test finished without failures:

$ rake
/Users/juno/.rbenv/versions/2.3.1/bin/ruby -I/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/lib:/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-support-3.5.0/lib /Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb
/Users/juno/src/experiment/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /Users/juno/src/experiment/config/application.rb to limit the frameworks that will be loaded.
"/"
.

Finished in 0.00954 seconds (files took 4.17 seconds to load)
1 example, 0 failures

Add secure_headers to Gemfile and bundle it.

gem 'secure_headers', '3.3.2'

Test has failed:

$ rake
/Users/juno/.rbenv/versions/2.3.1/bin/ruby -I/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/lib:/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-support-3.5.0/lib /Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb
/Users/juno/src/experiment/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /Users/juno/src/experiment/config/application.rb to limit the frameworks that will be loaded.
F

Failures:

  1) ApplicationHelper has url helper
     Failure/Error: p root_path

     NameError:
       undefined local variable or method `root_path' for #<RSpec::ExampleGroups::ApplicationHelper:0x007fd95f9608a8>
     # ./spec/helpers/application_helper_spec.rb:5:in `block (2 levels) in <top (required)>'

Finished in 0.01303 seconds (files took 4.2 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/helpers/application_helper_spec.rb:4 # ApplicationHelper has url helper

/Users/juno/.rbenv/versions/2.3.1/bin/ruby -I/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/lib:/Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-support-3.5.0/lib /Users/juno/src/experiment/vendor/bundle/ruby/2.3.0/gems/rspec-core-3.5.0/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb failed

I confirmed this with secure_headers 2.5.2 (previous major release) and 3.3.2 (current release).
Unfortunately I have no time to find out the cause of this confliction...

@samphippen
I hope this will be of some help.

I've pushed a demo app which reproduces this here: https://github.com/samphippen/demo_app_for_rspec_1644

Thanks for that app @samphippen. I tried reproducing it in my own app with just rspec-rails, and it _worked_. The difference between my app and yours was the addition of the rails-controller-testing gem:

group :test do
    gem 'rails-controller-testing', '0.1.1'
end

If I comment these lines out in your app's Gemfile, then the issue goes away. I'll continue to investigate this and try to get to the bottom of what rails-controller-testing is doing.

Interestingly, you can work around the problem by not requireing the gem in the Gemfile:

in Gemfile:

group :test do
  gem 'rails-controller-testing', require: false
end

in rails_helper.rb(or an initializer, or whereever)

require 'rails-controller-testing'

You do then have to explicitly load configure the helpers in rails_helper.rb

[:controller, :view, :request].each do |type|
  config.include ::Rails::Controller::Testing::TestProcess, type: type
  config.include ::Rails::Controller::Testing::TemplateAssertions, type: type
  config.include ::Rails::Controller::Testing::Integration, type: type
end

I don't know the exact mechanism causing the Gemfile-require'd variant to not work, but this workaround works in my apps (views in test can see helpers, rails-controller-testing features still work).

I would've thought you could achieve the same effect by putting the offending content from the gem into a Railtie with an initialize block, but that doesn't seem to work.

This should be fixed upstream.

馃憤

This will probably help somebody. I spent so much time to track it down.

In a very old test I had this:

before(:each) do
  routes.draw { get 'search' => 'warden#search' }
end

which caused helper tests to fail intermittently.

Fixed by adding:

  after do  
    Rails.application.reload_routes!
  end
Was this page helpful?
0 / 5 - 0 ratings