Session sometimes not persisting in Capybara Selenium test - session

I have a number of remote: true forms in my Rails 4 application to make up a wizard.
At each post, the action adds keys to the session object in my controller.
#post :some_action
def some_action
current_form_indetifier = params[:current_form_indetifier]
session[current_form_indetifier] = 'some_data'
end
This works fine in development and production.
It also SOMETIMES works perfectly in my Capybara Selenium test.
#step 1
fill_in 'My name is', with: 'Andy Smith'
fill_in 'I work at', with: 'Coca Cola'
find('.signup-form-next-button').click
#session key set in this post
wait_for_ajax
#step 2
fill_in 'Your Email', with: 'andy#smith.com'
fill_in 'Password', with: 'some-super-long-password'
find('.signup-form-next-button').click
#session key from last request is gone :-(
wait_for_ajax
It's super important to note that this does work sometimes.
However, for the majority (70%) of the time it does not working during testing.
By logging, I can see that the key/values are being added to the session in each request, but then in the next request the key is no longer in the session.
#first request
puts session.keys => "['form_1']"
#second request
puts session.keys => "[]"
Again, this works sometimes.
What I've tried so far to no avail:
enabling config.action_controller.allow_forgery_protection = true in environments/test.rb (it's false by default)
commenting out protect_from_forgery with: :exception in the application_controller.rb
It's important to remember that this does sometimes work.
Any ideas?
Update
For now I've worked around this by using the ActiveRecord SessionStore, so it seems the issue is around the cookies.

Related

How to run all examples except one in Ruby using Rspec

config.before(:example,) do
visit '/'
find('a[class=btn').click
fill_in 'username', with: $email
fill_in 'password', with: $password
find('input[class=btn]').click
end
I want to log in to the website in all tests except one, how do i do that?
I tried this:
config.before(:example,) |test| do
visit '/'
find('a[class=btn').click
fill_in 'username', with: $email
fill_in 'password', with: $password
find('input[class=btn]').click
unless test.metadata[:notrun]
end
end
I was expecting all test run except the one with the tag :notrun, but it runs anyway
Your unless block is just
unless test.metadata[:notrun]
end
so it's not doing anything. If you wanted the code in the before to not run then you could wrap it all in the unless
config.before(:example) |test| do
unless test.metadata[:notrun]
visit '/'
find('a[class=btn').click
fill_in 'username', with: $email
fill_in 'password', with: $password
find('input[class=btn]').click
end
end
but that will just stop the before hook from doing anything on the tagged test(s), it won't actually prevent the test from being run. Easiest way to prevent a specific example from being run is just to tag it with skip (instead of your notrun)
it 'blah blah', skip: true do
....
end
If I understand correctly, the OP wants to login before every test except one. Using skip: true will actually skip the test, not the before block.
There is a way to configure a before block to only execute on certain tests using metadata. It works like this:
RSpec.configure do |config|
config.before(:each, login: true) do
visit '/'
find('a[class=btn').click
fill_in 'username', with: $email
fill_in 'password', with: $password
find('input[class=btn]').click
end
end
RSpec.describe 'MyController' do
describe '#index' do
it 'does something while logged out'
context 'logged in', login: true do
it 'does something while logged in'
it 'does something else while logged in'
end
end
end
You can place the metadata on any describe, context, or example/it block. So, if you had a file full of tests that should be logged in, you'd just put the metadata on the outermost describe at the top of the file.

sessions arent working on sinatra

So i've been using sinatra and well no matter what i try i cannot seem to get sessions to work as intended.
Im enabling session/cookies with the following:
use Rack::Session::Cookie, :key => 'localhost_tester',
:path => '/',
:expire_after => 14400, # In seconds
:secret => 'secret_stuff'
And im trying to create a login page, the post data seems to be getting sent but no session is being created. This is what im using:
get '/account-login' do
#title = 'Adnetwork'
erb :accounts
end
post '/account-login' do
email = params[:email]
password = params[:password]
user = User.new()
if user.login(email, password)
#session isnt being made...
session['email'] = email
#redirect once session is complete
redirect to'/dashboard'
else
erb :accounts
end
end
The session wont actually be called "email" thats just an example i was using while testing. But it never actually creates the session. I have cookie editor plugin on chrome to see whats happening and the only thing thats being created is a session called "localhost" tester.
Am i being an idiot and doing it all wrong or is it something else that im missing?

Devise not storing sessions and losing credentials after redirect

It is a VERY strange bug and I am leading with it for 24 hours. It was working well and suddenly it started to fail.
The problem:
When I want to login with Facebook, the app redirec to Facebook permissions request, go back, save the update in the account model (access_token, and updated_at), but I am redirected to the home without permissions to access to signed_in sections.
My stack is:
Rails4, Devise 3.0.0.rc, Omniauth, Omniauth-facebook 1.4.0.
The app only accept login with Facebook.
Take a look:
Omniauth controller: account_signed_in? = true
class Accounts::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
# You need to implement the method below in your model (e.g. app/models/user.rb)
#account = Account.find_for_facebook_oauth(request.env["omniauth.auth"], current_account)
if #account.persisted?
sign_in_and_redirect #account, :event => :authentication #this will throw if #user is not activated
puts account_signed_in? # <-- true
set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_account_registration_url
end
end
ApplicationController: account_signed_in? = true
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
private
def stored_location_for(resource_or_scope)
nil
end
def after_sign_in_path_for(resource_or_scope)
puts account_signed_in? # <-- true
current_account.pages.empty? ? new_page_path : pages_path
end
StaticController (home) account_signed_in? = false
class StaticController < ApplicationController
def home
puts account_signed_in? # <- false
render layout: 'home'
end
I don't know if can there be something that disturb the normal flow of sessions between Devise and Rails.
Found that!
The sessions weren't saved because of the domain parameter in session_store.rb:
BrainedPage::Application.config.session_store :cookie_store,
key: '_my_session', :domain => Rails.configuration.domain
Seems I had changed the domain configuration in development environment (added port, because I was using this var for other propose too), and I didn't realize the impact it could make.

Capybara and Rails have_content failing in spec to test to see if a messages partial appears

I have a request spec which passes up until the point where I need to check to see if content is present on the page, which I am using page.should have_content to do. The content is actually a message which appears on successful form submission, which is rendered from a messages partial. The test fails even though If I test through the browser, functionality works as expected and the content appears as it should. I'm also using FactoryGirl to generate the users to use for the form submission.
Here's the error I get after running the spec with the --format d option:
UserSignup
shows a thank you message on successful form submission (FAILED - 1)
Failures:
1) UserSignup shows a thank you message on successful form submission
Failure/Error: page.should have_content("Thank you. You will be notified of our launch at #{user.email}.")
expected #has_content?("Thank you. You will be notified of our launch at quinn.purdy#casperzboncak.org.") to return true, got false
# ./spec/requests/user_signup_spec.rb:21:in `block (2 levels) in <top (required)>'
user_signup_spec.rb:
require 'spec_helper'
describe "UserSignup" do
it "shows a thank you message on successful form submission" do
user = FactoryGirl.create(:user)
visit sign_up_path
fill_in "user_fullname", with: user.fullname
fill_in "user_email", with: user.email
click_button "Sign up"
current_path.should eq(sign_up_path)
page.should have_content("Thank you. You will be notified of our launch at #{user.email}.")
end
end
users_controller.rb:
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(secure_params)
if #user.valid?
#user.subscribe
flash[:notice] = "Thank you. You will be notified of our launch at #{#user.email}."
redirect_to sign_up_path
else
render :new
end
end
private
def secure_params
params.require(:user).permit(:fullname, :email)
end
end
I'm wondering if it could be because I render the messages partial from the application layout, but when it gets outputted in the users view, the message appears inside the body of the source, but outside the main class.
So I seem to have got the tests passing by adding the line , :js => true do beside 'it' and using the selenium web driver. There's got to be a way to do it without selenium I'm thinking, because you have to sit and wait while it actually runs it in a browser which is the downside.
Maybe I'm going about it the wrong way, and I should actually be checking for the partial in a view spec (currently it was just part of the feature test).

how to run capybara commands once, then run some tests

I have the given testing code:
describe 'A new user', js: true do
before do
#new_user = Fabricate.build(:user)
end
it 'should sign up' do
#login code
visit '/'
click_link 'Login'
fill_in 'user[email]', :with => #new_user.email
fill_in 'user[password]', :with => #new_user.password
click_button 'Login now'
#login code end
page.should have_content("Hello #{#new_user.first_name}!")
current_path.should == dashboard_path
end
it 'should receive a confirmation mail' do
#same login code again
visit '/'
click_link 'Login'
fill_in 'user[email]', :with => #new_user.email
fill_in 'user[password]', :with => #new_user.password
click_button 'Login now'
mail = ActionMailer::Base.deliveries.last
assert_equal #new_user.email, mail['to'].to_s
end
end
Now I want to add more tests.
To avoid code doubling, how can I run the capybara login code once before all tests?
One solution would be to put the login code in the before method. Another would be to create a method do_login, put the code in it and run every test like this:
it 'should do something after login' do
do_login
#test code here
end
But for both solutions, the code is run for every test and thats not what I want. Putting the login code in a before(:all) doesn't work, too.
How can I run some capybara code once and then do all the tests after this?
You can't run capybara code once and then run all the tests. You always start from scratch. Your proposed solution with before(:each) or helper method is the only posibility. (It's possible to run some ruby before(:all) e.g. create objects outside the transaction check here but not Capybara)
To speed up your specs you can test login feature in separate spec and then somehow stub the authentication but it depends on your implementation.
If you are using Devise check devise wiki: https://github.com/plataformatec/devise/wiki/How-To:-Controllers-tests-with-Rails-3-(and-rspec)

Resources