In our integration test for rails 3.2.12 app, there is a test case to open the create new user page which only admin has the right to do. Here is our rspec case (with capybara) which passes:
it "should have login field in create new user page" do
ul = FactoryGirl.build(:user_level, :position => 'admin')
#user = FactoryGirl.create(:user, :login => 'test12', :password => 'password', :password_confirmation => 'password', :user_levels => [ul])
visit '/'
fill_in "login", :with => #user.login
fill_in "password", :with => 'password'
click_button 'Login'
visit new_user_path
page.body.should have_content("New User")
end
The user position "admin" is defined in user_levels which belongs to a user. What the rspec case above does is to log in and open the create new user page.
In user controller, there is a before_filter to check if the user is admin:
before_filter :require_admin
The odd thing is that if we assign non-admin position to the user in rspec case above, the case still passes. It seems that the before_filter require_admin fails to stop a non-admin user open the create new user page in integration test.
What could be wrong with the rpsec code above? Thanks for help.
Related
Ok, I'm using has_secure_password in my User model to automatically fill in the :password_digest field in my model.
I'd like to simulate a login in my test_account_page.rb integration test below, so that I can confirm that a logged in user can access the page at account_path.
test "a logged in user can access their account page" do
#user = FactoryGirl.create(:user)
# Sign in first
visit signin_path
fill_in 'email', with: #user.email
fill_in 'password', with #user.password # <!-- this won't work
click_button 'Login'
# Then visit account page
...
end
This won't work because #user.password does not give us the password in plain text form (the whole idea of using has_secure_password in the first place is to make the original password unrecoverable).
So how do I test a page hidden behind the login screen when using has_secure_password?
Try to use user attributes like this:
test "a logged in user can access their account page" do
#user = FactoryGirl.create(:user)
#user_attrs = FactoryGirl.attributes_for(:user)
# Sign in first
visit signin_path
fill_in 'email', with: #user_attrs.email
fill_in 'password', with #user_attrs.password
click_button 'Login'
# Then visit account page
...
end
I'm super new to testing, so I'm not really sure what I should be debugging here.
That said, I have two different user types: Authors and Readers, subclassed on Users.
They can both sign up fine in my app, and the tests for Readers works without any problems.
The signup form for Authors includes a stripe payment form - and makes a remote call to Stripe's API before submitting the form.
Here is what the test looks like:
require 'spec_helper'
feature 'Author sign up' do
scenario 'author can see signup form' do
visit root_path
expect(page).to have_css 'form#new_author'
end
scenario 'user signs up and is logged in' do
visit root_path
fill_in 'author[email]', :with => 'author#example.com'
fill_in 'author[password]', :with => '123456'
fill_in 'author[password_confirmation]', :with => '123456'
fill_in 'author[name]', :with => 'joe shmoe'
fill_in 'author[zipcode]', :with => '02021'
fill_in 'card_number', :with => '4242424242424242'
fill_in 'card_code', :with => '123'
select "1 - January", :from => 'card_month'
select "2014", :from => 'card_year'
find('.author_signup_button').click
expect(page).to have_css '.author_menu'
end
end
The only difference between this test and the Reader test are the credit card forms.
The controller which handles this account creation looks like this:
def create
#author = Author.new(params[:author])
if #author.save_with_payment
sign_in #author, :event => :authentication
redirect_to root_path, :notice => "Thanks for signing up!"
else
render :nothing => true
end
end
If I don't have the else in here, the test fails sooner, saying its missing templates. Which means its not passing the "save_with_payment" method, which supports the idea that the form never hits stripe.
The error simply says:
**Failure/Error: expect(page).to have_css '.author_menu'
expected css ".author_menu' to return something**
This worked before I integrated with stripe - so I'm convinced it has to do with the ajax call.
Is there something I should be doing to support ajax?
The answer, was to use :js => true in the test:
scenario 'user signs up and is logged in', :js => true do
This forces the test to run with selenium, and uses the browser.
I run across problems when I execute the cucumber tests on devise.
The tests that are failing are just the default ones provided when you install devise (I just modified some words for "sign in" that became "login" on my website but I don't think it's the reason of the problem).
As I'm a beginner, I don't understand what is even wrong or what cucumber is telling me. Why is it mentioning rspec here? should I add the rspec-expectations gem ?
The error I get on my console when I run cucumber:
Scenario: User signs in successfully # features/users/sign_in.feature:12
Given I exist as a user # features/step_definitions/user_steps.rb:58
And I am not logged in # features/step_definitions/user_steps.rb:49
When I sign in with valid credentials # features/step_definitions/user_steps.rb:72
Then I see a successful sign in message # features/step_definitions/user_steps.rb:152
expected to find text "Signed in successfully." in "Mywebsite Follow us How it works More Login × Invalid email or password. Login * Email Password Remember me Not a member yet? Sign Up Now!Forgot your password?Didn't receive confirmation instructions? Rails Tutorial About Contact Help" (RSpec::Expectations::ExpectationNotMetError)
./features/step_definitions/user_steps.rb:153:in `/^I see a successful sign in message$/'
features/users/sign_in.feature:16:in `Then I see a successful sign in message'
When I return to the site # features/step_definitions/user_steps.rb:110
Then I should be signed in # features/step_definitions/user_steps.rb:136
The files the error is refering to:
/features/step_definitions/user_steps.rb
### UTILITY METHODS ###
def create_visitor
#visitor ||= { :name => "xxx", :email => "xxx#gmail.com",
:password => "xxx", :password_confirmation => "xxx" }
end
def find_user
#user ||= User.first conditions: {:email => #visitor[:email]}
end
def create_unconfirmed_user
create_visitor
delete_user
sign_up
visit '/users/sign_out'
end
def create_user
create_visitor
delete_user
#user = FactoryGirl.create(:user, email: #visitor[:email])
end
def delete_user
#user ||= User.first conditions: {:email => #visitor[:email]}
#user.destroy unless #user.nil?
end
def sign_up
delete_user
visit '/users/sign_up'
fill_in "Name", :with => #visitor[:name]
fill_in "Email", :with => #visitor[:email]
fill_in "user_password", :with => #visitor[:password]
fill_in "user_password_confirmation", :with => #visitor[:password_confirmation]
click_button "Sign up"
find_user
end
def sign_in
visit '/users/sign_in'
fill_in "Email", :with => #visitor[:email]
fill_in "Password", :with => #visitor[:password]
click_button "Login"
end
(....) and more below:
Then /^I see a successful sign in message$/ do
page.should have_content "Signed in successfully."
end
and /features/users/sign_in.feature
Scenario: User signs in successfully
Given I exist as a user
And I am not logged in
When I sign in with valid credentials
Then I see a successful sign in message
When I return to the site
Then I should be signed in
When i manually go on my website, it does display "Signed in successfully." when I sign in so what's the problem? I really don't understand.
Add the following step to debug:
Then /^show me the page$/ do
save_and_open_page
end
And add show me the page to the feature:
Given I exist as a user
And I am not logged in
When I sign in with valid credentials
Then show me the page
And I see a successful sign in message
It will help you to debug the error.
Put this into spec_helper, or support/devise.rb
config.include Devise::TestHelpers, :type => [:feature, :controller]
I've got a problem with my controller tests for my Courses Controller. It seems that devise is not signing in my user correctly. All the generated controller tests for this controller only are failing.
I create my user in users.rb using Factory-girl as per below...
FactoryGirl.define do
factory :user do
sequence :email do |n|
"test#{n}#email.com"
end
password "password"
password_confirmation "password"
end
end
Then in my courses_controller_spec.rb I simulate the login as per below..
require 'spec_helper'
describe CoursesController do
include Devise::TestHelpers
before(:each) do
##request.env["devise.mapping"] = Devise.mappings[:user]
user = Factory.create(:user)
user.toggle!(:admin)
sign_in user
end
describe "DELETE destroy" do
it "redirects to the courses list" do
course = Factory.create(:course)
delete :destroy, {:id => course.to_param}, valid_session
response.should redirect_to(courses_url)
end
end
And I get the output...
Failure/Error: response.should redirect_to(courses_url)
Expected response to be a redirect to <http://test.host/courses> but was a redirect to <http://test.host/users/sign_in>
Please note I've also used the following in my spec_helper.rb
config.include Devise::TestHelpers, :type => :controller
And I've tried it as per https://github.com/plataformatec/devise/wiki/How-To:-Controllers-and-Views-tests-with-Rails-3-%28and-rspec%29
In my request specs I can create the user and login using the below which works fine but I'd like to get all the controller tests working also
fill_in "Email", :with => user.email
fill_in "Password", :with => user.password
click_button "Sign in"
Any help here would be much appreciated.
I just figured this out myself. Remove the valid_session from your delete call. That seems to overwrite the session defined using the devise test helpers.
Everything else seems correct. Keep all the devise setup code and just change the delete line in your spec to:
delete :destroy, {:id => course.to_param}
I also kept in the following line in my before( :each ) block, which you commented out. Not sure what it does yet:
#request.env["devise.mapping"] = Devise.mappings[:user]
I'm new to Cucumber and totally lost as to why this integration test is failing. I have the following scenarios:
Scenario: User changes profile
Given I have an account
When I change my profile
Then my profile should be saved
Scenario: User changes login
Given I have an account
When I change my login information
Then my account should be changed
And these step definitions:
Given /^I have an account$/ do
#user = Factory.create(:user)
visit login_path
fill_in "Email", :with => #user.email
fill_in "Password", :with => 'secret'
click_button "Sign in"
end
When /^I change my profile$/ do
visit edit_user_profile_path(#user)
fill_in "First name", :with => "John"
fill_in "Last name", :with => "Doe"
click_button "Update Profile"
end
Then /^my profile should be saved$/ do
#user.profile.first_name.should == "John"
#user.profile.last_name.should == "Doe"
end
When /^I change my login information$/ do
visit edit_user_path(#user)
fill_in "Email", :with => "foo#example.com"
click_button "Update Login Information"
end
Then /^my account should be changed$/ do
#user.email.should == "foo#example.com"
end
And I fail the "Then" condition on both scenarios with this message:
# Scenario 1
expected: "John"
got: "Test1" (using ==) (RSpec::Expectations::ExpectationNotMetError)
# Scenario 1
expected: "foo#example.com"
got: "test2#example.com" (using ==) (RSpec::Expectations::ExpectationNotMetError)
So, in both cases the factory information is still present after submitting the form to update the user login or profile. However, if I test this in a real browser it works perfectly. So, why is this test failing???
Thanks for the help!
#user is just a variable which lives inside your cucumber code block. It will not be changed. What will be changed in the test is the database record. To check that it was changed indeed you have to visit some page where user name is displayed.
(Just as you do in your real life test)