Log in test fails with RSpec / Capybara / Poltergeist - ruby-on-rails

I'm writing test code for Rails application with React.
I'm using RSpec, Capybara, Poltergeist(PhantomJS 2.0) and Devise for authentication.
Because this is a javascript test, I'm also using database_cleaner gem as suggested here.
When test runs I can see user data goes into database(mysql) and Devise method user.valid_password?("password") returns true, however, test fails.
spec_helper.rb
RSpec.configure do |config|
config.use_transactional_fixtures = false
Capybara.register_driver :poltergeist do |app|
options = {
inspector: true,
js_errors: false,
#debug: true,
phantomjs_options: %w[
--web-security=no
--ignore-ssl-errors=yes
--ssl-protocol=any
]
}
Capybara::Poltergeist::Driver.new(app, options)
end
Capybara.javascript_driver = :poltergeist
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
The spec looks like this.
require 'spec_helper'
feature 'Registration', js: true do
let!(:email) { "email#test.com" }
scenario "user can sign up and log in" do
visit 'sign_up'
find('input').set(email)
find('.submit').click
expect(page).to have_content('welcome!')
visit '/sign_out'
visit '/sign_in'
expect(page).to have_content('Login')
find('input[name="email"]').set(email)
find('input[name="password"]').set('password')
find('.submit').click
wait_for_ajax
expect(page).to have_content('Test User')
end
end
API looks like this.
post do
email = params[:email]
password = params[:password]
if email.nil? or password.nil?
return error!(['this is error'], 401)
end
user = User.where(email: email.downcase).first
if user.nil?
return error!(['this is error'], 401)
end
if !user.valid_password?(password)
return error!(['this is error'], 401)
else
user.ensure_authentication_token
user.save
return { status: 'ok', results: { access_token: user.authentication_token } }
end
end
I get log like below with PhantomJS 2.0.
API.ajax:POST /sessions
API.ajax:POST /sessions
API.ajax:POST /sessions :failed
httpStatus:401
error
[object Object]
API.ajax:POST /sessions :failed
httpStatus:401
error
[object Object]
So something went wrong in authentication process but it only happens when I run test. (I can sign up and log in with Chrome or Firefox.)
Appreciate any idea.
Thanks!

It turned out some functionality refers HARD CODED port 3000 when I run test..
rspec - Running rails server changes test result? - Stack Overflow
I don't know why it's built like that but at least for now I can run my test by adding Capybara setting:
Capybara.server_port = 3000
Thanks!

Related

rspec test fails to enable javascript

I have the next test with rspec and selenium:
require 'rails_helper'
feature "Creating an student" do
context "When an student visit the sign_up page" do
scenario "Should be able to create an student" do
state = FactoryGirl.create(:state)
city = FactoryGirl.create(:city, state: state)
institution = FactoryGirl.create(:institution)
visit root_path
.........
The devise function to register is this:
def new
#institutions = Institution.all.order(:name)
#states = State.all
#cities = City.all
super
end
when I search in my controller the States and Cities, I found this, but when I enable javascript
scenario "Should be able to create an student", js: true do
the States and Cities return nil.
Update 1
My spec_helper file is this:
require 'database_cleaner'
require 'capybara'
Capybara.register_driver :chrome do |app|
Capybara::Selenium::Driver.new(app, :browser => :chrome)
end
Capybara.javascript_driver = :chrome
Capybara.default_max_wait_time = 10
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
DatabaseCleaner.strategy = :transaction
end⋅
config.before(:each) do
DatabaseCleaner.start
end⋅
config.after(:each) do
DatabaseCleaner.clean
end⋅
end
I do not know why this happens.

Capybara and poltergeist test failing

I been using :firefox drivers for capyabara and this test was passing but when I switch to poltergeist driver the test been failing now with the following error:
Minitest::UnexpectedError: Capybara::ElementNotFound: Unable to find field "email"
Here is the capybara and poltergeist setup:
def setup
# FactoryGirl.lint
DatabaseCleaner.strategy = :truncation
DatabaseCleaner.start
Capybara.run_server = true
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, :js_errors => false)
end
Capybara.default_driver = :poltergeist
Capybara.current_driver = :poltergeist
Capybara.javascript_driver = :poltergeist
Capybara.app_host = 'http://localhost:4200'
Capybara.server_port = 3000
Capybara.default_max_wait_time = 5
end
Here is the test:
test "User should be able to signin" do
visit '/'
wait_for_ajax
fill_in 'email', with: #user.email
fill_in 'password', with: #user.password
assert true
end
So, when I changed the driver to :selenium the test pass with no error.
How do I setup/fix poltergeist to pass this test?
I took screenshot and it shows loading indicator which is a div that is removed in afterModel Ember hook using the following code:
_ember['default'].$('.ember-load-indicator').remove();
For Ajax calls we have the following function as test helper to wait for ajax calls:
def wait_for_ajax
Timeout.timeout(Capybara.default_wait_time) do
loop until finished_all_ajax_requests?
end
end
def finished_all_ajax_requests?
page.evaluate_script('jQuery.active').zero?
end
I suspect it's a timing issue... When using poltergeist vs a browser, you can get these weird behaviours, where an element is present, but not really loaded hence the error... An easy way to confirm this is by putting a sleep prior to fill_in email... put sleep 10 just to be safe...
Additional tip:
To help debug headless tests, consider adding screenshots on failures -
Add this to the end of your Capybara setup:
Capybara::Screenshot.register_filename_prefix_formatter(:rspec) do |example|
"screenshot_#{example.description.gsub(' ', '-').gsub(/^.*\/spec\//,'')}"
end
screenshot_path = "#{PROJECT_ROOT}/screenshot/"
Capybara.save_and_open_page_path = screenshot_path

Issue with Capybara request specs with JS - can't find the model

I'm having an issue with JS request specs - basic visiting of a model edit page:
it "can edit a doc", :js => true do
doc = FactoryGirl.create(:doc) # tried with Doc.create as well
puts Doc.find(doc.id) # 1 <- so it's definitely in the DB!
visit edit_doc_path(doc)
end
Result: "ActiveRecord::RecordNotFound - Couldn't find doc with id=1"
The odd thing is it works with standard request spec. I tried both webkit and selenium drivers. My spec_helper looks like this (should be pretty standard):
RSpec.configure do |config|
config.use_transactional_fixtures = false
Capybara.javascript_driver = :webkit
config.before(:suite) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
config.before(:each, :type => :request) do
Capybara.reset_sessions!
end
end
Rails 3.1.4, no versioning for capybara, rspec, etc. test libraries.
Any input much appreciated! Thanks!
Seems like you have same problem as this:
Capybara with :js => true causes test to fail
Try setting DatabaseCleaner strategy to :truncation and see if it works
config.before(:suite) do
DatabaseCleaner.strategy = :truncation
end

Database_Cleaner Destroying Records between HTTP Requests in the middle of a spec

I'm running integration specs using Rspec and Capybara and cleaning out records between specs using Database Cleaner. If it matters, I'm running my specs automatically using Guard and Spork.
Somehow, in the middle of a test run, records are being deleted from the database, causing them to fail. Have I setup Datbase Cleaner incorrectly? Or am I doing something else wrong? I saw this post already, but I don't think this is my problem.
Any help would be appreciated!
Here is spec_helper.rb
Spork.prefork do
# ...
RSpec.configure do |config|
config.mock_with :rspec
config.use_transactional_fixtures = true
config.include(MailerMacros)
config.treat_symbols_as_metadata_keys_with_true_values = true
config.filter_run :focus => true
config.run_all_when_everything_filtered = true
config.before(:suite) { DatabaseCleaner.strategy = :truncation }
config.before(:each) { DatabaseCleaner.start }
config.after(:each) { DatabaseCleaner.clean }
end
end
Spork.each_run do
FactoryGirl.reload
end
And here is my spec: (notice the 2 puts statements)
feature "Claim Firm" do
let(:firm) { Factory(:firm, :user_id => nil) }
scenario "The details page should show a 'Claim' link", :focus => true do
email = 'claimer#foo.com'
password = 'secretpass123'
u = Factory(:user, :email => email, :password => password, :name => "Bob Claimer")
puts "User Count: #{User.count}" # ==> 1
visit login_path
puts "User Count: #{User.count}" # ==> 0
# The rest of the spec fails because there are no user records...
end
end
Not sure what the root cause is, but the truncation strategy for SQLite is an optimization that seems to behave funny in certain situations, so stick with :transaction or :deletion if they're not too slow.

Simulating a non-local request in Rails/RSpec request testing

I'd like to block off access to the application to all non-local requesters (my application's actual functionality in practice is more sophisticated, but figuring out how to do this will solve my specific issue). How would I go about testing this with request tests in RSpec?
In spec/requests/gatekeeper_spec.rb
describe "A local request to the site root" do
before :each do
get root_path
end
it "should not allow access" do
response.status.should be(401)
end
end
describe "An external (terminology?) request to the site root" do
before :all do
# TODO: make request remote
end
before :each do
get root_path
end
it "should allow access" do
response.status.should be(200)
end
end
How should I implement the # TODO line? I've looked into mocks and think that rigging request.remote_ip may be appropriate, but I'm not certain exactly how such a mock is implemented.
If I understand correctly, test requests have a remote address of "0.0.0.0", so they would normally be considered remote and you'd want to stub the local requests, not the other way around.
I think this should work for controller specs -- not sure about request specs:
request.stub(:local?) { true }
Untested, but should work in Rails 2.3.x and 3.0:
before :each do
Rails::Initializer.run do |config|
config.action_controller.consider_all_requests_local = false
end
end
after :each do
Rails::Initializer.run do |config|
config.action_controller.consider_all_requests_local = true
end
end
In Rails 4 you can do it with:
RSpec.configure do |config|
config.before(:each, allow_rescue: true) do
Rails.application.config.action_dispatch.stub(:show_exceptions) { true }
Rails.application.config.stub(:consider_all_requests_local) { false }
end
end
And then in your test file:
describe "A test" do
it "renders custom error pages", :allow_rescue => true do
# ...
end
end
The name :allow_rescue is taken from a ActionController::Base.allow_rescue configuration which exists in Rails 3, and there the RSpec configuration would be:
RSpec.configure do |config|
config.before(:each, allow_rescue: true) do
ActionController::Base.stub(:allow_rescue) { true }
end
end

Resources