Capybara is confusing me. If I use Capybara in combination with Ruby on Rails 3 and RSpec 2, then in RSpec request tests, the following matcher works:
response.body.should have_selector "div.some_class"
The response object has the class ActionDispatch::TestResponse. But the following line, which should work officially, does not work:
page.should have_selector "div.some_class"
The page object has the class Capybara::Session. In which cases do you have to use the response.body object and when do you have to use a page object ?
So I just ran into similar, and this is I think what's going on:
It depends on code you didn't include here of how you visit the page. I'm writing an rspec request spec.
If I retrieve the page with rspec's own:
get '/some/path'
then response.body.should have_selector works as you say, but page.should does not.
To make Capybara 'page' work (and to make Capybara interactions like click_button or fill_in work), instead of retrieving with rspec's 'get', you need to retrieve with Capybara's 'visit':
visit '/some/path'
page.should have_selector("works")
'page', a capybara method, only gets set when using 'visit', a capybara method.
This does get confusing, all the mixing and matching of different libraries involved in rails testing.
You would use response when you want to use the standard rails methods. And, alternately, you'd use page when you want to use the capybara methods. In capybara you'd most likely use have_css in the example given.
Related
I am writing tests for a Sinatra app that takes input from an API via a gem. Once I have the API response I need to test that the template has correctly rendered. The response of the API will be the HTML of the page that I am loading.
My first instinct was to write a test that looks like this:
describe 'the root path'
it 'should render the index view' do
get '/'
expect(last_response).to render_template(:index)
end
end
Unfortunately when I try this I get the following error: undefined method `render_template'
I was wondering if anyone has encountered this problem - it seems like it should be an easy fix, but I can't seem to find any documentation to help with it.
I'm currently not testing views at all because of time constraints, but I did have some limited successs with Rack::Test.
In theory you can say:
require 'rack/test'
include Rack::Test::Methods
def app
Sinatra::Application
end
describe 'it should render the index view' do
get '/'
expect(last_response).to be_ok
expect(last_response.body).to eq(a_bunch_of_html_somehow)
end
If I were to go this road again, since my views are haml, I could implement the a_bunch_of_html_somehow method using a call to Haml::Engine -- but I'm not sure whether that helps you.
I'm lifting this wholesale from the Sinatra site here -- the page is well worth a read.
We ended up scrapping this approach since it was better handled by integration testing tool suites such as Selenium or Capybara. There is no equivalent that I could find in the basic Sinatra Rspec suite that could do this - it made more sense to move it into a different scope
This one has had me stumped for a couple of days..
I have a cucumber test which fails with rails 3.2.11 but passes on rails 3.2.3. I'm getting a no route matches error however when I go through the exact same steps manually on the website it works.
My routes are -
get 'reward_player/:id' => 'reward_players#show', :as => :reward_player
And the error I am getting is
No route matches {:controller=>"admin/reward_player", :action=>"show", :id=>nil}
My step to visit this page is just click_link "Reward Player". When I use save_and_open_page to view the page the id is in the link. I'm really not sure what is going on or if it is a test that should have always been failing.
So it ended up being my route, it should have been
get 'reward_player/:user_id' => 'reward_players#show', :as => :reward_player
seeing as the controller was looking for a user_id in the params. So ended up being a test that shouldn't have really pass to start with.
Go gentle on me: I've got the flu and only a few of my neural synapses are firing!
Here's a simple requests test for RSpec:
require 'spec_helper'
describe 'Home Page' do
it 'should mention Home' do
get '/'
response.body.should have_content("Home")
end
end
Great. It works. Now I want to verify that there's an image loaded when visting the home page as well. I assume there's a matcher for images similar to have_content(), so I first go looking for the definition of have_content().
Not found in
https://www.relishapp.com/rspec/search?query=have_content
http://guides.rubyonrails.org/testing.html
http://api.rubyonrails.org/
But the I remember that RSpec has nifty naming rules for matchers, so (e.g.) even?() => be_even(). But even then, searching for "content" in the above doesn't find anything.
(As an aside, I'm pretty sure I'm not looking for the Capybara method of the same name, since I'm doing a get and not visit. Right?)
At the risk of getting this question rejected for being too vague: where the heck is this method coming from, and where do I learn what else I can pass to response.body.should?
RSpec request specs use Capybara, so you can use either get or visit.
If you want to just check that the page has an <img> element with the correct link, you could use:
response.should have_selector('img', :src => '...')
I'm pretty new to Rails. I have been developing my app with RSpec. I have just followed a tutorial for Facebooker2 and added the before_filter for authentication.
#app/controller/application_controller.rb
before_filter :ensure_authenticated
However, my specs such as the one below failed because there's no valid session which is understandable.
#spec/controllers/answers_controller_spec.rb
describe "GET index" do
it "assigns all answers as #answers" do
get :index, {}, valid_session
assigns(:answers).should include(answers(:reading))
end
end
But I can't seem to find a way to fake a valid session for rspec to use in the following function.
#spec/controllers/answers_controller_spec.rb
def valid_session
{}
end
Is there a way at all? If not, what is the rails way of doing things for such a case?
If you aren't concerned about testing the actual authentication and just want to simulate a valid session, you could stub out the filter:
controller.stub(:ensure_authenticated).and_return(true)
EDIT: you may need ApplicationController.stub(...)
I'm using cucumber to test my rails 3.1 application and i'm using devise for authentication.
I need to test if current user email is the same with the one used during authorization.
The problem is that devise helpers are not available in cucumber step definition.
Is there any solution to make devise helpers available in cucumber step definitions?
i tried this:
Cucumber::Rails::World.send('define_method', 'current_user') do
#current_user ||= (session[:user] && User.find(session[:user])) || :false
end
but that didn't help.
Add this to the step definitions file that needs to use it:
World(Devise::TestHelpers)
While this makes the 'sign_in' and 'sign_out' methods available, they can't actually be used from Cucumber, so this DOES NOT WORK. The comments at the top of devise's file says "Do not use Devise::TestHelpers in integration tests". See: https://github.com/plataformatec/devise/blob/master/lib/devise/test_helpers.rb
Unfortunately, cucumber steps don't have access to the web request object and session parameters. It appears the only way to do this is to repeatedly perform the login web requests at the start of each scenario. Boring. I find it odd that cucumber can directly manipulate the test rails app's database but not the web request/session. In any case, this old post shows a good example of refactoring steps to be in a module that can be shared by many steps easily: http://drnicwilliams.com/2009/04/15/cucumber-building-a-better-world-object/
If anyone else has an answer for how a scenario can set the logged in state without having to do all the capybara web calls, I'd love to hear it.
You can do this to stub log ins in Cucumber:
https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara
put the lines in support/env.rb:
include Warden::Test::Helpers
After do
Warden.test_reset!
end
then you can do:
user = create :user
login_as :user, scope: :user
BUT, the login_as helper does not redirect you to the next page after logging you in. It just logs you in.
So you must explicitly go to the next page you are testing as a logged in user.
So you must do another step to explicitly do that, e.g. visit '/'
Something that may help is https://github.com/ngty/cross-stub - this allows you to stub methods cross process, which is necessary for cucumber testing sometimes