I'm trying to use capybara on a ruby on rails application to do some content testing, as well I'm using the devise gem to implement user authentication. I'm having trouble logging into my application to perform my test cases.
Initially, my scenario was as follows:
scenario "User arrives at main page" do
visit "purchase_orders#index"
page.should have_content("All")
# some more tests and checks
end
Where purchase_orders#index is the authenticated root, where a user's purchase orders are shown.
But when I was running the tests, I was getting the following error :
expected to find text "All" in "Log in to manage your orders * Email * Password Forgot your password? Remember me Sign up • Didn't receive confirmation instructions? About Us • Contact Us •
which tells me that its not getting past the log in page. I next tried adding the following to my scenario, before running the tests, to make it log in:
visit "purchase_orders#index"
fill_in('Email', :with => 'username#gmail.com')
fill_in('Password', :with => 'password')
click_button('Log in')
where username and password are actual created accounts, but again it fails and doesn't get past the sign in page. Finally, I tried adding a before(:each) method, as follows, to attempt to sign users in for test cases:
before(:each) do
visit "users/sessions#new"
fill_in('Email', :with => 'nico.dubus17#gmail.com')
fill_in('Password', :with => 'password')
click_button('Log in')
end
which, again, did not work for me. So my question is: What is the best practice and syntax for getting past the sign in page, and into the actual application? I've looked for documentation and answers on this, but haven't found anything.
Thank you!
Found an answer. I installed the warden gem to (gem 'warden') and factory girl gem (gem "factory_girl_rails", "~> 4.0") and ran a bundle install. I then created a user fixture with factory girl as follows in a factory.rb file in the spec folder:
# This is a user factory, to simulate a user object
FactoryGirl.define do
factory :user, class: User do
first_name "John"
last_name "Doe"
email "nico_dubus#hotmail.com"
encrypted_password "password"
end
end
in my rails helper file, I added this line to be able to use FactoryGirl's methods without calling it on the class every time:
config.include FactoryGirl::Syntax::Methods
Afterwards, I added these lines to the top of my capybara test page:
include Warden::Test::Helpers
Warden.test_mode!
Finally, I built a user object to use within the scope of the test:
user = FactoryGirl.build(:user)
And whenever I need to log in, I use warden's log in method
login_as(user, :scope => :user)
And voila!
Related
I am trying to create test to admin panel. But it fails while the program try to log_in.
Failures:
1) Visit products login works correctly
Failure/Error: expect(page).to have_content("Logged in successfully")
expected to find text "Logged in successfully" in "Login\nAll departments\nHome\nCart: (Empty)\n \nInvalid email or
password.\nLogin as Existing Customer\nRemember me\nor Create a new
account | Forgot Password?"
# ./spec/features/home_spec.rb:14:in `block (2 levels) in '
The password, and the email are correct for admin. I found solutions in other posts, like adding configuration to capybara, but it still fails.
spec_helper
require 'capybara/rspec'
require 'rails_helper'
require 'spree/testing_support/controller_requests'
require 'capybara/rails'
Capybara.app_host = "http://localhost:3000"
Capybara.server_host = "localhost"
Capybara.server_port = "3000"
_spec.rb
require "spec_helper"
RSpec.describe 'Visit products' do
it 'login works correctly' do
visit spree.admin_path
fill_in "spree_user[email]", with: "piotr.wydrzycki#yahoo.com"
fill_in "spree_user[password]", with: "password"
click_button Spree.t(:login)
expect(page).to have_content("Logged in successfully")
end
end
Since the page is showing "Invalid email or password" either the email or password aren't correct, or the user for the test isn't being created correctly. Since you don't show the creation of any test users in your test it's most likely there aren't any. When running in test mode the app doesn't use your development database, it has its own database and you need to create all the objects (like users) you expect to exist for the test. You can do this by using fixtures or something like factory_bot to create users before each test.
Additionally, there should be no need to set server_host,server_port, or app_host in your situation.
I am using Machinist to create my test users which I want to log in before each test which I am running with Capybara:
include Capybara::DSL
include ActionController::UrlWriter
before do
SslRequirement.disable_ssl_check = true
user = User.make
visit new_user_session_path
fill_in('username', with: user.email)
fill_in('password', with: '12345')
click_button('submit')
end
it "responds as expected" do
# ...
end
Now when the user is created with User.make I can access it through User.all when it fact it's not persisted in the database yet, this is because
ActiveRecord::Base.connection.open_transactions == 1
I can fix/hack this by doing a
ActiveRecord::Base.connection.commit_db_transaction
after User.make, but I'd rather fix this properly. Is this a Capybara configuration which I am missing? Disclaimer: Using Rails 2.3 and RSpec 1.3
You don't show which driver you're using with Capybara, but generally you shouldn't be using transactions for testing when using Capybara (yes there are potential workarounds to allow it but they all have side-effects). See transactions and database setup and then look into the database_cleaner gem with truncation - here's a blog post about it that should be good with the age of gems you're using - http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
I am following railscast #275 with testing the forgot me password. I am having troubles getting past the email has already been taken error. With the coding I have by following the tutorial I am suppose to receive this error, "error for no link with title or text "password". Instead this is what I am getting, "Validation failed: Email has already been taken (ActiveRecord::RecordInvalid)"
I have done a search, unable to find a solution for it.
Here's password_resets_spec.rb:
require 'spec_helper'
describe "PasswordResets" do
it "emails user when requesting password reset"
user = FactoryGirl.create(:user)
visit login_path
click_link "password"
fill_in "Email", :with => user.email
click_button "Reset Password"
end
factories.rb:
FactoryGirl.define do
factory :user do
sequence :email do |n| "test#{n}#example.com"
end
password "secret"
end
end
Here's what I did when I finally notice it started to work. I installed database cleaner. Then I did the commands:
rake db:reset
rake db:migrate
rake db:test:prepare
Following that I noticed I had to add a "do" to the end of " it "emails user when requesting password reset".
Now I have no errors and I can continue in my testing adventure. Thanks to those who tried to assist.
The factory definition seems OK.
I would start by making sure that your test database is empty before running the spec. There may be an existing user record "test1#example.com" lingering. Also, have you tried to run only that example? Does it make any difference?
Looks like while running your test cases the factory that was created didn't rolled back/deleted the record.
add a before(:each) deletes previous records before the example executes
before(:each) do
User.delete_all
end
Solution
This worked. The main essence is that I have to set the Capybara.server_port and Capybara.app_host and sign in manually in the sign in form. Capybara.app_host cannot be set with a dynamic subdomain unless its declared in a variable. All urls has to be hard coded.
require 'spec_helper'
feature 'customer' do
let(:user) {FactoryGirl.create(:user)}
let(:firm) {user.firm}
let(:customers) {"http://#{firm.subdomain}.lvh.me:31234/customers"}
let(:root_url) {"http://#{firm.subdomain}.lvh.me:31234/"}
before(:all) do
Capybara.server_port = 31234
sub = firm.subdomain
Capybara.app_host = root_url
end
def sign_in_on_js
visit root_url
fill_in "Email", :with => user.email
fill_in "Password", :with => "password"
click_button "Sign in"
page.should have_content("Signed in successfully.")
end
scenario "make new", js: true do
sign_in_on_js
visit customers
page.should have_content("Add new customer")
find("#dialog_customer").click
page.should have_content("Create new customer")
end
end
Original question
I am making a multitenant app in rails. There is going to be a lot of javascript. But, I cant get the testing to work.
When not running :js = true every thing works. The problem arises in specs like this one
let(:customers) {"http://#{firm.subdomain}.lvh.me:3003/customers"}
scenario "Statistics select", :js => true do
visit customers
page.should have_content("Add new customer")
end
The poltergeist web driver for capybara cannot find the url and returns a blank page
Failure/Error: page.should have_content("Add new customer")
expected there to be text "Add new customer" in ""
I have this in my spec_helper.rb
require 'capybara/rspec'
require 'capybara/poltergeist'
Capybara.javascript_driver = :poltergeist
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, :debug => true)
end
Poltergeist and phantomjs try to deliver. I get this output
{"name"=>"set_debug", "args"=>[true]}
{"response"=>true}
{"name"=>"visit", "args"=>["http://subdomain2.lvh.me:3003/statistics"]}
poltergeist [1362522132943] state default -> loading
{"response"=>{"status"=>"fail"}}
Do I need to have a server running during testing to make this work?
I've tried selenium and capybara-webkit, but phantomjs has gotten closest to success.
I have also tried to change the hosts file in different ways( maybe not correct )
Any tips on setup are welcome!
Update
Starting to get desperate. I now start the rails server
rails s -e test -p 3001
and then run my tests.
Now I get redirected to the sign in page. I have this in the specs
before(:each) do
login_as(user, :scope => :user)
end
How can I sign in the test user on the rails test server without going trough the sign in process manually for every spec
Capybara already starts a server for you, to quote the docs:
Some Capybara drivers need to run against an actual HTTP server. Capybara takes care of this and starts one for you in the same process as your test, but on another thread. Selenium is one of those drivers, whereas RackTest is not.
Within your test you can use the visit method with a relative url, for example:
visit("/statistics")
Capybara will direct this request to the server it just started for this test.
When your want to use an absolute url within your test, you can, but you should also specify the port the server is running on. This port is being randomly chosen during the test. Some drivers have a method available to retrieve the port number.
For example when you use the Capybara-Webkit driver:
Capybara.current_session.driver.server_port
To visit an absolute url you can then use:
port_number = Capybara.current_session.driver.server_port
visit("http://127.0.0.1:#{port_number}/statistics")
Within the test specs probably a method login_as won't work. You have to log in with a few simple steps. For example:
before(:each) do
visit "/login"
fill_in "Email", :with => "my#email.com"
fill_in "Password", :with => "secret"
click_button "Login"
end
To test multiple subdomains you can set the Capybara.app_host. Take a look at this question for a detailed explanation.
UPDATE
Capybara 2 includes a nice feature called always_include_port which will automatically add the port number the server is running on.
Capybara.always_include_port = true
So instead of
visit("http://127.0.0.1:#{port_number}/statistics")
you can now use
visit("/statistics")
and it will automatically connect to http://127.0.0.1:#{port_number}/statistics.
If you want to test multiple subdomains with Capybara.app_host, you could use a domain name which always resolves to 127.0.0.1 for example lvh.me.
For example, if you specify Capybara.app_host = "http://example.lvh.me" it will run the tests using the example subdomain.
I have the following steps in a capybara/rspec integration test, that is simply trying to sign up a new member.
visit new_member_registration_path
fill_in('Name:', :with => 'Rob Doe' )
fill_in('member_email', :with => 'rob#smith.com' )
fill_in('member_email_confirmation', :with => 'rob#smith.com' )
fill_in('member_password', :with => 'secret')
fill_in('Company or Venue Name:', :with => 'Rob Inc.')
fill_in('Contact Number:', :with => '040544404440')
click_button('Sign up')
save_and_open_page
For some reason the 'email' and 'password' data is not being passed to the DeviseRegistrations controller (it is blank when viewing the test log) and therefore causing the validation to fail. However up until the save_and_open_page there is no rspec errors (so those fields are being filled in).
What am I missing? Do I need to subclass the DeviseRegistrations controller?
Tested on Rails 3.0.7 with rack-test 0.5.7 and rails 3.1rc1 and rack-test 0.6.0
Assuming you have debugger in your Gemfile, here's how you can use it. (This assumes you're using the Rack driver for Capybara.)
# test.rb
visit new_member_registration_path
fill_in('Name:', :with => 'Rob Doe' )
debugger
The terminal will stop your script and wait for you to do something.
# Terminal
/file/path/to/you/test.rb:12
fill_in('Name:', :with => 'Rob Doe' )
(rdb:1)
Open up an IRB session here:
(rdb:1) irb
You can do any RSpec or Capybara method here:
>> current_path.should == 'foo/bar'
Try submitting the form at this point:
>> click_button "Sign Up"
>> save_and_open_page
See what error messages Devise gave to you on the resulting page. With the Rack driver, you won't see the fields being filled in. In that case, you might want to try using the Selenium driver
# test.rb
Capybara.default_driver = :selenium
visit new_member_registration_path
However, you can't drive Capybara from IRB using the Selenium driver. You will, though, be able to see what form values Selenium is putting into your form. Since things happen quickly with Selenium, you can use debugger to pause the test, while you inspect the page that Selenium opened up in your browser.
The problem was in the application layout file. I had another (albeit hidden) form that was posting the blank form fields.
After I created a blank project and saw that it worked perfectly, I peeled back all the potential parts of my app until I found the culprit.
So the answer to the question is, no, a custom devise controller is not required when you are using custom devise views.