Why consider_all_requests_local fails with rspec config - ruby-on-rails-3

rspec-rails (2.7.0) rails (3.0.10)
post: Rails 3.1 Error Catching is irrelevant for me.
Code:
class ApplicationController < ActionController::Base
unless Rails.application.config.consider_all_requests_local
rescue_from ActiveRecord::RecordNotFound, :with => :render_404
rescue_from Exception, :with => :render_500
rescue_from FunnyException, :with => :my_errors
def my_errors(exception)
#some stuff for production
puts "=======From top====#{Rails.application.config.consider_all_requests_local}"
end
else
rescue_from FunnyException, :with => :my_errors
def my_errors(exception)
#some stuff for development
puts "=====From bottom======#{Rails.application.config.consider_all_requests_local}"
end
end
end
This code perfectly works with production/development... problem is when I wanna test it with rspec. How to switch test case between environments?
I tried adding something like:
before do
Rails.application.config.consider_all_requests_local = true
end
I get:
...=====From bottom======true .=====From bottom======true .=====From
bottom======true .=====From bottom======true
so tried
before do
Rails.application.config.consider_all_requests_local = false
end
so I get:
...=====From bottom======false .=====From bottom======false .=====From
bottom======false .=====From bottom======false
How is that even possible? ... same with changing spec_helper
config.before(:each) do
Rails.application.config.consider_all_requests_local = false
end
unless is not working. Top section is unreachable with rspec... always hits Bottom why ? I assume it is somehow tied now with Rack... but is there any solution to dynamically change this behavior inside rspec?
regards

Ok I found quite easy solution
before do
Rails.application.config.consider_all_requests_local = false
load "application_controller.rb"
end
after do
Rails.application.config.consider_all_requests_local = true
load "application_controller.rb"
end
It is part of anonymous application controller test suite.
You have to add after block... because this change will persist through other suites.
Any improvements welcome :D
edit: Using spork and guard causes for me sometimes random errors... before :all seems to solve that problem

You also need to set Rails.application.config.action_dispatch.show_exceptions = true. But since Rails caches that value, this will only work if you run your spec on its own. Fortunately, you can change these options only for the current spec by mocking the config:
before do
method = Rails.application.method(:env_config)
expect(Rails.application).to receive(:env_config).with(no_args) do
method.call.merge(
"action_dispatch.show_exceptions" => true,
"action_dispatch.show_detailed_exceptions" => false,
"consider_all_requests_local" => false
)
end
end
Thanks to:
http://atodorov.org/blog/2016/04/27/changing-rails-consider_all_requests_local-in-rspec-fails/
https://thepugautomatic.com/2014/08/404-with-rails-4/#comment-1714338343

I found that with cucumber-rails the right way of doing it is to add the #allow-rescue tag.

The logic block is defined on class level, which gets evaluated during the class load time. This is why it will not go to 'else' even if you manually set it to false at run time.
I am also curious to know what's the best way to test this. My only clue is somehow reload or re eval ActionController, similar to reload! method in rails console.

Related

Can't create user for testing using capybara with rspec

I want to test a simple sign in flow, which needs a existed user in the test database.
describe 'Signin page' do
before :each do
User.generate(:email => 'automatic_tester#gmail.com', :password => 'palmdrive', :first_name => 'Automatic', :last_name => 'Tester')
end
it 'signs in a user', :js => true do
signin
current_path.should == redirect_path
end
end
def signin
## Action to sign in the user
end
## Use DatabaseCleaner since selenium driver is used
DatabaseCleaner.strategy = :truncation
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before :each do
DatabaseCleaner.start
end
config.after :each do
DatabaseCleaner.clean
end
end
Because the way to create a user is a little bit more complicated, so I defined the User.generate method to create a user. To ensure it actually works, in the rails console with test environment, running User.generate(:email => 'automatic_tester#gmail.com', :password => 'palmdrive', :first_name => 'Automatic', :last_name => 'Tester')it successfully created a user in database. Comment out the before :each, the test suite passed successfully.
But the problem is running the codes above, the test fails. It was due to the user can't be created in the database. Why can't the User.generate method create a user?
In the spec_helper add:
class ActiveRecord::Base
mattr_accessor :shared_connection
##shared_connection = nil
def self.connection
##shared_connection || retrieve_connection
end
end
# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
solves the issue. Then no need to use the DatabaseCleaner either
Use create instead
User.create(:....)
Note that create will create a record in your database. Writing to the DB is an expensive operation and you may want to avoid that in some cases by using new rather than create.
A better approach is to use factories. See FactoryGirl https://github.com/thoughtbot/factory_girl

Anonymous controller in Minitest w/ Rails

While converting from RSpec to Minitest I ran into a slight issue that Google has not helped with one bit, and that's figuring out how to do something like this:
describe ApplicationController do
controller do
def index
render nothing: true
end
end
it "should catch bad slugs" do
get :index, slug: "bad%20slug"
response.code.should eq("403")
end
end
with Minitest. Is there a way to create anonymous controllers like this inside of Minitest or is there documentation that could help me learn how to test controllers with minitest?
You can do something like that:
# Add at runtime an action to ApplicationController
ApplicationController.class_eval do
def any_action
render :nothing
end
end
# If disable_clear_and_finalize is set to true, Rails will not clear other routes when calling again the draw method. Look at the source code at: http://apidock.com/rails/v4.0.2/ActionDispatch/Routing/RouteSet/draw
Rails.application.routes.disable_clear_and_finalize = true
# Create a new route for our new action
Rails.application.routes.draw do
get 'any_action' => 'application#any_action'
end
# Test
class ApplicationControllerTest < ActionController::TestCase
should 'do something' do
get :any_action
assert 'something'
end
end
I don't think anonymous controllers are supported. Instead of using a DSL to create a controller, try defining a controller in your test.
class SlugTestController < ApplicationController
def index
render nothing: true
end
end
describe SlugTestController do
it "should catch bad slugs" do
get :index, slug: "bad%20slug"
response.code.must_equal "403"
end
end

setting config.action_controller.perform_caching = true breaks routes in rails 3.2.1 app

I am experiencing extremely strange behaviour in Rails 3.2.1
I have some resources that do not have show actions.
For example:
resources :homes, :except => [:show]
In my controller I say:
def update
#domain = Domain.where(:domain => request.domain.split('.').first).first
#home = Home.find(params[:id])
if #home.update_attributes(params[:home])
expire_page :action => :index
redirect_to(admin_path(#domain), :notice => "Updated.")
else
render :action => "edit"
end
end
and all is hunky dory in development.
But in production rails consistently tries to redirect to (the non existent) show action, despite the obvious redirect_to. It's as if this method is ignored totally. In fact I can try and redirect to any path in the app and it will be ignored. As soon as I set perform_caching to false in production.rb the routes begin to behave as expected again! Any ideas why this is happening and how I can make it stop!? Obviously I could turn off caching, but I need the pages to be cached for performance reasons.
Thanks for reading.

Login Failure when Testing with Capybara, Rspec and Selenium in Rails 3.1

I added some confirmation dialog boxes for my Rails 3.1 application and, prior to that, their corresponding tests. Following the model of Railscast #257, I added ':js => true' to the test, added database_cleaner and modified the spec_helper.rb file accordingly.
When I run the test, Firefox launches, Capybara-Selenium fills in the fields the the appropriate username and a password, but log-in fails (i.e., "invalid username/password".) Other tests that do not have ':js => true' and also login, do still pass.
I would like to add more javascript to my application in the future and I am avoiding solutions that would hack Capybara to get this to work (e.g., click 'OK' on all dialogs.)
Any ideas what I might be missing? Fail that, any suggestions on how to debug this problem?
Thank you.
You should set use_transactional_fixtures = false for your seleniumtests.
This can be done in the spec_helper.rb with
config.use_transactional_fixtures = false
for all your tests.
Or do this for a single testcase:
describe 'testcase' , :type => :request do
self.use_transactional_fixtures = false
it 'your test', :js => :true do
testing...
end
end
This happens because selenium-tests access the database in a different way. With transactional fixtures enabled, selenium will work on an empty database -> your user does not exist and you cannot login.
For normal tests you should use transactional fixtures because your tests run much faster.
As per Avdi Grimm's post (features a detailed explanation):
Gemfile:
group :test do
gem 'database_cleaner'
end
spec_helper.rb:
config.use_transactional_fixtures = false
spec/support/database_cleaner.rb:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, :js => true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
I had transactional fixtures disabled but adding the :js => true block to database_cleaner.rb did it for me.

NoMethodError - undefined method

I'm having problems displaying data from a separate controller. I have a number of users, each with many pages. I've followed this tutorial with a few minor adjustments.
The error that keeps appearing is:
NoMethodError in SitesController#show
undefined method `page' for #<ActionDispatch::Request:0x00000102452d30>
My routes.rb is as follows:
devise_for :users
resources :users, :only => [:index, :show] do
resources :pages, :shallow => true
end
match '/' => 'sites#show', :constraints => { :subdomain => /.+/ }
root :to => "home#index"
And I have a sites controller:
class SitesController < ApplicationController
def show
#site = Site.find_by_name!(request.page)
end
end
I've also tried:
def show
#site = Site.find_by_name!(params[:site])
end
Which gives a different error.
Am totally stuck trying to figure this out!
Looking forward to your assistance.
Bob
The problem is here: request.page
The request object is of the class ActionDispatch::Request, which does not have a page method.
To track down errors like this, you can try either looking at the docs or messing around in the debugger.
Try running your controller with --debugger enabled.
If you are running Ruby 1.8, install the ruby-debug gem.
If you are running Ruby 1.9, install the ruby-debug19 gem.
Add a debugger call here:
class SitesController < ApplicationController
def show
debugger
#site = Site.find_by_name!(request.page)
end
end
Run your server with the --debugger option.
See what p request.page does. I bet it will have an "undefined method" error, just you see when you try to view that controller action.
If you do a p request.class you can find out what class the object is, and then look up the docs to see how to use it.