I'm trying to test the order process in a request spec by filling out the purchase form:
describe "CC order" do
before do
visit order_path "product"
fill_in "full_name", with: "test name"
fill_in "email", with: "test#email.com"
fill_in "card_number", with: "4242424242424242"
fill_in "card_cvc", with: "123"
# etc...
click_on "complete-button"
end
it "should display confirmation message" do
page.should have_content "Thanks for your order!"
end
end
A new User and Order should be saved after the purchase form is submitted and does so correctly in development. However, my test fails because instead of processing the order it tells me that the database is locked:
I do have transactional fixtures turned on and some of my other tests use them. Is there another way I should be testing my order process?
EDIT: It seems like it open happens when I use page in the it block. If I just make the test block empty, everything works fine.
I was running out of ideas so I switched from sqlite to postgresql in development + test. That fixed the problem.
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 have this integration test for my Rails App:
require 'test_helper'
class StudyCapybaraTest < ActionDispatch::IntegrationTest
def setup
#user = users(:archer)
#vocabs = #user.vocabs
Capybara.register_driver :selenium_chrome do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
Capybara.current_driver = :selenium_chrome
#Capybara.default_wait_time = 5
visit login_path
fill_in "session_email", with: #user.email
fill_in "session_password", with: 'password'
click_button "session_commit"
end
test "full study process" do
assert_title "Home | Word Up"
visit study_user_path(#user)
....
end
end
Weirdly, when I remove the first line of the first test "full study process"
assert_title "Home | Word Up"
the test fails because the test user doesn't seem to be logged in. The same problem occurs when I move
visit study_user_path(#user)
into the setup function (as it was before).
But that doesn't change anything about the sequence and logic, right?
The only thing I can think of, is that the assertion comes to early, and the
app doesn't have time to execute the instructions needed to meet the assertions.
Is this a timing issue, and if so, how can I prevent them from happening in the future? Thx!
First, your intuition on it being a timing issue is correct. click_button does just that - it clicks the button. It doesn't wait for a form to post, it doesn't wait for any ajax to occur, etc. So without the assert_title your test is clicking the button, and immediately changing the url in the browser. The changing the url in the browser would have the effect of canceling any form submission or behavior that was triggered by the click_button call. You need to wait after the click_button for something that changes on the page as a result of clicking the button, along the lines of
assert_text('You are now logged in')
Secondly, the setup method is run before each test so you really don't want to be registering the driver in there, since it only needs to be done once.
I have several non-javascript specs that use the ui to create and edit records.
When I run these specs the test database records are automatically removed for me by the rspec teardown for each test.
However the test below which is the first one to have :js => true for some ajax stuff isn't doing tear down of the records afterwards and then tests start to break because the database is no longer empty correctly when they start. The link and the group rows still exist in the test database.
# spec/features/verifying_link_spec.rb
require 'spec_helper'
describe "verification", :js => true, :type => :feature do
before :all do
User.create(:username => 'r#google.com', :password => 'esceptio')
end
before :each do
visit '/ladmin/login'
fill_in 'username', :with => 'r#google.com'
fill_in 'password', :with => 'esceptio'
find('input[value="Login"]').click
end
it "lets me verify a link" do
find('div#side div a', text: 'New Group').click
fill_in 'group[group_name]', with: 'Group Add'
click_button 'Save'
find('div#side div a', text: 'New Link').click
fill_in 'link[url_address]', with: 'http://www.a.com/newtest9876link'
fill_in 'link[alt_text]', with: 'abcd9876'
click_button 'Save'
this_year=Time.now.strftime('%Y')
l=Link.first
l.update_attribute(:verified_date, nil)
expect(Link.count).to eq 1
visit links_path
find('a', text: "verify")
click_link("verify", match: :first)
sleep(3)
expect(page).to have_content(this_year)
end
end
Right now I am using a workaround solution of using the ui to delete the records (below) but this should not be necessary
# added at bottom of spec
click_link('Details')
click_link('Delete')
page.driver.browser.switch_to.alert.accept
click_link('Groups')
click_link('Delete')
page.driver.browser.switch_to.alert.accept
None of my other unit tests or feature tests (except this one with js) have this problem. They all create records that get removed automatically.
I highly recommend using the database_cleaner gem to clean your database out between tests. Rspec wraps everything in a transaction and rolling it back once the example is finished. However, when you start using javascript you might be saving the data outside of the rspec transaction and then the database never reverts to its original state.
Truncation is slower than the transaction strategy. However you may only need the truncation strategy with JS tests. You could follow this guide to setup the database cleaner gem in that manner: http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/
If you find your tests taking eons, you might want to investigate some time looking at a gem that preloads your environment. I highly recommend zeus
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.