This is a mild annoyance I've noticed when running my rspec (v3.3.1) test suite.
For all test cases where I've used the be_success matcher, a newline is printed on my terminal. As a result, on running the suite, my terminal looks like this:
....*.................
.
.......
..
.
.......................................................F....T
Instead of
....*...................................................................................F....T
which is what I'd like.
I figured be_success is the culprit by running my suite with the --format d option and noticed that only tests that use be_success, cause a new line to be printed.
I'd like to know if there's a way I can get rid of this without having to replace be_success with something like have_http_status(200).
Thanks!
be_success does not normally print lines. All it does it call success?.
My guess is that you've got a puts in your success? implementation and/or in something success? delegates to. Perhaps from a past debugging session?
Related
I am following along with the Ruby on Rails Tutorial by Michael Hartl and am up to the point of running tests. The test is a simple "supposed to fail" test shown here:
test "should get about" do
get static_pages_about_url
assert_response :success
end
with the error being simply that the about page, controller method, and route do not yet exist. However when I run the test I get a massive block of code which fills up my terminal. This is just a small sampling as an example of what i'm seeing.
E
Error:
StaticPagesControllerTest#test_should_get_about:
NameError: undefined local variable or method `static_pages_about_url' for #<StaticPagesControllerTest:0x00007fe6682cc760 #_routes=nil, #NAME="test_should_get_about", #failures=[#<Minitest::UnexpectedError: Unexpected exception>], #assertions=0, #integration_session=#<#<Class:0x00007fe6685342c8>:0x00007fe66859fc58 #_routes=nil, #app=#<SampleApp::Application:0x000055d7735cea68 #_all_autoload_paths=["/home/clay/Programs/sample_app/app/channels", "/home/clay/Programs/sample_app/app/controllers", "/home/clay/Programs/sample_app/app/controllers/concerns", "/home/clay/Programs/sample_app/app/helpers", "/home/clay/Programs/sample_app/app/jobs", "/home/clay/Programs/sample_app/app/mailers", "/home/clay/Programs/sample_app/app/models", "/home/clay/Programs/sample_app/app/models/concerns"], #_all_load_paths=["/home/clay/Programs/sample_app/lib", "/home/clay/Programs/sample_app/vendor", "/home/clay/Programs/sample_app/app/channels", "/home/clay/Programs/sample_app/app/controllers", "/home/clay/Programs/sample_app/app/controllers/concerns", "/home/clay/Programs/sample_app/app/helpers", "/home/clay/Programs/sample_app/app/jobs", "/home/clay/Programs/sample_app/app/mailers", "/home/clay/Programs/sample_app/app/models", "/home/clay/Programs/sample_app/app/models/concerns"], #app=#<ActionDispatch::HostAuthorization:0x000055d774009820 #app=#<Rack::Sendfile:0x000055d774009988 #app=#<ActionDispatch::Static:0x000055d773fe4f98 #app=#<ActionDispatch::Executor:0x000055d773fe5088 #app=#<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x000055d77382f4d8 #name="ActiveSupport::Cache::Strategy::LocalCache", #local_cache_key=:active_support_cache_null_store_local_cache_4420, #app=#<Rack::Runtime:0x000055d773fe51f0 #app=#<Rack::MethodOverride:0x000055d773fe5290 #app=#<ActionDispatch::RequestId:0x000055d773fe5330 #app=#<ActionDispatch::RemoteIp:0x000055d773fe5420 #app=#<Rails::Rack::Logger:0x000055d773fe54e8 #app=#<ActionDispatch::ShowExceptions:0x000055d773fe5588 #app=#<ActionDispatch::DebugExceptions:0x000055d773fe56c8 #app=#<ActionDispatch::ActionableExceptions:0x000055d773fe5790 #app=#<ActionDispatch::Reloader:0x000055d773fe58f8 #app=#<ActionDispatch::Callbacks:0x000055d773fe5998 #app=#<ActionDispatch::Cookies:0x000055d773fe5a38 #app=#<ActionDispatch::Session::CookieStore:0x000055d773fe5c68 #app=#<ActionDispatch::ContentSecurityPolicy::Middleware:0x000055d773fe5d58 #app=#<ActionDispatch::PermissionsPolicy::Middleware:0x000055d773fe5e20 #app=#<Rack::Head:0x000055d773fe5ec0 #app=#<Rack::ConditionalGet:0x000055d773fe5f60 #app=#<Rack::ETag:0x000055d773fe6050 #app=#<Rack::TempfileReaper:0x000055d773fe60f0
All I really need is the NameError: undefined local variable or method 'static_pages_about_url' and the location of the failing test right? Is this standard for failing tests in Ruby on Rails or is there a way to change how error messages are displayed from showing all of this less useful information?
In test driven development (TDD), you write the tests first. When you run them, all of them will be failing because you have not written the implementation yet (this is your "Red"). After that, you write the implementation that makes the tests pass (this is your "Green"). Once all tests are passsing, it comes the stage where you refactor the implementation (if required, this is your "Refactor"). Red, Green, Refactor.
In your particular example, you have written the test that checks if you can "GET" the about page but because you have not yet implemented the solution, your tests are failing.
In order to make the test pass, you'll need to add this to your route.rb file.
get 'static_pages/about'
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
New to Ruby, Rails and TDD. I'm using RSpec with Capybara and Capybara webkit.
Trying to test if a div element exists on a page.
Test Code:
require 'spec_helper'
describe "Login module" do
before do
visit root_path
end
it "should have a module container with id mLogin" do
page.should have_css('div#mLogin')
end
it "should have a module container with id mLogin", :js => true do
page.evaluate_script('$("div#mLogin").attr("id")').should eq "mLogin"
end
end
The first test passes but the second test fails with:
Login module should have a module container with id mLogin
Failure/Error: page.evaluate_script('$("div#mLogin").attr("id")').should eq "mLogin"
expected: "mLogin"
got: nil
Ran the JS in browser dev tools and get "mLogin" rather than nil.
Any ideas? Thanks.
find('div#mLogin')[:id].should eq 'mLogin'
See this from doc:
#evaluate_script
Evaluate the given JavaScript and return the result. Be careful when using this with scripts that return complex objects, such as jQuery statements. execute_script might be a better alternative.
evaluate_script always return nil, as far as I remember.
Anyway, your second test seems like is testing if capybara works, because your first test is enough.
One likely problem is that the have_css matcher supports Capybara's synchronization feature. If the selector isn't found right away, it will wait and retry until it is found or a timeout elapses.
There's more documentation about this at http://rubydoc.info/github/jnicklas/capybara#Asynchronous_JavaScript__Ajax_and_friends_
On the other hand, evaluate_script runs immediately. Since this is the first thing you do after visiting the page, there's a race condition: it's possible that it executes this script before the page has finished loading.
You can fix this by trying to find an element on the page that won't appear until the page is loaded before you call evaluate_script.
Alternately, you can wrap your call in a call to synchronize to explicitly retry, but this is not generally recommended. For situations like this, you're much better off using Capybara's built-in matchers. The evaluate_script method should only be used as a last resort when there is no built-in way to accomplish what you need to do, and you need to take a lot of care to avoid race conditions.
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.
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)}