rspec stack level too deep - ruby-on-rails

When I run my model specs and controller specs separately, it's fine. When I run them together, I get a stack overflow, literally :)
$ bundle exec rspec --fail-fast spec/models
........
Finished in 0.44274 seconds
8 examples, 0 failures
$ bundle exec rspec --fail-fast spec/controllers
..
Finished in 0.99339 seconds
2 examples, 0 failures
$ bundle exec rspec --fail-fast spec
F
Failures:
1) HerpController derp derp example
Failure/Error: Unable to find matching line from backtrace
SystemStackError:
stack level too deep
# /Users/jared/.rvm/gems/ruby-1.9.2-p290/gems/actionpack-3.2.1/lib/abstract_controller/layouts.rb:359
Finished in 0.02241 seconds
1 example, 1 failure
How do I even begin to debug this? Thanks.

Removing half of my specs at a time turned up the problem. I suppose this is an example of bisect debugging. Thanks to Frederick Cheung, whose comment suggested this approach.
For posterity, this was the problem.
include Rails.application.routes.url_helpers
describe "Attendee#next_page" do
end
Apparently, includes go inside the describe
describe "Attendee#next_page" do
include Rails.application.routes.url_helpers
end
I have a lot to learn about rspec. :)

You can either put a debugger statement in your code and debug that way, or just start using puts "got here" in the places of your code that you know are being run. I would suggest using something meaningful instead of "got here" too :-)

I'd start either with puts or raise statements at key points in your code so you can start to narrow down which line is causing the problem. Once you start getting close, you can comment out one line at a time to figure out which line the problem disappears with - as soon as you've got it down to one line, you can figure out what that line is doing that Ruby doesn't like.
In general terms of where to start, "Stack level too deep" is usually an infinite loop or infinite recursion problem - I'd imagine that there's something going on where a model is invoking a controller that's invoking the model, or vice-versa. No way to know for sure until you start commenting out lines, but any place where you've got function calls is going to belong on your suspect short list. Good luck!

Possibly you can get "Unable to find matching line from backtrace" error in case you are checking some var which wasn't initialised actually
In this example pay attention to var observation which is not initialised in the wrong snippet
wrong snippet
describe "GET index" do
it "assigns all observations as #observations" do
get :index, {}, valid_session
assigns(:observations).should eq([observation])
end
end
fixed example (line 3)
describe "GET index" do
it "assigns all observations as #observations" do
observation = Observation.create! valid_attributes
get :index, {}, valid_session
assigns(:observations).should eq([observation])
end
end
Sometimes we rely on using let as initializer, but forget to add it e.g.
let(:observation) {FactoryGirl.create(:observation)}

Related

Rails 5.1 System Test Fixtures and Database Cleanup

Are rails 5.1 system tests supposed to reset the test database with original fixture data between each test?
This is not happening for me even between completely different test classes. One of my system tests is:
test 'delete thing' do
# deletes a thing from the fixture data
end
then I have another test that just looks to see if the thing is there
test 'view thing' do
# tries to view the thing
end
The test passes if the "view thing" test is ran first. If the "delete thing" test runs first then when my system test tries to view the thing then it fails.
I thought Rails system tests were resetting the data just like all the other tests. Is this not the case? Am I missing something?
Solved this one by changing the number of workers in our config/puma.rb file to 0 instead of 1.
Changing
workers ENV.fetch("WEB_CONCURRENCY") { 1 }
to
workers ENV.fetch("WEB_CONCURRENCY") { 0 }
fixed the issue for us.
I have just been dealing with this exact issue this morning, and I think I have figured it out.
This doc on fixtures helped me a bit: http://api.rubyonrails.org/v5.1.4/classes/ActiveRecord/FixtureSet.html.
For me though, I just had to make sure i was using the ModelName.method approach when my test involved modifying data (like adding and deleting records) as this interacts with the test database and does not change your fixtures. At first I was using the fixture_name.method for both reading and writing, and that led to unexpected results.
So for example, with a model of Blog and a fixture file blogs.yml with one record in it (hashed to key = :one):
test "view blog" do
get blog_path blogs(:one).id
assert_response :success
*OR*
get blog_path Blog.first.id
assert_response :success
end
But if modifying, stick with the second approach:
test "delete blogs" do
assert_equal 1, Blog.count
assert_equal Blog.first.id, blogs(:one).id
Blog.destroy_all
assert_equal 0, Blog.count
assert_raises(NoMethodError) { Blog.first.id }
assert_nothing_raised { blogs(:one).id }
end
test "before_or_after_delete_blogs" do
assert_equal 1, Blog.count
assert_equal Blog.first.id, blogs(:one).id
end
Both of those should pass.
Apologies if my explanation is off base. If that's the case, could you provide a little more context with your example?
I use the gem database_cleaner. Not sure if that's exactly the answer to your problem.
Also this could help?
rake db:test:prepare
Not too sure if your issue but hopefully that helps

Rails RSpec Mocking Date.today.wday in Rake Task

I'm trying to mock Date.today.wday in a rake task in rspec.
Gem versions: RSpec 2.14.8 --- Rails 4.1.1 --- ruby 2.0.0
Here is a simplified fake version of my test to illustrate essentially what I'm trying to do:
describe "scheduler" do
describe ":thursday_invitations" do
let(:run_issue_invites) do
Rake::Task[:thursday_invitations].reenable
Rake.application.invoke_task :thursday_invitations
end
before do
Rake.application.rake_require 'tasks/scheduler'
Rake::Task.define_task(:environment)
Date.today.should_receive(:wday).and_return(4) ###MY NEMESIS CODE LINE
end
context "on thursday" do
it "issues invitations" do
expect(Date.today.wday).to eq(4) ###THE VERIFICATION TEST THAT KEEPS FAILING
run_issue_invites
expect(<other_stuff_to_test>).to <return_properly>
end
end
end
end
So, the real key of this is mocking out the Date.today.wday. Because I want to be able to run my spec on any day of the week, I need to mock/stub out this method to always return "4" (the day-number for Thursday in Rails). So, I initially setup my test to first verify that it is receiving a "4" (the assertion in the test). If today is, say, Friday (which it is) and I run the test, it fails saying that it expected "4" but got "5". That is, it is not returning the value that I want it to when I receive the method. I have tried stubbing with similar ineffective results. Normally, mocking is a breeze, but what seems to be the hangup is .wday which operates on Date.today.
Because this is a rake task (which I'm not as familiar with mocking), I may have to specify something further, but I haven't been able to get to the bottom of it...
Let me know if you need any other clarifying information.
I believe the reason you're not seeing the behavior you expect is that the object you are mocking is the not the same object under test.
In a Rails 4+ environment, this is what I see on the rails console:
[1]> Date.today.object_id
70104549170200
[2]> Date.today.object_id
70104552970360
The fact that the object_id is different in subsequent calls to Date.today means that each call returns a new object. So Date.today.should_receive(:wday).and_return(4) is setting an expectation on an object that will never be used again.
You'll need to rewrite your spec to ensure the same object is returned by Date.today each time. Here's one solution, omitting other parts of your example for clarity:
let!(:today) { Date.today }
before do
Date.stub(:today).and_return(today)
today.should_receive(:wday).and_return(4)
end
it "issues invitations" do
expect(Date.today.wday).to eq(4)
end

Capybara Selenium webdriver Transactional Rollbacks work arounds

I'm writing a couple of Feature Specs for an app and using the default Selenium webdriver that comes with Capybara. This is the spec I have written.
DatabaseCleaner.cleaning do
find(:css,'.dropdown-toggle').click
click_on "Locations"
find(:css, "#location-8-upgradesub-60").click
value1 = find(:css, "#location-8-review-subscription").text
value1.should be == '(2) Reviews (Paid)'
end
I'm facing 2 issues with this snippet:
1) Capybara isn't waiting for the XHR to get over and is coming out of the test before that. It works if I give a sleep condition for about 10 sec.
UPDATE
Solved 1) by setting Capybara.default_wait_time = 15 and writing a helper to make sure jQuery isn't active. page.evaluate_script('jQuery.active').zero?
2) I'm not able to rollback the DB transaction that takes place when selenim simulates the test. I see an INSERT and COMMIT in the test.log but no ROLLBACK because of which I need to keep changing my specs every time I run the test. If I use,DatabaseCleaner.strategy = :truncation, my entire DB gets wiped out and that is not something I want.
I've done some extensive googling on this issue and haven't been able to find an efficient work around. I've tried using the same transactional thread too, for the test server. Haven't had fruitful results with too! Any heads up or help would be greatly appreciated. Thanks in advance!
UPDATE
I followed this link https://relishapp.com/rspec/rspec-rails/docs/transactions and put my spec inside a before(:each) block and stored the value in an #value1 instance variable to compare it with the desired value within the it block. I haven't had any luck with that too.
before(:each) do
find(:css,'.dropdown-toggle').click
click_on "Locations"
find(:css, "#location-8-upgradesub-60").click
wait_for_ajax #Helper method to wait for ajax call to get over
find(:css, "#location-8-review-subscription").should be_visible
#value1 = find(:css, "#location-8-review-subscription").text
end
it "should open the dropdown, find Location and open it's modal", js:true do
#value1.should be == '(2) Reviews (Paid)'
end
With 1), I think have_content or have_selector will work. These methods will wait for some seconds before checking the content/selector exist. You could config this time via spec_helper.rb. You could put have_content/have_selector BEFORE your find(..).click to make sure it is exist before next tests.
Finally found a work around. I added this code snippet in spec_helper.rb. Not using Database Cleaner anymore.
Reference: http://www.opinionatedprogrammer.com/2011/02/capybara-and-selenium-with-rspec-and-rails-3/#comment-441060846. The entire comment thread is pretty useful.
ActiveRecord::ConnectionAdapters::ConnectionPool.class_eval do
def current_connection_id
# Thread.current.object_id
Thread.main.object_id
end
end

RSpec No example found

For some reason, RSpec is not recognizing assertions in one of my spec files - but runs the print statement around it.
To start the spec test, on the terminal:
rspec spec/lib/slots_scheduler_spec.rb
Part of the spec file that asserts... (is part of a loop)
print "#{slots_result[0].date} #{slot.date}\n"
slots_result[0].date.should == slot.date
And what I see on the console...
....
2012-11-18 2012-11-11
2012-11-25 2012-11-11
No examples found.
Finished in 0.00005 seconds
0 examples, 0 failures
If something is wrong, I expect some other message than '0 examples, 0 failures'. Why are my tests ignored like this?
You Haven't Defined an Example Group
Your code, as posted above, has no example groups. Example groups require a describe or context block, and a specify or it block for each test in order to work.
Your print statements work because they are valid Ruby. However, the RSpec DSL requires more from you before it will result in an actual test being performed.

capybara error message, test still passes

When I run integrations tests with Capybara/webkit I get this error message:
undefined|36|TypeError: Result of expression 'node' [undefined] is not an object.
However it doesn't cause the test to fail and it doesn't always occur. When it does occur it seems to occur at the same point in the test (right before the final assertion)
test:
it "does something with things" do
#....
within('#dialog_box') do
click_button 'Save'
end
puts 'after within'
page.should have_content(thing_attrs[:name])
puts 'after assertion'
end
Final output:
after within
undefined|36|TypeError: Result of expression 'node' [undefined] is not an object.
after assertion
does something with things [pass]
How can I narrow down what is causing this? It makes test output ugly :)
I had a very similar problem, the error I was getting was:
undefined|0|TypeError: 'undefined' is not an object
In the end in order to figure out where it was coming from, I removed js files from application.js one by one until the error disappeared. Once I had narrowed it down, I figured out that there was, in fact, an undefined variable, which wasn't causing any issues and hence all tests were passing.
There might be a better way to do this, not really sure, but this approach worked for me. Best of luck.

Resources