Testing as a logged in user in rails - ruby-on-rails

I wanna test my functionals in my rails application, but the tests require a user/admin to be logged in. I have looked at many websites, but I cannot grasp what I really should be doing to make it work. I'm sure there there is an easy thing to do, but I cannot seem to find it.
I have seen the stubs command used, but I only get that it is an undefined method and I don't really know what it is supposed to do.
Any ideas on how I can run my tests as if it was an user/admin requesting them?
Thanks for any help I might get.

acceptance/integration testing:
If you're using cucumber, just login as the user. Something like:
fill_in 'users[username]', :with => "my username"
fill_in 'users[password]', :with => "my password"
click_button "Log In"
If you're using rspec+capybara, you can do something like this (assuming you're using Devise for authentication)
# spec/spec_helper.rb
include Warden::Test::Helpers
# in spec/acceptance/some_spec.rb
...
login_as FactoryGirl.create(:user)
unit testing
see https://github.com/plataformatec/devise#test-helpers if you're using Devise
otherwise, you can implement similar functionality by writing to the session object, or by stubbing out current_user (assuming you call it that)

Related

Rspec Selenium passing variable using through command and use that variable in test case

I have a test case like this.
describe "City Sports" do
context 'xyz cases' do
it 'checks the xyz signin' do
visit "https://secure-xyz/"
fill_in 'emailAddress', with: email
fill_in 'password', with: "password1"
find_button('signInButton').trigger('click')
if current_url == "https://secure-xyz.do"
#click_button 'Register'
fill_in 'newEmailAddress', with: email
find_button('registerButton').trigger('click')
fill_in 'password', with: 'password1'
find_button('registrationSubmitButton').trigger('click')
end
end
end
I have this test case and the variable email which I am being use in the test case I want to pass through command line like
rspec spec/users:#{email}/sign_in.rb
how can In pass email variable through command line and how can I get this variable in test case.
I solved this by adding the all of the test cases in rake task and I am calling it via.
email="abcAgmail.com,password" rake task:task
and its working fine for me.
Your best bet (if you really want to go down this route) will be to look into using a rake file because as far as I know, without customising the rspec command (I wouldn't recommend this) you won't be able to pass in a variable.
The other cleaner solution will be to keep things like test email addresses inside some sort of config which can then be consumed by your test. For example you could have a test data module:
module TestData
module Users
def known_user
{ email: 'email#example.com', password: 'password' }
end
end
end
This can then be accessed in your test with TestData::Users.known_user and appending [:email] or [:password] depending on which bit of data you're trying to get at. The benefit of this is you're not having to pass variables into tests. After all, surely you're going to want to eventually run a whole test suite and having to provide arguments for each test will become a nightmare.

Upgrade to Rails 4.2 breaks rspec feature specs - why?

My model and controller specs are running fine, but after the upgrade to rails 4.2, my feature specs, which use Capybara, no longer work. Example:
#in spec_helper.rb:
def login_admin
create(:user,
first_name: 'John',
last_name: 'Doe',
email: 'doej#test.com',
admin: true)
visit root_path
fill_in 'email', with: 'doej#test.com'
fill_in 'password', with: 'password1'
click_button 'Log in'
puts 'created'
end
#in spec/features/albums_spec.rb
feature "Albums", :type => :feature do
before(:each) do
login_admin
end
scenario 'do something' do
save_and_open_page
end
end
When I run this spec, it never finishes, either pass or fail. No error is thrown; it just sits there, showing Albums with the cursor beneath. 'created' is never put to stdout, and the page is never launched by the save_and_open_page call. Test log shows the erb file is rendered by my login action. This was all working prior to the rails 4.2 upgrade.
This only fails during the spec run - using the app in the browser works fine.
What am I missing here?
UPDATE: possible problems related to capybara/rspec:
Avoid creating models in feature specs, because they're created in a different thread. Instead, create the user using capybara steps (i.e. "sign up" the user every time).
If you really need the database prepared for scenario in a way impossible to create from clicking around the site, implement a simple "admin" area in your app (you'll probably need one anyway) or admin API interface or something like a CSV upload option, etc.
Otherwise, you can search for "capybara rspec database_cleaner append_after" for a setup to support creating models in feature specs, but I've found that none of the solutions are really bullet-proof. You could try: https://github.com/RailsApps/rails_apps_testing
I'm guessing your example is/was stuck on a database operation (waiting for db connection in other threads to end).
PREVIOUS ANSWER:
A few ideas:
catch exceptions in the login_admin method and print them out using STDERR.puts
remove the click_button and see if it fails as expected (shows you the login page)
add a sleep 4 after the password is typed in
separate the click_button into 2 calls (to see which one hangs):
btn = find(:button, locator, options)
STDERR.puts "found: #{btn.inspect}"
btn.click
use bundle show capybara to find out where it is, edit the find (or click) method and put in STDERR.puts methods there to see what's wrong

Cucumber vs Rspec what to use to check user permissions

I'm using devise and cancan to ensure protection to some areas of my website.
What tool is best to check that a user with a role can access and another role cannot?
Actually I'm creating several cucumber features to make sure a user with admin role can see the page and all other roles cannot (receiving an error message). Is there a better way to do that?
I've read a lot about when to use cucumber over rspec and when user rspec over cucumber, and the general idea I got is that I should say with cucumber "the user says this" and with rspec make sure that under the hood all is working properly... by the way it's hard to apply this general concept at work, and to be honest I find it to be a waste of time. If I can check the final page is what is expected why should I test, for example, for controllers? I find it only worth it to test for model validations and model functions.
Any suggestion? Possibly something more practical than the RSpec book since I have to apply concepts asap.
Expanding from the comments.
Based on https://github.com/ryanb/cancan/wiki/Testing-Abilities I do the following to test.
Inside my Administrator spec .
require 'spec_helper'
require 'cancan/matchers'
describe Administrator do
describe "abilities" do
subject { ability }
let(:ability) { Ability.new(admin) }
let(:account) { FactoryGirl.create :account, isp: admin.isp }
context "is a helpdesk admin" do
let(:admin) { FactoryGirl.create :helpdesk_admin }
let(:mail_user) {FactoryGirl.create :mail_user, account: account}
let(:web_user) {FactoryGirl.create :web_user, account: account }
let(:radius_user) { FactoryGirl.create :radius_user, account: account}
it { should be_able_to(:change_password,mail_user)}
it { should be_able_to(:change_password,radius_user)}
it { should be_able_to(:change_password,web_user)}
it { should_not be_able_to(:manage, Account.new) }
end
context "is a realm admin" do
let(:admin) { FactoryGirl.create :realm_admin }
it{ should be_able_to(:manage, MailDomain.new)}
it{ should be_able_to(:manage, RadiusDomain.new)}
it{ should be_able_to(:manage, WebDomain.new)}
it{ should be_able_to(:manage, Administrator.new)}
end
end
This lets me test the abilities that Each Role has assigned
Then inside my features/ I do something like this for each controller, to make sure that I don't forget an authorize.
context "regular admin" do
let(:admin) {FactoryGirl.create(:admin)}
before(:each) do
visit login_path
fill_in "email" , with: admin.email
fill_in "password", with: admin.password
click_button "Sign in"
end
it "shoudln't allow them to add new admins" do
visit new_administrator_path
page.should have_content "You are not authorized to access this page."
end
end
Cucumber is better for business case testing e.g. Bill can't edit Ben's profile. RSpec may be better for more exhaustive analysis, though one would hope you can trust that both Devise and CanCan have done this for you.
I have a sample project that shows some interesting ways of using Cucumber to do work with authentication so you can write very simple features. It would not take much to extend these ideas to usage with roles. Hope its of some use
see here

How do I re-use Capybara sessions between tests?

I want to keep on using the same session and by that I mean Rails' session between various Test::Unit integration tests that use Capybara. The Capybara::Session object is the same in all the tests as it is re-used, but when I access another page in another test, I'm immediately logged out.
Digging in I found that capybara_session.driver.browser.manage.all_cookies is cleared between one test and the next.
Any ideas how? or why? or how to avoid it?
Trying to work-around that, I saved the cookie in a class variable and re-added later by running:
capybara_session.driver.browser.manage.add_cookie(##cookie)
and it seems to work, the cookie is there, but when there's a request, the cookie gets replaced for another one, so it had no effect.
Is there any other way of achieving this?
Add the following after your capybara code that interacts with the page:
Capybara.current_session.instance_variable_set(:#touched, false)
or
page.instance_variable_set(:#touched, false)
If that doesn't work, these might help:
https://github.com/railsware/rack_session_access
http://collectiveidea.com/blog/archives/2012/01/05/capybara-cucumber-and-how-the-cookie-crumbles/
If what you are doing is trying to string together individual examples into a story (cucumber style, but without cucumber), you can use a gem called rspec-steps to accomplish this. For example, normally this won't work:
describe "logging in" do
it "when I visit the sign-in page" do
visit "/login"
end
it "and I fill in my registration info and click submit" do
fill_in :username, :with => 'Foo'
fill_in :password, :with => 'foobar'
click_on "Submit"
end
it "should show a successful login" do
page.should have_content("Successfully logged in")
end
end
Because rspec rolls back all of its instance variables, sessions, cookies, etc.
If you install rspec-steps (note: currently not compatible with rspec newer than 2.9), you can replace 'describe' with 'steps' and Rspec and capybara will preserve state between the examples, allowing you to build a longer story, e.g.:
steps "logging in" do
it "when I visit the sign-in page" #... etc.
it "and I fill in" # ... etc.
it "should show a successful" # ... etc.
end
You can prevent the call to #browser.manage.delete_all_cookies that happens between tests by monkey patching the Capybara::Selenium::Driver#reset! method. It's not a clean way of doing it, but it should work...
Add the following code to your project so that it is executed after you require 'capybara':
class Capybara::Selenium::Driver < Capybara::Driver::Base
def reset!
# Use instance variable directly so we avoid starting the browser just to reset the session
if #browser
begin
##browser.manage.delete_all_cookies <= cookie deletion is commented out!
rescue Selenium::WebDriver::Error::UnhandledError => e
# delete_all_cookies fails when we've previously gone
# to about:blank, so we rescue this error and do nothing
# instead.
end
#browser.navigate.to('about:blank')
end
end
end
For interest's sake, the offending line can be seen in Capybara's codebase here: https://github.com/jnicklas/capybara/blob/master/lib/capybara/selenium/driver.rb#L71
It may be worth posting the reason why you need this kind of behaviour. Usually, having the need to monkey patch Capybara, is an indication that you are attempting to use it for something it was not intended for. It is often possible to restructure the tests, so that you don't need the cookies persisted across integration tests.

How do I test the actions that require the user to be logged in?

I am trying to test my controllers, but some of the actions in my controller expect the user to be logged in. How will I test them? Do I mess with the session variable directly? Also, what if a lot of the actions expect the user to be logged in? Should I set up a before action, and log the user in there?
Another idea I had was that I could test them in an integration test, and do a post on the login form, before I actually test the desired action. Something like:
def setup
# log the user in, this will happen before every test
end
# integration test
test "I should see my posts" do
#setup should have happened before this, and I should be logged in
get posts_path
assert ...
end
Is this the way to test these actions? Am I missing something?
Depending on your authentication framework you use there are several ways. Devise for example has some TestHelpers, that make it easy to login users without having go through the actual webpage in functional tests. If thats not an option, like soundsop said, browser testing. (look at, from high to low: cucumber, capybara, selenium/...)
The Book includes some testing examples in their depot application:
test "should login" do
dave = users(:one)
post :create, :name => dave.name, :password => 'secret'
assert_redirected_to admin_url
assert_equal dave.id, session[:user_id]
end
Full details in the "Authenticating Users" section.
You can either make fake user credentials in the setup, or you can stub out the method which checks the credentials using a mocking library. I've done both and don't have a firm preference.

Resources