Rspec views fail with Rails 4 mountable engine - ruby-on-rails

I've created a Rails 4 app with a mountable Rails 4 engine called Foobar. That engine contains a scaffold for Items.
After setting up rspec-rails in the engine, I am unable to get the view specs to pass.
I get the following error:
2) foobar/items/index renders a list of items
Failure/Error: render
ActionView::Template::Error:
undefined method `item_path' for #<#<Class:0x007fe6dae7b3c8>:0x007fe6da9a2ec8>
# ./app/views/foobar/items/index.html.erb:21:in `block in ___sers_ianneub__ocuments__ode_rails_engine_spec_test_engines_foobar_app_views_foobar_items_index_html_erb__1719273292435665376_70314743713380'
# ./app/views/foobar/items/index.html.erb:16:in `each'
# ./app/views/foobar/items/index.html.erb:16:in `___sers_ianneub__ocuments__ode_rails_engine_spec_test_engines_foobar_app_views_foobar_items_index_html_erb__1719273292435665376_70314743713380'
# ./spec/views/foobar/items/index.html.erb_spec.rb:20:in `block (2 levels) in <top (required)>'
When starting up the rails server in either the outer application or the engine's spec/dummy app the views all seem to work just fine.
So my question is:
Why do the rspec tests fail, even though the engine views work fine from the rails server?
Bonus question:
What can I change in the index.html.erb to make the test pass?
I'm really trying to understand what is at play here in the rspec tests. IMHO it seems like there is an issue with rspec (and/or rspec-rails) that prevents this from working. Like something isn't being loaded in the tests that would normally make this work inside the rails server. In other words: if it works in the rails server, then it should work in rspec the same way. Would that be correct? What am I missing?
The app is available here:
https://github.com/ianneub/rails-engine-spec-test
You should be able to clone the repo and run these commands to duplicate the error:
cd engines/foobar
bundle install
rspec
Thank you in advance for any help and guidance that you share with me (and the world).

Line 21 in the 'index.html.erb' view needs scoping to the foobar gem.
<td><%= link_to 'Show', foobar.item_path(item) %></td>

That's because Rspec renderer do not include url_helpers methods, but rails renderer somehow included these methods. Could be fixed by
a before hook:
RSpec.configure do |config|
config.before(:example, type: :view) do
view.class_eval do
include <Your Engine Namespace>::Engine.routes.url_helpers
end
end
end

Related

RuntimeError: can't modify frozen Array (Rollbar, Rails 5.1 upgrade)

Unable to use rspec and rollbar after upgrading to rails 5.
Create a Rails 4 app
Upgrade gemfile to use rails 5
Try adding rollbar gem/support
Standard config/environment.rb:
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!
Error when running rspec:
An error occurred while loading {path to specific spec file}
Failure/Error: require File.expand_path('../../config/environment', __FILE__)
RuntimeError:
can't modify frozen Array
# ./config/environment.rb:6:in `<top (required)>'
# ./spec/rails_helper.rb:5:in `<top (required)>'
...
No examples found.
In most cases, that error is a red herring for something else.
When encountering it, don't get overwhelmed with the recurrent can't modify frozen Array error messages, and instead check the very first error that appears when running a spec.
For example:
Failure/Error: validate :uniqueness, if: 'should_be_unique?'
ArgumentError: Passing string to be evaluated in :if and :unless
conditional options is not supported. Pass a symbol for an instance
method, or a lambda, proc or block, instead.
Just to add one tip on top of Maxximo Mussini's answer.
If anyone can't find the first error on the terminal, please try to run RSpec on one file, i.e. rspec spec/models/user_spec.rb
You should be able to find the root case.
In my case, I haven't updated my local .env variables that is required by User model
Hope it helps
Debugging this is not easy but one possible solution is simple. It could be a naming conflict with Rollbar, possibly something getting monkey-patched. If you're seeing this RuntimeError but not using Rollbar, see other answer.
Add a Module ("namespace" of your choice) around your app class definition in config/application.rb.
The module won't affect much. The only difference I could find is when printing out your app it will now appear as (that's how we found the fix vs a new working app):
<MyTestAPP::Application ...> instead of <Application ...>
Change:
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.1
end
To:
Module MyTestApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.1
end
end

Rails Engine - RSpec tests

I my main rails project I have mounted a engine of common code which does common tasks like currency conversion.
I can reference the methods in this common engine like this:
MyCommon::CurrencyHelper.convert_to_currency
This works fine in the project code, but does not seem to be working when I change the RSpec tests to point to the common methods.
The tests fail as it cannot find the common methods:
NoMethodError: undefined method `convert_to_currency' for MyCommon::CurrencyHelper:Module
./spec/helpers/application_helper_spec.rb:211:in `block (3 levels) in <top (required)>'
Do I need to do something else?
If by "I change the RSpec tests to point to the common methods" you mean that you are running the RSpec tests from engines/my_common directory (the engine's tests found in engines/my_common/spec) then you can find/reference your convert_to_currency method like this CurrencyHelper.convert_to_currency in your tests.
So for example, Stuff::BookingSlot.book_a_slot! (where Stuff is the engine) would be tested like this:
it 'book_a_slot! marks a slot as unavailable when a host is available' do
ai = FactoryGirl.create(:booking_slot, available: false, host_id: 1)
ai2 = ai.clone
ai2.update_attributes(available: true, host_id: 2)
BookingSlot.book_a_slot!
expect(ai2.reload.available).to eq false
end

RSpec explicitly tagged cases failing from NameError

I'm currently using rspec-core-3.1.7 with a rails application I've inherited. It seems like the previous owners made a lot of progress with their testing suite, but I can't seem to get it working properly. My spec_helper.rb and rails_helper.rb are fresh from a rails generate rspec:install, with some minor tweaks.
The way the tests are set-up looks as follows:
require "rails_helper"
RSpec.describe FooController, :type => :routing do
...
and here was the relevant error message:
athan#spacerobot:~/website$ rake spec:routing
/home/athan/.rbenv/versions/2.1.2/bin/ruby -I/home/athan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib:/home/athan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/rspec-support-3.1.2/lib /home/athan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/exe/rspec --pattern ./spec/routing/\*\*/\*_spec.rb
/home/athan/website/spec/routing/foo_routing_spec.rb:3:in `<top (required)>': uninitialized constant FooController (NameError)
from /home/athan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/configuration.rb:1105:in `load'
from /home/athan/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/rspec-core-3.1.7/lib/rspec/core/configuration.rb:1105:in `block in load_spec_files'
...
But for some reason, I can't get rspec to find FooController before it throws the NameError. Is it a common convention to... pretend these classes exist, when describing RSpec tests? Where would they come from...? How should I properly define test descriptions?
I am not too familiar with how rails uses rspec, but I do use rspec quite a bit for my test suites. I am suspecting that you need to add a require for the FooController into either the spec_helper.rb or rails_helper.rb. In my case, I require all of my test framework components in the spec_helper.rb so that they are available for all the tests to use. Hope that helps.

Using "Bundle Update" in Rails produced bazillion errors on test

I'm trudging through this deeply error-prone tutorial on Ruby on Rails located here: http://ruby.railstutorial.org/ruby-on-rails-tutorial-book.
I've been working through a section about testing using rspec. Now, the instructions that this tutorial provided created a whole host of errors (deprecations, array issues, etc.) that filled up my page. After rummaging the internet for several hours, I decided to follow several suggestions to update all my gems.
Having updated my gems and attempted to perform this very basic test (the default test really), I got this whole pile of error that I couldn't begin to understand. All I can say is "please help".
Thank you.
> bundle exec rspec spec/requests/static_pages_spec.rb
Rack::File headers parameter replaces cache_control after Rack 1.5.
←[31mF←[0m
Failures:
1) StaticPages GET /static_pages works! (now write some real specs)
←[31mFailure/Error:←[0m ←[31mget static_pages_path←[0m
←[31mNameError:←[0m
←[31mundefined local variable or method `static_pages_path' for #<RSpec::
Core::ExampleGroup::Nested_1::Nested_1:0x5168040>←[0m
←[36m # ./spec/requests/static_pages_spec.rb:6:in `block (3 levels) in <top
(required)>'←[0m
Finished in 0.19901 seconds
←[31m1 example, 1 failure←[0m
Failed examples:
←[31mrspec ./spec/requests/static_pages_spec.rb:5←[0m ←[36m# StaticPages GET /st
atic_pages works! (now write some real specs)←[0m
If you upgraded all your gems to the latest, then one issue you probably have is your newer capybara gem no longer looks for your tests in 'spec/requests'. That test needs to be in 'spec/features' now. If there is no 'spec/features' just create it.
Also, capybara will need this line in your 'spec/spec_helper.rb' if it isn't already:
require 'capybara/rspec'

Ruby/Rails: AssociationTypeMismatch with the correct association, but it expects different object id? Whaaa?

So, I'm getting a pretty strange error here... I tried to isolate it but it's quasi-intermittent. I'm kinda wondering if it has something to do with using capybara with a javascript driver, because this isn't happening in my non-capybara tests. Here it is:
Failure/Error: #existing_user, household = create_new_user_and_household
ActiveRecord::AssociationTypeMismatch:
User(#57141560) expected, got User(#42098260)
# ./app/models/household.rb:64:in `block in create_new_household'
# ./app/models/household.rb:62:in `new'
# ./app/models/household.rb:62:in `create_new_household'
# ./spec/support/spec_helpers.rb:55:in `create_new_user_and_household'
# ./spec/integration/accepting_an_invitation_spec.rb:21:in `block (4 levels) in <top (required)>'
Here's the block in question:
household = Household.new attributes, do |h|
h.account = user.account || Account.create(user: user)
end
Pretty basic, and works fine when I do it manually in the rails console.
I'm not sure what else to tell you guys... but I'm happy to provide more info.
I'm using rspec for all of my testing.
So the answer, as Frederick Cheung pointed out was to set cache_classes to true in test.rb.
This supposedly conflicts with spork, which is why I was told to turn it off in the first place--since you want spork to re-load your models and whatnot whenever you run another test. The solution is to set cache_classes to true but also put ActiveSupport::Dependencies.clear in your spork prefork block.
References:
ActiveSupport:Dependencies
Reloading Models
Spork tips
Spork cache_classes explanation

Resources